Книги, полные глупости: Определите лимерики

15

Как мы все знаем, лимерики - это короткие, пятистрочные, иногда непристойные стихи со схемой рифмования AABBA и метром анапестика (что бы это ни было):

Написание абсурдного лимерика
Строка первая и строка пять рифмуются в слове
И так же, как вы рассчитывали
Они рифмуются со вторым
Четвертая строка должна рифмоваться с третьим

Вам поручено написать самый короткий программу, которая при подаче вводимого текста печатает, считает ли он, что ввод является допустимым лимериком. Ввод может быть либо в командной строке, либо через стандартный ввод, по вашему выбору, а вывод может быть простым «Y» / «N» или доверительным счетом, опять же по вашему выбору.

Вот еще один пример правильного лимерика:

Была молодая леди, чьи глаза
были уникальны по цвету и размеру,
когда она широко их открыла.
Люди все отвернулись
и с удивлением ушли.

Но стихотворение ниже явно не лимерик, так как оно не рифмуется:

Был пожилой человек св. Пчелы,
которого ужалила в руке оса.
Когда его спросили: "Это больно?"
Он ответил: «Нет, это не так,
я так рад, что это не шершень».

И это не так, так как метр все не так:

Я слышал о человеке из Берлина,
который ненавидел комнату, в которой он находился.
Когда я спросил, почему
Он со вздохом сказал:
«Ну, вы видите, вчера вечером была пара хулиганов, которые праздновали, как Медведи побеждают проклятых. Чемпионат мира, и они были очень громкими, поэтому я не мог уснуть из-за шума ».

Улики

Вот некоторые из подсказок, которые вы могли бы использовать, чтобы решить, является ли ваш вклад лимерикой:

  • Лимерики всегда в пять строк.
  • Строки 1, 2 и 5 должны рифмоваться.
  • Строки 3 и 4 должны рифмоваться.
  • Строки 1, 2 и 5 имеют около 3x3 = 9 слогов, в то время как третий и четвертый имеют 2x3 = 6 слогов

Обратите внимание, что ни один из них, за исключением первого, не является жестким и быстрым: 100% -ая оценка правильности невозможна.

правила

  • Ваша запись должна по крайней мере правильно классифицировать примеры с 1 по 3 детерминистическим образом.

  • Вы имеете право использовать любой язык программирования , который вы хотите, за исключением, конечно , языков программирования , специально предназначенных для этого конкурса (см здесь ).

  • Вам не разрешается использовать любую библиотеку, кроме стандартных предложений вашего языка программирования.

  • Вы можете предположить, что этот файл , словарь произношения CMU Sphinx, находится в файле с именем «c» в текущем каталоге.

  • Вы не можете жестко программировать входные данные теста: ваша программа должна быть общим классификатором лимериков.

  • Вы которые позволили предположить , что вход ASCII, без какого - либо специального форматирования (например , в примерах), но программа не следует путать interpunction.

Бонусы

Доступны следующие бонусы:

  • Ваша программа выводит свой результат как лимерик? Вычтите бонус в 150 символов !
  • Ваша программа также правильно определяет сонеты? Вычтите дополнительный бонус в 150 символов !
  • Ваша программа выводит свой результат как сонет при использовании в сонете? Вычтите дополнительный бонус в 100 символов !

В заключение...

Не забудьте упомянуть, какие бонусы, по вашему мнению, вы заслуживаете, если таковые имеются, и вычесть бонус из вашего числа персонажей, чтобы получить ваш счет. Это кодовое соревнование по гольфу : выигрывает самая короткая заявка (то есть заявка с наименьшим количеством очков).

Если вам нужны дополнительные (положительные) данные испытаний, ознакомьтесь с OEDILF или Книгой чепухи . Данные отрицательного теста должны быть легко построены.

Удачи!

Бродить наута
источник
Это должно быть code-challengeиз-за бонусов. Пожалуйста, прочитайте описание тега
user80551
2
@ user80551 Консенсус по мета выглядит иначе.
Ручка двери
Я прояснил природу бонусов, надеюсь, это прояснит путаницу.
Бродить Наута
2
Оооооооо Медведи!
alvonellos
Я не понимаю бонусы. Как я должен вывести «Y» в виде лимерика?
брезгливый оссифраж

Ответы:

8

Питон: 400 - 150 - 150 = 100

Самый короткий сценарий, который я мог придумать, это тот ...

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

... но даже не пытайся. Он анализирует предоставленный словарь для каждого слова, которое встречается, поэтому он очень медленный. Кроме того, ошибка генерируется всякий раз, когда слово отсутствует в словаре.

Код по-прежнему соответствует требованиям: распознает, был ли текст передан через stdin лимерикой, сонетом или ни тем, ни другим.

Оптимизированная версия содержит всего 20 символов.

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

Характеристики

  • способен распознавать сонеты (-150)
  • ответы на лимерики с лимерикой (-150)
  • относительно быстро: только один файл разбирается за исполнение

использование

cat poem.txt | python poem-check.py

Возможны 3 разных выхода:

  • Лиммерик говорит, что вход один, если это так
  • Лиммерик говорит, что вход не один, если это так
  • «Сонет», если вход распознается как таковой

Расширенный код с пояснениями

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)
Матье Родик
источник
Выглядит круто! Я еще не проверял, но вы уверены, что он принимает ввод «либо из командной строки, либо через стандартный ввод» (см. Вопрос)? Если нет, вы должны добавить это (вероятно, a sys.stdin.read()или open(sys.argv[1]).read()где-то) и пересчитать.
Бродить Наута
Ладно! Исправил это :)
Матье Родич
Как алгоритм проверяет рифмы?
DavidC
С помощью файла, предоставленного Wander Nauta в вопросе! Это действительно помогло.
Матье Родик,
1
Ухоженная! Жаль, что я не могу тебя дважды проголосовать.
Бродить Наута
2

ECMAScript 6 (138 баллов; попробуйте в Firefox):

288- 150бонусные баллы за включение лимерика (взято из @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!')

Примечания:

Ожидает переменную c будет содержать содержимое файла словаря, поскольку вы не можете читать файлы в обычном ECMAScript.

ECMAScript не имеет стандартного ввода, но promptобычно считается «стандартным вводом»; однако, поскольку promptв большинстве браузеров (если не во всех) браузеры преобразуют разрывы строк в пробелы, я принимаю входные данные из переменнойi .

Код Ungolfed:

// 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!');
зубная щетка
источник
Ухоженная! Это не требует «ввода в командной строке или через стандартный ввод», что требуется для вопроса. Может быть, вы могли бы переписать его, чтобы использовать Node.js или что-то.
Странствуй Наута
@ WanderNauta Спасибо. Пожалуйста, смотрите последние изменения, так как я объясняю, почему я не использую стандартный ввод.
Зубная щетка