Libri pieni di sciocchezze: identifica i limerick


15

Come tutti sappiamo, i limerick sono brevi poesie a cinque righe, occasionalmente oscene, con uno schema in rima AABBA e un metro arazzoico (qualunque cosa sia):

Scrivere l'assurdo Limerick
Riga 1 e riga 5 rima in parola
E proprio come hai calcolato
Hanno rima con il secondo
La quarta riga deve rima con il terzo

Hai il compito di scrivere il programma più breve che, quando viene inviato un testo di input, stampa se ritiene che l'input sia un limerick valido. L'input può essere sulla riga di comando o tramite input standard, a tua scelta, e l'output potrebbe essere un semplice "Y" / "N" o un punteggio di confidenza, sempre a tua scelta.

Ecco un altro esempio di un limerick corretto:

C'era una giovane donna i cui occhi
erano unici per quanto riguarda il colore e le dimensioni
Quando li ha spalancati,
tutti si sono allontanati
e sono partiti con sorpresa

Ma la poesia che segue è chiaramente non è un limerick, dal momento che non rima:

C'era un vecchio di St. Bees
che era stato punto nel braccio da una vespa.
Alla domanda "Fa male?"
Lui rispose: "No, non è così,
sono così felice che non fosse un calabrone."

Né è questo, poiché lo strumento è tutto sbagliato:

Ho sentito parlare di un uomo di Berlino
che odiava la stanza in cui si trovava
Quando gli chiesi perché
avrebbe dovuto dire con un sospiro:
"Bene, vedi, ieri sera c'erano un paio di teppisti che stavano celebrando gli Orsi vincendo i maledetti World Cup, ed erano davvero rumorosi, quindi non potevo dormire a causa del frastuono ".

indizi

Ecco alcuni degli indizi che potresti utilizzare per decidere se il tuo input è un limerick:

  • I limerick sono sempre lunghi cinque righe.
  • Le righe 1, 2 e 5 dovrebbero far rima.
  • Le righe 3 e 4 dovrebbero far rima.
  • Le righe 1, 2 e 5 hanno circa 3x3 = 9 sillabe, mentre la terza e la quarta hanno 2x3 = 6 sillabe

Nota che nessuno di questi, tranne il primo, è duro e veloce: una valutazione della correttezza del 100% è impossibile.

Regole

  • La tua voce dovrebbe almeno classificare correttamente gli esempi da 1 a 3 in modo deterministico.

  • Si è permesso usare qualsiasi linguaggio di programmazione che si desidera, ad eccezione dei linguaggi di programmazione naturalmente studiati appositamente per questo concorso (vedi qui ).

  • Non è consentito utilizzare alcuna libreria tranne le offerte standard del proprio linguaggio di programmazione.

  • Si è permesso di pensare che questo file , il dizionario pronuncia CMU Sphinx, è in un file chiamato 'c' nella directory corrente.

  • Siete non autorizzati a hard-code per gli ingressi di prova: il programma dovrebbe essere un classificatore generale Limerick.

  • Si è autorizzati a supporre che l'ingresso è ASCII, senza alcuna formattazione speciale (come negli esempi), ma il programma non deve essere confusa con nell'interpunzione.

bonus

Sono disponibili i seguenti bonus:

  • Il tuo programma emette il suo risultato come un limerick? Sottrai un bonus di 150 caratteri !
  • Il tuo programma identifica anche correttamente i sonetti? Sottrai un bonus extra di 150 caratteri !
  • Il tuo programma genera il suo risultato come sonetto quando utilizzato su un sonetto? Sottrai un bonus di lunghezza extra di 100 caratteri !

Infine...

Ricorda di indicare quali bonus ritieni di meritare, se presenti, e di sottrarre il bonus dal tuo numero di personaggi per arrivare al tuo punteggio. Questa è una gara di golf in codice : vince l'entrata più breve (ovvero l'entrata con il punteggio più basso).

Se hai bisogno di ulteriori dati di test (positivi), controlla l' OEDILF o il Libro delle sciocchezze . I dati dei test negativi dovrebbero essere facili da costruire.

In bocca al lupo!


Questo dovrebbe essere code-challengedovuto ai bonus. Si prega di leggere le descrizioni dei tag
user80551

2
@ user80551 Il consenso sulla meta sembra essere diversamente.
Maniglia della porta

Ho chiarito la natura dei bonus, spero che chiarisca la confusione.
Passeggia per Nauta il

2
Goooooooo Bears!
alvonellos,

Non capisco i bonus. Come dovrei produrre "Y" sotto forma di un limerick?
ossifrage schifoso

Risposte:


8

Python: 400-150-150 = 100

La sceneggiatura più breve che ho potuto inventare è quella ...

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))

... ma non provarlo nemmeno. Analizza il dizionario fornito per ogni parola che incontra, quindi è molto lento. Inoltre, viene generato un errore ogni volta che una parola non è presente nel dizionario.

Il codice soddisfa comunque i requisiti: riconoscere se il testo passato tramite stdin è un limerick, un sonetto o nessuno di questi.

Con solo altri 20 caratteri, ecco la versione ottimizzata:

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))

Caratteristiche

  • in grado di riconoscere sonetti (-150)
  • risponde ai limerick con un limerick (-150)
  • relativamente veloce: solo un file di analisi per esecuzione

uso

cat poem.txt | python poem-check.py

Sono possibili 3 diverse uscite:

  • un limmerick che dice che l'ingresso è uno se è il caso
  • un limmerick che dice che l'ingresso non è uno se è il caso
  • "Sonnet" se l'ingresso è riconosciuto come tale

Codice espanso con spiegazioni

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)

Sembra fico! Non l'ho ancora testato, ma sei sicuro che questo richieda input "dalla riga di comando o tramite input standard" (vedi domanda)? In caso contrario, dovresti aggiungere quello (probabilmente un sys.stdin.read()o un open(sys.argv[1]).read()posto da qualche parte) e raccontare.
Passeggia per Nauta il

Va bene! Corretto :)
Mathieu Rodic,

In che modo l'algoritmo verifica la presenza di rime?
DavidC

Con l'aiuto del file fornito da Wander Nauta nella domanda! Mi ha davvero aiutato.
Mathieu Rodic,

1
! Neat Un peccato che non posso votarti due volte.
Passeggia per Nauta il

2

ECMAScript 6 (138 punti; prova in Firefox):

288- 150bonus punti per l'inclusione del limerick (pizzicato da @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!')

Appunti:

Si aspetta che la variabile ccontenga il contenuto del file del dizionario, in quanto non è possibile leggere i file in ECMAScript semplice.

ECMAScript non ha input standard, ma promptè generalmente considerato "input standard"; tuttavia, poiché promptconverte le interruzioni di riga in spazi nella maggior parte dei browser (se non in tutti), accetto input dalla variabile i.

Codice non golfato:

// 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!');

! Neat Tuttavia, ciò non richiede "input dalla riga di comando o tramite input standard", richiesto dalla domanda. Forse potresti riscriverlo per usare Node.js o qualcosa del genere.
Wander Nauta

@WanderNauta Grazie. Si prega di consultare l'ultima modifica, poiché spiego perché non sto usando l'input standard.
Spazzolino
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.