난센스로 가득 찬 책 : 석회암을 식별하십시오


15

우리 모두 알다시피, 석회암은 AABBA 운율 체계와 anapestic 미터 (그것이 무엇이든)가있는 짧고 5 줄이며 때로는 울리는시입니다.

리머 릭의 불합리한 글쓰기
1 줄과 5 줄은 운율로
말한 것처럼

번째 줄은 네 번째 줄입니다.

입력 텍스트를 제공 할 때 입력이 유효한 석회암이라고 생각하는지 여부를 인쇄 하는 가장 짧은 프로그램 을 작성해야합니다 . 입력은 명령 행 또는 표준 입력을 통해 선택 가능하며 출력은 단순한 "Y"/ "N"또는 신뢰 점수 (선택 사항) 일 수 있습니다.

올바른 석 회계의 또 다른 예는 다음과 같습니다.

그녀 의 눈
은 색깔과 크기가 독특했습니다.
그녀가 넓게 열었을 때
사람들은 모두 옆으로 돌아 서서
놀랐습니다.

그러나 아래의시는 명확 하지 가 운율하지 않기 때문에, 리머 릭 :


말벌에 의해 팔에 찔린 세인트 비즈의 노인이있었습니다 .
물었을 때, "아파요?"
그는 대답했다. "아니요
. 호넷이 아니 어서 너무 기쁩니다."

미터가 모두 잘못되었으므로 이것도 아닙니다.

나는 베를린 사람 들어
그가에 있던 방 싫어
나는 이유를 물었을 때
: 그는 한숨을 쉬며 말을
"음, 당신은 참조 꿰매 경력 곰을 축하했다 주위 깡패의 부부가 있었다 지난 밤에 월드컵과 그들은 시끄러워서 식사 때문에 잠을 잘 수 없었습니다. "

단서

다음은 입력 내용이 중요하지 않은지 여부를 결정하는 데 사용할 수있는 힌트입니다.

  • 리머 릭의 길이는 항상 5 줄입니다.
  • 1, 2, 5 행은 운이 좋을 것입니다.
  • 3 번과 4 번 라인은 운이 좋을 것입니다.
  • 1, 2, 5 행에는 약 3x3 = 9 음절이 있고 세 번째와 네 번째에는 2x3 = 6 음절이 있습니다

첫 번째를 제외한 이들 중 어느 것도 빠르고 빠르지 않습니다. 100 % 정확성 등급은 불가능합니다.

규칙

  • 항목 1은 예제 1에서 3까지를 결정 론적으로 가장 정확하게 분류 해야합니다 .

  • 이 콘테스트를 위해 특별히 설계된 프로그래밍 언어를 제외하고 원하는 프로그래밍 언어를 사용할 수 있습니다 ( 여기 참조 ).

  • 프로그래밍 언어의 표준 오퍼링을 제외한 모든 라이브러리를 사용할 수 없습니다 .

  • 당신이 되어 있다고 가정 할 수 이 파일 의 CMU 스핑크스의 발음에 사전, 현재 디렉토리에 'C'라는 파일에 있습니다.

  • 테스트 입력을 하드 코딩 할 수 없습니다 . 프로그램은 일반적인 석회암 분류기 여야합니다.

  • 당신이 하는 특별한 형식없이 (예처럼), 입력이 ASCII라고 가정 할 수 있지만, 프로그램은 interpunction 혼동해서는 안된다.

보너스

다음과 같은 보너스를 이용할 수 있습니다 :

  • 당신의 프로그램은 결과를 석회암으로 출력합니까? 150 자 길이 보너스 빼기 !
  • 귀하의 프로그램은 또한 소네트를 올바르게 식별합니까? 추가 길이 보너스 150 자 빼기 !
  • 프로그램은 소네트에서 사용될 때 소네트로 결과를 출력합니까? 빼기 100 자 추가 여분의 길이 보너스!

드디어...

당신이받을 자격이 있다고 생각되는 보너스를 언급하고 점수에 도달하기 위해 캐릭터 수에서 보너스를 빼십시오. 이것은 코드 골프 콘테스트입니다 : 가장 짧은 참가작 (즉, 가장 낮은 점수를 얻은 참가작)이 승리합니다.

더 많은 (긍정적 인) 테스트 데이터가 필요하면 OEDILF 또는 Nonsense Book을 확인하십시오 . 부정적인 테스트 데이터는 쉽게 구성 할 수 있어야합니다.

행운을 빕니다!


이것은 code-challenge보너스 때문입니다. 태그 설명을 읽으십시오
user80551

2
@ user80551 메타에 대한 합의 그렇지 않은 것으로 보인다.
Doorknob

보너스의 본질을 명확하게 밝혔으므로 혼란이 사라지기를 바랍니다.
Wander Nauta

2
구 오곰!
alvonellos

보너스를 이해하지 못합니다. 어떻게 "Y"를 석회암 형태로 출력해야합니까?
squeamish ossifrage

답변:


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 가지 출력이 가능합니다 :

  • 입력 인 경우 하나라고 말하는 리머 릭
  • 입력이 하나가 아니라고 말하는 리머 릭
  • 입력이 그와 같이 인식되면 "Sonnet"

설명이있는 확장 코드

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()곳)과 재검 표를.
Wander Nauta

괜찮아! 그것을 수정 :)
Mathieu Rodic

알고리즘은 운율을 어떻게 확인합니까?
DavidC

질문에 Wander Nauta가 제공 한 파일의 도움으로! 정말 도움이되었습니다.
Mathieu Rodic

1
산뜻한! 부끄러운 줄 아시 겠어요.
Wander Nauta

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 또는 다른 것을 사용하도록 다시 작성할 수 있습니다.
Wander Nauta

@WanderNauta 감사합니다. 표준 입력을 사용하지 않는 이유를 설명하면서 최신 편집 내용을 참조하십시오 .
칫솔
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.