Buku yang penuh omong kosong: Identifikasi limerick

15

Seperti kita ketahui, limerick adalah puisi pendek, lima baris, dan kadang-kadang cabul dengan skema berima AABBA dan meteran permadani (apa pun itu):

Menulis sebuah
baris Limerick yang absurd satu dan baris lima sajak dalam kata
Dan seperti yang Anda anggap
Mereka berima dengan yang kedua
Baris keempat harus berima dengan yang ketiga

Anda ditugasi untuk menulis program terpendek yang, ketika diumpankan teks input, mencetak apakah ia berpikir bahwa input tersebut adalah limerick yang valid. Input dapat berada pada baris perintah atau melalui input standar, pada pilihan Anda, dan output bisa berupa "Y" / "N" sederhana atau skor kepercayaan, lagi pada pilihan Anda.

Inilah contoh lain dari limerick yang benar:

Ada seorang nona muda yang matanya
unik untuk warna dan ukuran.
Ketika dia membukanya lebar-lebar. Semua
orang berbalik
dan mulai terkejut

Tetapi puisi di bawah ini jelas bukan limerick, karena tidak berima:

Ada seorang lelaki tua St. Bees
yang disengat lengannya oleh seekor tawon.
Ketika ditanya, "Apakah itu sakit?"
Dia menjawab, "Tidak, tidak,
aku senang bahwa itu bukan lebah."

Ini juga tidak, karena meteran semuanya salah:

Saya mendengar tentang seorang pria dari Berlin
yang membenci ruangan tempat dia berada.
Ketika saya bertanya mengapa
Dia akan berkata sambil mendesah,
"Ya, begini, tadi malam ada beberapa penjahat di sekitar yang sedang merayakan Beruang-beruang yang memenangkan beruang terkutuk. Piala Dunia, dan mereka sangat keras sehingga saya tidak bisa tidur karena keributan. "

Petunjuk

Berikut adalah beberapa petunjuk yang dapat Anda gunakan untuk memutuskan apakah input Anda adalah limerick:

  • Limerick selalu panjang lima baris.
  • Baris 1, 2 dan 5 harus berima.
  • Baris 3 dan 4 harus berima.
  • Baris 1, 2 dan 5 memiliki sekitar 3x3 = 9 suku kata, sedangkan suku ketiga dan keempat memiliki suku kata 2x3 = 6

Perhatikan bahwa tidak satu pun dari ini kecuali yang pertama sulit dan cepat: peringkat kebenaran 100% tidak mungkin.

Aturan

  • Entri Anda setidaknya harus secara benar mengkategorikan contoh 1 hingga 3 secara deterministik.

  • Anda yang diperbolehkan untuk menggunakan bahasa pemrograman apapun yang Anda inginkan, kecuali bahasa pemrograman saja dirancang khusus untuk kontes ini (lihat di sini ).

  • Anda tidak diperbolehkan menggunakan perpustakaan apa pun kecuali penawaran standar bahasa pemrograman Anda.

  • Anda yang diperbolehkan untuk menganggap bahwa file ini , CMU Sphinx pengucapan kamus, dalam sebuah file yang bernama 'c' di direktori saat ini.

  • Anda tidak diperbolehkan melakukan hard-kode untuk input tes: program Anda harus menjadi kategorizer limerick umum.

  • Anda yang diperbolehkan untuk mengasumsikan bahwa input ASCII, tanpa format khusus (seperti pada contoh), tetapi program Anda tidak harus bingung dengan interpunction.

Bonus

Bonus berikut tersedia:

  • Program Anda menampilkan hasilnya sebagai limerick? Kurangi bonus panjang 150 karakter !
  • Program Anda juga mengidentifikasi soneta dengan benar? Kurangi 150 karakter bonus ekstra panjang!
  • Program Anda menampilkan hasilnya sebagai soneta ketika digunakan pada soneta? Kurangi 100 karakter bonus ekstra panjang tambahan!

Akhirnya...

Ingatlah untuk menyebutkan bonus mana yang menurut Anda pantas, jika ada, dan kurangi bonus dari jumlah karakter Anda untuk sampai pada skor Anda. Ini adalah kontes kode golf : entri terpendek (yaitu entri dengan skor terendah) menang.

