Книги, повні нісенітниці: Визначте обмеження


15

Як ми всі знаємо, лімерики - це короткі, п'ятирядкові, періодично невмілі вірші із схемою римування AABBA та анапестичним вимірювачем (що б там не було):

Написання абсурдного
рядка Лімерика перший та п’ять рядків римою словом
І так само, як ви вважали,
вони римуються другим
Четвертий рядок повинен римувати з третім

Вам доручено написати найкоротшу програму, яка під час подачі вхідного тексту друкує, чи вважає він, що вхід є допустимим обмеженням. Введення може бути або в командному рядку, або за допомогою стандартного введення, за вашим бажанням, а вихід може бути простим "Y" / "N" або довірчим балом, знову ж за вашим бажанням.

Ось ще один приклад правильного обмеження:

Була молода леді, очі якої
були неповторними за кольором і розміром,
коли вона їх широко відкрила. Всі
люди відхилилися в сторону
і почали здивовано

Але вірш нижче, очевидно, не обмежує, оскільки він не римується:

Там був старий чоловік святих бджіл,
котрий був застрелений осею в руку.
На запитання: "Болить?"
Він відповів: "Ні, це не так,
я так радий, що це був не шершень".

Також це не так, як у лічильнику все неправильно:

Я чув про людину з Берліна,
яка ненавиділа кімнату, в якій він був,
Коли я запитав, чому
Він сказав зітхаючи:
"Ну, бачите, минулої ночі було пару хуліганів, які святкували ведмедів, які перемагали затьмареного Кубок світу, і вони були дійсно гучні, тому я не міг спати через дим ".

Підказки

Ось декілька підказок, якими ви можете скористатися, щоб визначити, чи є ваш внесок обмеженням чи ні:

  • Лімерики завдовжки завжди п'ять рядків.
  • Рядки 1, 2 і 5 повинні римувати.
  • Рядки 3 і 4 повинні римувати.
  • Рядки 1, 2 і 5 мають близько 3x3 = 9 складів, а третій і четвертий мають 2x3 = 6 складів

Зауважте, що жодне з них, окрім першого, не є міцним і швидким: 100% -ва оцінка правильності неможлива.

Правила

  • Ваш запис повинен, як мінімум, правильно класифікувати приклади 1 - 3 детерміновано.

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

  • Ви НЕ дозволяється використовувати будь-яку бібліотеку , крім стандартних пропозицій мови програмування в.

  • Ви які дозволили припустити , що цей файл , то словник вимови CMU Sphinx, знаходиться в файлі з ім'ям "с" в поточному каталозі.

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

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

Бонуси

Доступні такі бонуси:

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

Нарешті ...

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

Якщо вам потрібні додаткові (позитивні) дані тестування, ознайомтеся з OEDILF або Книгою дурниць . Негативні дані тестування повинні бути легко побудовані.

Удачі!


Це повинно бути code-challengeчерез бонуси. Прочитайте описи тегів
user80551

2
@ user80551 Здається, що консенсус щодо мета не відрізняється .
Дверна ручка

Я уточнив характер бонусів, сподіваюся, що це усуне плутанину.
Блукати Наута

2
Goloooo Ведмеді!
alvonellos

Я не розумію бонусів. Як я повинен вивести "Y" у вигляді обмежувача?
r3mainer

Відповіді:


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)

Виглядає круто! Я ще не перевіряв його, але ви впевнені, що це вимагає введення "або в командному рядку, або через стандартний ввід" (див. Питання)? Якщо ні, то слід додати це (можливо sys.stdin.read(), open(sys.argv[1]).read()десь чи десь) і перерахувати.
Блукати Наута

Добре! Виправив це :)
Матьє Родік

Як алгоритм перевіряє риму?
DavidC

За допомогою файлу, наданого Вандером Наутою у питанні! Це справді допомогло.
Матьє Родік

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.

Невикористаний код:

// 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 Дякую Будь ласка, дивіться останню редакцію, оскільки я пояснюю, чому я не використовую стандартний ввід.
Зубна щітка
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.