Książki pełne bzdur: Zidentyfikuj limeryki

15

Jak wszyscy wiemy, limeryki to krótkie, pięcioliniowe, czasem lubieżne wiersze ze schematem rymowania AABBA i miernikiem anapestic (cokolwiek to jest):

Pisanie absurdalnego
wiersza pierwszej i piątej Limericka rymuje się słowem
I tak, jak się spodziewałeś
Rymują się z drugim
Czwarta linia musi rymować się z trzecim

Twoim zadaniem jest napisanie najkrótszego programu, który po wprowadzeniu tekstu wejściowego drukuje, czy uważa, że ​​dane wejściowe są poprawnym limerickiem. Dane wejściowe mogą być albo w wierszu poleceń, albo przez standardowe dane wejściowe, zależnie od wyboru, a dane wyjściowe mogą być albo prostym „Y” / „N”, albo wynikiem ufności, ponownie według twojej opcji.

Oto kolejny przykład poprawnego limeryka:

Była Młoda Dama, której oczy
były wyjątkowe pod względem koloru i wielkości.
Kiedy je szeroko otworzyła.
Wszyscy odwrócili się na bok
i zaczęli zaskoczeni

Ale poniższy wiersz wyraźnie nie jest limerykiem, ponieważ nie rymuje się:

Był tam starzec Pszczół,
który został ugodzony w ramię przez osę.
Na pytanie „Czy to boli?”
Odpowiedział: „Nie, to nie,
tak, cieszę się, że to nie był szerszeń”.

To też nie jest, ponieważ licznik jest całkowicie błędny:

Słyszałem o mężczyźnie z Berlina,
który nienawidził pokoju, w którym był.
Zapytałem, dlaczego
powiedziałby z westchnieniem:
„Widzicie, wczoraj wieczorem było kilku chuliganów, którzy świętowali Niedźwiedzie wygrywając cholerę Mistrzostwa Świata i były bardzo głośne, więc nie mogłem spać z powodu zgiełku. ”

Wskazówki

Oto kilka wskazówek, które możesz wykorzystać, aby zdecydować, czy Twój wkład jest limerykiem:

  • Limeryki mają zawsze pięć linii.
  • Linie 1, 2 i 5 powinny rymować się.
  • Linie 3 i 4 powinny rymować się.
  • Linie 1, 2 i 5 mają około 3 x 3 = 9 sylab, podczas gdy trzecia i czwarta ma 2x3 = 6 sylab

Zauważ, że żaden z nich oprócz pierwszego nie jest trudny i szybki: ocena 100% poprawności jest niemożliwa.

Zasady

  • Wpis powinien przynajmniej co najmniej poprawnie kategoryzować przykłady od 1 do 3 w sposób deterministyczny.

  • Wy wolno używać dowolnego języka programowania, który chcesz, z wyjątkiem języków programowania kurs specjalnie zaprojektowanych do tego konkursu (patrz tutaj ).

  • Państwo nie może używać jakichkolwiek biblioteki oprócz swojego języka programowania w standardowych ofert.

  • Wy wolno zakładać, że ten plik , słownik pronounciation CMU Sphinx, znajduje się w pliku o nazwie „c” w bieżącym katalogu.

  • Teraz nie wolno twardym kodu dla wejść testowych: Twój program powinien być ogólny Limerick Klasyfikator.

  • Wy wolno zakładać, że wejście jest ASCII, bez specjalnego formatowania (jak w przykładach), ale program nie powinien być mylony przez interpunction.

Bonusy

Dostępne są następujące bonusy:

  • Twój program wyświetla wynik jako limeryk? Odejmij 150 znaków bonus długości !
  • Twój program również poprawnie identyfikuje sonety? Odejmij 150 znaków bonus dodatkowych !
  • Twój program wyświetla wynik jako sonet, gdy jest używany w sonecie? Odejmij 100 znaków dodatkowego bonusu za dodatkową długość!

Wreszcie...