Jika Anda membutuhkan lebih banyak data tes (positif), lihat OEDILF atau Book of Nonsense . Data tes negatif harus mudah dibuat.

Semoga berhasil!

Mengembara Nauta
sumber
Ini harus code-challengekarena bonus. Silakan baca deskripsi tag
user80551
2
@ user80551 Konsensus tentang meta tampaknya sebaliknya.
Gagang Pintu
Saya sudah mengklarifikasi sifat bonusnya, saya harap itu bisa menghilangkan kebingungan.
Mengembara Nauta
2
Goooooooo Beruang!
alvonellos
Saya tidak mengerti bonusnya. Bagaimana saya bisa menampilkan "Y" dalam bentuk limerick?
squeamish ossifrage

Jawaban:

8

Python: 400 - 150 - 150 = 100

Script terpendek yang bisa saya buat adalah ...

import re,sys;f,e,c=re.findall,lambda l,w:f('^'+w.upper()+'  (.+)',l),lambda*v:all([a[i]==a[v[0]]for i in v]);a=[sum([[e(l,w)[0].split()for l in open('c')if e(l,w)][0]for w in f(r'\w+',v)],[])[-2:]for v in sys.stdin];n=len(a);print n==14and c(0,3,4,7)*c(1,2,5,6)*c(8,11)*c(9,12)*c(10,13)*"Sonnet"or"For a critic\nOf limerick\nWell-equipped\nIs this script.\n%s limerick!"%(n==5and c(0,1,4)and c(2,3))

... tapi jangan coba-coba. Ini mem-parsing kamus yang disediakan untuk setiap kata yang ditemuinya, sehingga menjadi sangat lambat. Juga, kesalahan dihasilkan setiap kali sebuah kata tidak ada dalam kamus.

Kode masih memenuhi persyaratan: mengenali apakah teks dilewatkan melalui stdin adalah limerick, soneta, atau bukan keduanya.

Dengan hanya 20 karakter, inilah versi yang dioptimalkan:

import re,sys;f,e,c=re.findall,lambda l:f(r'^(\w+)  (.+)',l),lambda*v:all([a[i]==a[v[0]]for i in v]);d={e(l)[0][0]:e(l)[0][1].split()for l in open('c')if e(l)};a=[sum([d.get(w.upper(),[])for w in f(r'\w+',v)],[])[-2:]for v in sys.stdin];n=len(a);print n==14and c(0,3,4,7)*c(1,2,5,6)*c(8,11)*c(9,12)*c(10,13)*"Sonnet"or"For a critic\nOf limerick\nWell-equipped\nIs this script.\n%s limerick!"%(n==5and c(0,1,4)and c(2,3))

fitur

  • mampu mengenali soneta (-150)
  • jawaban untuk limericks with a limerick (-150)
  • relatif cepat: hanya satu file parsing per eksekusi

Pemakaian

cat poem.txt | python poem-check.py

3 output yang berbeda dimungkinkan:

  • limmerick yang mengatakan inputnya adalah satu jika itu yang terjadi
  • seorang limmerick yang mengatakan input bukan satu jika itu yang terjadi
  • "Soneta" jika inputnya dikenali

Kode diperluas dengan penjelasan

import re, sys

# just a shortened version of the 're.findall' function...
f = re.findall
# function used to parse a line of the dictionary
e = lambda l:f(r'^(\w+)  (.+)', l)

# create a cache of the dictionary, where each word is associated with the list of phonemes it contains
d = {e(l)[0][0]:e(l)[0][1].split(' ') for l in open('c') if e(l)}

# for each verse (line) 'v' found in the input 'sys.stdin', create a list of the phoneme it contains;
# the result array 'a' contains a list, each item of it corresponding to the last two phonemes of a verse
a = [sum([d.get(w.upper(), []) for w in f(r'\w+',v)],[])[-2:] for v in sys.stdin]

