Sách đầy vô nghĩa: Xác định limericks


15

Như chúng ta đã biết, limericks là những bài thơ ngắn, năm dòng, đôi khi dâm dục với sơ đồ gieo vần AABBA và máy đo an-vơ (bất kể đó là gì):

Viết một
dòng vô lý của Limerick Dòng một và dòng năm vần trong từ
Và giống như bạn đã nghĩ
họ vần với dòng thứ hai
Dòng thứ tư phải vần với dòng thứ ba

Bạn có nhiệm vụ viết chương trình ngắn nhất , khi được cung cấp một văn bản đầu vào, sẽ in xem nó có cho rằng đầu vào là một giới hạn hợp lệ hay không. Đầu vào có thể nằm trên dòng lệnh hoặc thông qua đầu vào tiêu chuẩn, tùy chọn của bạn và đầu ra có thể là "Y" / "N" đơn giản hoặc điểm tin cậy, tùy theo lựa chọn của bạn.

Đây là một ví dụ khác về một limerick chính xác:

Có một cô gái trẻ có đôi mắt
độc đáo về màu sắc và kích thước
Khi cô ấy mở to,
mọi người quay sang một bên
và bắt đầu ngạc nhiên

Nhưng bài thơ dưới đây rõ ràng không phải là một đoạn giới hạn, vì nó không có vần:

Có một ông già của St. Bees,
người bị ong bắp cày đâm vào cánh tay.
Khi được hỏi, "Có đau không?"
Anh ta trả lời, "Không, không,
tôi rất vui vì đó không phải là một con ong bắp cày."

Cũng không phải cái này, vì đồng hồ là tất cả sai:

Tôi nghe nói về một người đàn ông đến từ Berlin,
người ghét căn phòng mà anh ta ở
khi tôi hỏi về lý do tại sao
anh ta sẽ nói với một tiếng thở dài:
"Chà, bạn thấy đấy, đêm qua có một vài tên trùm đầu đang ăn mừng con gấu chiến thắng World Cup, và họ rất ồn ào nên tôi không thể ngủ được vì bữa tối. "

Manh mối

Dưới đây là một số manh mối bạn có thể sử dụng để quyết định xem liệu đầu vào của bạn có phải là một limerick hay không:

  • Limericks luôn dài năm dòng.
  • Dòng 1, 2 và 5 nên gieo vần.
  • Dòng 3 và 4 nên gieo vần.
  • Dòng 1, 2 và 5 có khoảng 3x3 = 9 âm tiết, trong khi dòng thứ ba và thứ tư có 2x3 = 6 âm tiết

Lưu ý rằng không có cái nào ngoại trừ cái đầu tiên là khó và nhanh: đánh giá chính xác 100% là không thể.

Quy tắc

  • Mục nhập của bạn ít nhất nên phân loại chính xác các ví dụ từ 1 đến 3 theo kiểu xác định.

  • Bạn được phép sử dụng bất kỳ ngôn ngữ lập trình nào bạn muốn, ngoại trừ các ngôn ngữ lập trình được thiết kế riêng cho cuộc thi này (xem tại đây ).

  • Bạn không được phép sử dụng bất kỳ thư viện nào ngoại trừ các dịch vụ tiêu chuẩn của ngôn ngữ lập trình của bạn.

  • Bạn được phép giả sử rằng tệp này , từ điển phát âm Nhân sư CMU, nằm trong một tệp có tên 'c' trong thư mục hiện tại.

  • Bạn không được phép mã cứng cho các đầu vào kiểm tra: chương trình của bạn phải là một bộ phân loại limerick chung.

  • Bạn được phép giả định rằng đầu vào là ASCII, không có bất kỳ định dạng đặc biệt nào (như trong các ví dụ), nhưng chương trình của bạn không bị nhầm lẫn bởi sự xen kẽ.

Tiền thưởng

Các phần thưởng sau đây có sẵn:

  • Chương trình của bạn đưa ra kết quả của nó như là một limerick? Trừ 150 phần thưởng chiều dài!
  • Chương trình của bạn cũng xác định chính xác sonnet? Trừ 150 ký tự tiền thưởng thêm chiều dài!
  • Chương trình của bạn đưa ra kết quả là sonnet khi được sử dụng trên sonnet? Trừ thêm 100 ký tự tiền thưởng thêm chiều dài!

Cuối cùng ...