Pamiętaj, aby wspomnieć o bonusach, które Twoim zdaniem zasługujesz, jeśli w ogóle, i odejmij bonus od liczby postaci, aby osiągnąć swój wynik. Jest to konkurs golfa kodowego : wygrywa najkrótszy wpis (tj. Zgłoszenie o najniższym wyniku).

Jeśli potrzebujesz więcej (pozytywnych) danych testowych, sprawdź OEDILF lub Księgę bzdur . Negatywne dane testowe powinny być łatwe do skonstruowania.

Powodzenia!

Wander Nauta
źródło
Powinno to wynikać code-challengez bonusów. Proszę przeczytać opisy znaczników
user80551
2
@ user80551 Konsensus w sprawie meta wydaje się być inny.
Klamka
Wyjaśniłem naturę bonusów, mam nadzieję, że to wyjaśni zamieszanie.
Wander Nauta
2
Goooooooo Bears!
alvonellos
Nie rozumiem bonusów. Jak mam wypisać „Y” w postaci limeryka?
r3mainer

Odpowiedzi:

8

Python: 400-150-150 = 100

Najkrótszy scenariusz, jaki mogłem wymyślić, to ten ...

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

... ale nawet tego nie próbuj. Analizuje dostarczony słownik dla każdego napotkanego słowa, dlatego jest bardzo wolny. Ponadto generowany jest błąd, gdy słowa nie ma w słowniku.

Kod wciąż jednak spełnia wymagania: rozpoznanie, czy tekst przeszedł przez stdin jest limerykiem, sonetem, czy żadnym z nich.

Z jeszcze 20 znakami, oto zoptymalizowana wersja:

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

cechy

  • potrafi rozpoznać sonety (-150)
  • odpowiedzi na limeryki za pomocą limeryka (-150)
  • stosunkowo szybko: parsowanie tylko jednego pliku na wykonanie

Stosowanie

cat poem.txt | python poem-check.py

Możliwe są 3 różne wyjścia:

  • limmerick mówiący, że wejście jest jedno, jeśli tak jest
  • limmerick mówi, że wejście nie jest jednym, jeśli tak jest
  • „Sonnet”, jeśli wejście jest rozpoznawane jako takie

Rozszerzony kod z objaśnieniami

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
źródło
Wygląda fajnie! Nie przetestowałem go jeszcze, ale czy jesteś pewien, że wymaga to wprowadzenia „albo z wiersza poleceń, albo ze standardowego wejścia” (patrz pytanie)? Jeśli nie, powinieneś to dodać (prawdopodobnie a sys.stdin.read()lub open(sys.argv[1]).read()gdzieś) i przeliczyć.
Wander Nauta
W porządku! Poprawiono :)
Mathieu Rodic
W jaki sposób algorytm sprawdza rymy?
DavidC
Z pomocą pliku dostarczonego przez Wandera Nauta w pytaniu! To naprawdę pomogło.
Mathieu Rodic
1
Schludny! Szkoda, że ​​nie mogę cię dwukrotnie głosować.
Wander Nauta
2

ECMAScript 6 (138 punktów; spróbuj w Firefox):

288- 150premia punktowa za włączenie limeryka (ściągnięta z @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!')

Uwagi:

Oczekuje, że zmienna cbędzie zawierać zawartość pliku słownika, ponieważ nie można odczytać plików w zwykłym skrypcie ECMAScript.

ECMAScript nie ma standardowego wejścia, ale promptjest ogólnie uważany za „standardowe wejście”; jednak ponieważ promptkonwertuje podział wierszy na spacje w większości (jeśli nie wszystkich) przeglądarek, akceptuję dane wejściowe ze zmiennej i.

Nieskluczony kod:

// 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!');
Szczoteczka do zębów
źródło
Schludny! Nie wymaga to jednak „danych wejściowych w wierszu poleceń ani standardowych danych”, co jest wymagane przez pytanie. Może mógłbyś przepisać go na Node.js lub coś takiego.
Wander Nauta
@WanderNauta Dziękujemy. Zobacz najnowszą edycję, ponieważ wyjaśniam, dlaczego nie używam standardowego wejścia.
Szczoteczka do zębów