# let's store the length of 'a' in 'n'; it is actually the number of verses in the input
n = len(a)
# function used to compare the rhymes of the lines which indexes are passed as arguments
c = lambda*v:all([a[i] == a[v[0]] for i in v])

# test if the input is a sonnet, aka: it has 14 verses, verses 0, 3, 4 and 7 rhyme together, verses 1, 2, 5 and 6 rhyme together, verses 8 and 11 rhyme together, verses 9 and 12 rhyme together, verses 10 and 13 rhyme together
if n==14 and c(0,3,4,7) and c(1,2,5,6) and c(8,11) and c(9,12) and c(10,13):
    print("Sonnet")
else:
    # test if the input is a limerick, aka: it has 5 verses, verses 0, 1 and 4 rhyme together, verses 2 and 3 rhyme together
    is_limerick = n==5 and c(0,1,4) and c(2,3)
    print("For critics\nOf limericks,\nWell-equipped\nIs this script.\n%s limerick!", is_limmerick)
Mathieu Rodic
sumber
Terlihat keren! Saya belum mengujinya, tetapi apakah Anda yakin ini membutuhkan input "baik pada baris perintah atau melalui input standar" (lihat pertanyaan)? Jika tidak, Anda harus menambahkan itu (mungkin di sys.stdin.read()suatu open(sys.argv[1]).read()tempat) dan menceritakannya kembali.
Mengembara Nauta
Baik! Diperbaiki :)
Mathieu Rodic
Bagaimana cara algoritma memeriksa rima?
DavidC
Dengan bantuan file yang disediakan oleh Wander Nauta dalam pertanyaan! Ini sangat membantu.
Mathieu Rodic
1
Rapi! Sayang sekali aku tidak bisa membuatmu marah dua kali.
Mengembara Nauta
2

ECMAScript 6 (138 poin; coba di Firefox):

288- 150Poin bonus untuk termasuk limerick (dicubit dari @MathieuRodic).

a=i.split(d=/\r?\n/).map(x=>x.split(' '));b=/^\W?(\w+) .*? (\w+\d( [A-Z]+)*)$/;c.split('\r\n').map(x=>b.test(x)&&eval(x.replace(b,'d["$1"]="$2"')));e=f=>d[a[f][a[f].length-1]];alert('For critics\nOf limericks,\nWell-equipped\nIs this script.\n'+(a[4]&&e(0)==e(1)&e(0)==e(4))+' limerick!')

Catatan:

Diharapkan variabel cmengandung konten file kamus, karena Anda tidak dapat membaca file dalam skrip ECMAS.

ECMAScript tidak memiliki input standar, tetapi promptumumnya dianggap "input standar"; Namun, karena promptmengubah jeda baris ke spasi di sebagian besar (jika tidak semua) browser, saya menerima input dari variabel i.

Kode tidak dikunci:

// If you paste a string with multiple lines into a `prompt`, the browser replaces each line break with a space, for some reason.
//input = prompt();

// Split into lines, with each line split into words
lines = input.split('\n').map(x => x.split(' '));

dictionaryEntryRegEx = /^\W?(\w+) .*? (\w+\d( [A-Z]+)*)$/;
dictionary = {};
// Split it into
c.split(/\r?\n/).map(x => dictionaryEntryRegEx && eval(x.replace(dictionaryEntryRegEx, 'dictionary["$1"] = "$2"')));

// Get the last word in the line
getLastWordOfLine = (lineNumber) => dictionary[line[lineNumber][line[lineNumber].length - 1]]

alert('For critics\nOf limericks,\nWell-equipped\nIs this script.\n' + (lines[4] && getLastWordOfLine(0) === getLastWordOfLine(1) && getLastWordOfLine(0) === getLastWordOfLine(4)) + ' limerick!');
Sikat gigi
sumber
Rapi! Ini tidak mengambil 'input pada baris perintah atau melalui input standar', yang dibutuhkan oleh pertanyaan. Mungkin Anda bisa menulis ulang untuk menggunakan Node.js atau sesuatu.
Mengembara Nauta
@WanderNauta Terima kasih. Silakan lihat hasil edit terakhir, saat saya menjelaskan mengapa saya tidak menggunakan input standar.
Sikat gigi