Hãy nhớ đề cập đến những phần thưởng mà bạn nghĩ rằng bạn xứng đáng, nếu có, và trừ phần thưởng từ số lượng nhân vật của bạn để đạt được điểm số của bạn. Đây là một cuộc thi golf mã : mục ngắn nhất (tức là mục có điểm thấp nhất) sẽ thắng.

Nếu bạn cần thêm dữ liệu kiểm tra (tích cực), hãy xem OEDILF hoặc Sách vô nghĩa . Dữ liệu thử nghiệm âm tính phải dễ dàng để xây dựng.

Chúc may mắn!


Điều này nên là một code-challengevì tiền thưởng. Vui lòng đọc các mô tả thẻ
user80551 22/03/2016

2
@ user80551 Đồng thuận về meta dường như là khác.
Doorknob

Tôi đã làm rõ bản chất của tiền thưởng, tôi hy vọng điều đó sẽ làm sáng tỏ sự nhầm lẫn.
Đi lang thang Nauta

2
Goooooooo Gấu!
alvonellos

Tôi không hiểu tiền thưởng. Làm thế nào tôi có thể xuất "Y" dưới dạng limerick?
squossish ossifrage

Câu trả lời:


8

Con trăn: 400 - 150 - 150 = 100

Kịch bản ngắn nhất tôi có thể nghĩ ra là ...

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

... nhưng thậm chí không thử nó. Nó phân tích từ điển được cung cấp cho mỗi từ mà nó gặp, do đó rất chậm. Ngoài ra, một lỗi được tạo ra bất cứ khi nào một từ không có trong từ điển.

Mã vẫn đáp ứng các yêu cầu mặc dù: nhận ra liệu văn bản được truyền qua stdin là limerick, sonnet hay không.

Chỉ với 20 ký tự, đây là phiên bản được tối ưu hóa:

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

Đặc trưng

  • có thể nhận ra sonnet (-150)
  • câu trả lời cho limericks bằng limerick (-150)
  • tương đối nhanh: chỉ một phân tích cú pháp tệp cho mỗi lần thực hiện

Sử dụng

cat poem.txt | python poem-check.py

Có thể có 3 đầu ra khác nhau:

  • một limmerick nói rằng đầu vào là một nếu nó là trường hợp
  • một limmerick nói rằng đầu vào không phải là một nếu nó là trường hợp
  • "Sonnet" nếu đầu vào được công nhận như vậy

Mã mở rộng với giải thích

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)

Trông thật hấp dẫn! Tôi chưa thử nghiệm nó, nhưng bạn có chắc chắn điều này nhận đầu vào "trên dòng lệnh hoặc thông qua đầu vào tiêu chuẩn" (xem câu hỏi)? Nếu không, bạn nên thêm nó (có thể là một sys.stdin.read()hoặc một open(sys.argv[1]).read()nơi nào đó) và kể lại.
Đi lang thang Nauta

Được chứ! Đã sửa nó :)
Mathieu Rodic

Làm thế nào để thuật toán kiểm tra các vần điệu?
DavidC

Với sự giúp đỡ của tập tin được cung cấp bởi Wander Nauta trong câu hỏi! Nó thực sự có ích.
Mathieu Rodic

1
Khéo léo! Một sự xấu hổ tôi không thể nâng cao bạn hai lần.
Đi lang thang Nauta

2

ECMAScript 6 (138 điểm; thử trong Firefox):

288- 150điểm thưởng cho bao gồm cả limerick (bị chèn ép từ @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!')

Ghi chú:

Yêu cầu biến cchứa nội dung của tệp từ điển, vì bạn không thể đọc các tệp trong ECMAScript đơn giản.

ECMAScript không có đầu vào tiêu chuẩn, nhưng promptthường được coi là "đầu vào tiêu chuẩn"; tuy nhiên, khi promptchuyển đổi ngắt dòng thành khoảng trắng trong hầu hết các trình duyệt (nếu không phải tất cả), tôi chấp nhận đầu vào từ biến i.

Mã bị đánh cắp:

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

Khéo léo! Tuy nhiên, điều này không mất 'đầu vào trên dòng lệnh hoặc thông qua đầu vào tiêu chuẩn', được yêu cầu bởi câu hỏi. Có lẽ bạn có thể viết lại nó để sử dụng Node.js hoặc một cái gì đó.
Đi lang thang Nauta

@WanderNauta Cảm ơn bạn. Vui lòng xem bản chỉnh sửa mới nhất, vì tôi giải thích lý do tại sao tôi không sử dụng đầu vào tiêu chuẩn.
Bàn chải đánh răng
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.