Tê tê đột biến


28

Đây là một thử thách chơi gôn mã, theo đó bạn cần phải nghĩ ra một chương trình hoạt động như một câu đố hoặc một câu đố tự sửa đổi để minh họa cho việc học máy.

Lý lịch

Có một chương trình trí tuệ nhân tạo cơ bản gọi là 'trò chơi tê tê' được mô tả ở đây . Các ý tưởng cơ bản là chương trình khi chạy lần đầu tiên hỏi:

OK, hãy nghĩ về một cái gì đó

Có phải là một con tê tê?

Sau đó, bạn có thể trả lời:

Vâng

Trong trường hợp đó, nó nói:

Tốt Điều đó thật dễ dàng.

Hoặc nếu không, nó nói:

Oh. Vậy thì bạn thắng rồi - Bạn đang nghĩ gì vậy?

Mà bạn có thể nói:

con chó

Nó sẽ nói

Xin vui lòng cho tôi một câu hỏi về một con chó, để tôi có thể nói sự khác biệt giữa một con chó và một con tê tê

bạn có thể trả lời

Nó có ăn kiến ​​không?

Sau đó nó sẽ hỏi:

Câu trả lời cho một con chó là gì?

Mà bạn sẽ nói

Không

Và nó sẽ nói

Cảm ơn

Lần tới khi nó chạy, nó sẽ đặt câu hỏi ở trên và sẽ xây dựng một cây nhị phân của những câu hỏi như vậy.

Các thách thức

Đủ nền. Thách thức này là để viết một chương trình tê tê tự sửa đổi. Luật như sau:

  1. Đầu ra chương trình (như được mô tả ở trên) nên được STDERR. Câu trả lời cuối cùng sẽ luôn là "Tốt. Điều đó thật dễ dàng." hoặc "Cảm ơn". Sau này, nó sẽ xuất ra phiên bản hiện tại của chương trình hoặc phiên bản mới của chương trình kết hợp câu hỏi với STDOUT. Không có câu trả lời được viết bằng ngôn ngữ không hỗ trợ viết STDOUTSTDERRđọc từ STDINsẽ có hiệu lực.

  2. Nói cách khác, trong UNIX, bạn có thể gọi chương trình như thế này:

thí dụ:

$ mylanguage myprogram > myprogram.1
[dialog goes here]
$ mylanguage myprogram1 > myprogram.2
[dialog goes here]
  1. Chương trình phải sử dụng chính xác các lời nhắc được chỉ định (vì rút ngắn lời nhắc cho thấy không có kỹ năng). Các lời nhắc là (không có dấu ngoặc kép và trong đó% s được thay thế) như sau:

danh sách:

"OK, please think of something"
"Is it %s?"
"Good. That was soooo easy."
"Oh. Well you win then -- What were you thinking of?"
"Please give me a question about %s, so I can tell the difference between %s and %s"
"What is the answer for %s?"
"Thanks"
  1. Khi hy vọng có / không trả lời, chương trình của bạn nên chấp nhận yhoặc yestrong bất kỳ trường hợp cho 'yes', và nhoặc notrong bất kỳ trường hợp cho 'không'. Những gì bạn làm với đầu vào không phù hợp là tùy thuộc vào bạn. Chẳng hạn, bạn có thể quyết định lấy bất kỳ câu trả lời nào bắt đầu bằng yhoặc Ylà "có", và bất cứ điều gì khác là không.

  2. Bạn có thể giả sử rằng tên của những thứ được cung cấp và các câu hỏi chỉ bao gồm các chữ cái ASCII, số, dấu cách, dấu gạch nối, dấu hỏi, dấu phẩy, dấu chấm hết, dấu hai chấm và dấu chấm phẩy, tức là chúng khớp với regex ^[-?,.;: a-zA-Z]+$. Nếu bạn có thể đối phó với nhiều hơn thế (đặc biệt là các ký tự trích dẫn trong ngôn ngữ bạn đã chọn), bạn sẽ có được tự mãn, nhưng không được thêm bất kỳ điểm nào.

  3. Chương trình của bạn có thể không đọc hoặc viết bất kỳ tập tin (không bao gồm STDIN, STDOUTSTDERR), hoặc từ mạng; cụ thể là nó không thể đọc hay viết mã riêng từ đĩa. Trạng thái của nó phải được lưu trong mã chương trình.

  4. Khi chương trình được chạy và đoán câu trả lời chính xác, nó phải thực hiện chính xác như một câu hỏi, tức là nó phải ghi vào STDOUTchính xác mã của chính nó, không thay đổi.

  5. Khi chương trình được chạy và đoán câu trả lời không chính xác, nó phải mã hóa câu hỏi và câu trả lời mới được cung cấp trong mã của chính nó và viết nó STDOUTvào mã riêng của nó, để nó có khả năng phân biệt giữa dự đoán ban đầu và đối tượng mới được cung cấp, trong ngoài ra để phân biệt giữa tất cả các đối tượng trước đây.

  6. Bạn phải có khả năng đối phó với nhiều lần chạy phần mềm để nó tìm hiểu về nhiều đối tượng. Xem ở đây để biết ví dụ về nhiều lần chạy.

  7. Chạy thử được đưa ra tại liên kết trong đầu (rõ ràng chỉ bao gồm hộp thoại STDINSTDERRhộp thoại).

  8. Lỗ hổng tiêu chuẩn được loại trừ.


Chương trình có thể đột biến nhiều lần và hỗ trợ nhiều hơn 2 con vật không? Nếu vậy, bạn có thể cung cấp một ví dụ "Xin vui lòng cho tôi một câu hỏi về ..." đối thoại khi đã có hai hoặc nhiều động vật mà chương trình biết về?
Cristian Lupascu

Nếu người dùng chỉ nói "chó" thay vì "chó" thì sao? Chúng ta sẽ phân tích câu để phát hiện "a / an" hay chúng ta có thể xử lý câu trả lời theo nghĩa đen không? Tôi giả sử đã đưa ra lời nhắc mà bạn đã đưa ra (% s).
coredump

1
@coredump nếu người dùng nói "dog" không phải "dog", thì các câu trả lời sẽ không đúng ngữ pháp. Đó không phải là một vấn đề.
abligh

1
Ôi. Cố gắng làm điều này trong Runic sẽ là một cơn ác mộng. Lý do chính là việc nối tất cả các bit để đối phó với các chuỗi đầu vào tùy ý (sau đó cần phải có mặt dưới dạng chuỗi ký tự trong chương trình đầu ra kết quả) về cơ bản là không thể. Oh và Runic không thể xuất ra STDERR.
Draco18

1
Đây dường như là một "trò chơi" thú vị, vì vậy thay vì chơi golf, tôi đã tạo ra một loại tiền mã hóa để bạn có thể chơi Trò chơi Pangolin theo nội dung trái tim của bạn. Thưởng thức!
Skidsdev

Câu trả lời:


20

Lisp thông thường, 631 576

(let((X"a pangolin"))#1=(labels((U(M &AUX(S *QUERY-IO*))(IF(STRINGP M)(IF(Y-OR-N-P"Is it ~A?"M)(PROG1 M(FORMAT S"Good. That was soooo easy.~%"))(LET*((N(PROGN(FORMAT S"Oh. Well you win then -- What were you thinking of?~%")#2=(READ-LINE S)))(Q(PROGN(FORMAT S"Please give me a question about ~A, so I can tell the difference between ~A and ~A~%"N N M)#2#)))(PROG1(IF(Y-OR-N-P"What is the answer for ~A?"N)`(,Q ,N ,M)`(,Q ,M ,N))(FORMAT S"Thanks~%"))))(DESTRUCTURING-BIND(Q Y N)M(IF(Y-OR-N-P Q)`(,Q ,(U Y),N)`(,Q ,Y,(U N)))))))(write(list'let(list`(X',(U x)))'#1#):circle t)()))

Ví dụ phiên

Đặt tên cho kịch bản pango1.lispvà thực hiện như sau (sử dụng SBCL):

~$ sbcl --noinform --quit --load pango1.lisp > pango2.lisp
Is it a pangolin? (y or n) n
Oh. Well you win then -- What were you thinking of?
a cat
Please give me a question about a cat, so I can tell the difference between a cat and a pangolin
Does it sleep a lot?
What is the answer for a cat? (y or n) y
Thanks

Một vòng khác, thêm con gấu:

~$ sbcl --noinform --quit --load pango2.lisp > pango3.lisp
Does it sleep a lot? (y or n) y

Is it a cat? (y or n) n
Oh. Well you win then -- What were you thinking of?
a bear
Please give me a question about a bear, so I can tell the difference between a bear and a cat
Does it hibernate?
What is the answer for a bear? (y or n) y
Thanks

Thêm một con lười (chúng tôi kiểm tra trường hợp câu trả lời là "không"):

~$ sbcl --noinform --quit --load pango3.lisp > pango4.lisp
Does it sleep a lot? (y or n) y

Does it hibernate? (y or n) n

Is it a cat? (y or n) n
Oh. Well you win then -- What were you thinking of?
a sloth
Please give me a question about a sloth, so I can tell the difference between a sloth and a cat
Does it move fast?
What is the answer for a sloth? (y or n) n
Thanks

Kiểm tra tệp cuối cùng:

~$ sbcl --noinform --quit --load pango4.lisp > pango5.lisp
Does it sleep a lot? (y or n) y

Does it hibernate? (y or n) n

Does it move fast? (y or n) y

Is it a cat? (y or n) y
Good. That was soooo easy.

Nhận xét

  • Lần đầu tiên tôi quên in "Thanks", đây rồi.
  • Như bạn có thể thấy, các câu hỏi được theo sau (y or n), đó là vì tôi đang sử dụng y-or-n-pchức năng hiện có . Tôi có thể cập nhật câu trả lời để loại bỏ đầu ra này nếu cần.
  • Lisp thông thường có một *QUERY-IO*luồng hai chiều dành riêng cho tương tác người dùng, đó là những gì tôi đang sử dụng ở đây. Đầu ra tiêu chuẩn và tương tác người dùng không gây rối, theo IMHO tinh thần của câu hỏi.
  • Sử dụng SAVE-LISP-AND-DIEsẽ là một cách tiếp cận tốt hơn trong thực tế.

Tạo đầu ra

Đây là kịch bản được tạo cuối cùng:

(LET ((X
       '("Does it sleep a lot?"
              ("Does it hibernate?" "a bear"
               ("Does it move fast?" "a cat" "a sloth"))
              "a pangolin")))
  #1=(LABELS ((U (M &AUX (S *QUERY-IO*))
                (IF (STRINGP M)
                    (IF (Y-OR-N-P "Is it ~A?" M)
                        (PROG1 M (FORMAT S "Good. That was soooo easy.~%"))
                        (LET* ((N
                                (PROGN
                                 (FORMAT S
                                         "Oh. Well you win then -- What were you thinking of?~%")
                                 #2=(READ-LINE S)))
                               (Q
                                (PROGN
                                 (FORMAT S
                                         "Please give me a question about ~A, so I can tell the difference between ~A and ~A~%" 
                                         N N M)
                                 #2#)))
                          (PROG1
                              (IF (Y-OR-N-P "What is the answer for ~A?" N)
                                  `(,Q ,N ,M)
                                  `(,Q ,M ,N))
                            (FORMAT S "Thanks~%"))))
                    (DESTRUCTURING-BIND
                        (Q Y N)
                        M
                      (IF (Y-OR-N-P Q)
                          `(,Q ,(U Y) ,N)
                          `(,Q ,Y ,(U N)))))))
       (WRITE (LIST 'LET (LIST `(X ',(U X))) '#1#) :CIRCLE T)
       NIL))

Giải thích

Một cây quyết định có thể là:

  • một chuỗi, giống như "a pangolin", đại diện cho một chiếc lá.
  • một danh sách gồm ba yếu tố: (question if-true if-false)nơi questioncó một câu hỏi có / không đóng , dưới dạng một chuỗi if-trueif-falselà hai cây con có thể liên quan đến câu hỏi.

Các Uchức năng đitrả về một cây có thể sửa đổi. Mỗi câu hỏi được hỏi lần lượt, bắt đầu từ gốc cho đến khi chạm đến một chiếc lá, trong khi tương tác với người dùng.

  • Giá trị được trả về cho một nút trung gian (Q Y N)(Q (U Y) N)(resp. (Q Y (U N))) Nếu câu trả lời cho câu hỏi Q (resp. No ).

  • Giá trị trả về cho một chiếc lá là chính chiếc lá, nếu chương trình đoán chính xác câu trả lời, hoặc một cây tinh chế nơi chiếc lá được thay thế bằng một câu hỏi và hai kết quả có thể xảy ra, theo các giá trị được lấy từ người dùng.

Phần này khá đơn giản. Để in mã nguồn, chúng tôi sử dụng các biến đọc để xây dựng mã tự tham chiếu.Bằng cách đặt *PRINT-CIRCLE*thành đúng, chúng tôi tránh được đệ quy vô hạn trong quá trình in đẹp.Bí quyết khi sử dụng WRITEvới :print-circle Tđó là chức năng cũng có thể trả về giá trị để REPL, tuỳ thuộc vào việc ghi là hình thức cuối cùng, và như vậy, nếu REPL không xử lý cấu trúc hình tròn, giống như nó được xác định bởi giá trị mặc định tiêu chuẩn *PRINT-CIRCLE*, sẽ có một đệ quy vô hạn. Chúng ta chỉ cần đảm bảo rằng cấu trúc vòng tròn không được trả về REPL, đó là lý do tại sao có NIL ở vị trí cuối cùng của LET. Cách tiếp cận này làm giảm đáng kể vấn đề.


Có vẻ tốt! Điều (y or n)này là không bắt buộc, nhưng tôi muốn cho phép nó vì nó là một cải tiến.
abligh

@ableigh Cảm ơn. Về y / n, điều đó thật tuyệt, thật hữu ích và IMHO điều này không thực sự mâu thuẫn với # 3 mà là về việc tránh rút ngắn các lời nhắc.
coredump

9

Python 2.7.6, 820 728 byte

(Có thể hoạt động trên các phiên bản khác nhau nhưng tôi không chắc chắn)

def r(O,R):
 import sys,marshal as m;w=sys.stderr.write;i=sys.stdin.readline;t=O;w("OK, please think of something\n");u=[]
 def y(s):w(s);return i()[0]=='y'
 while t:
  if type(t)==str:
   if y("Is it %s?"%t):w("Good. That was soooo easy.")
   else:w("Oh. Well you win then -- What were you thinking of?");I=i().strip();w("Please give me a question about %s, so I can tell the difference between %s and %s"%(I,t,I));q=i().strip();a=y("What is the answer for %s?"%q);w("Thanks");p=[q,t];p.insert(a+1,I);z=locals();exec"O"+"".join(["[%s]"%j for j in u])+"=p"in z,z;O=z["O"]
   t=0
  else:u+=[y(t[0])+1];t=t[u[-1]]
 print"import marshal as m;c=%r;d=lambda:0;d.__code__=m.loads(c);d(%r,d)"%(m.dumps(R.__code__),O)
r('a pangolin',r)

Chà, nó không ngắn như câu trả lời Lisp thông thường, nhưng đây là một số mã!


4

Python 3, 544 byte

q="""
d=['a pangolin'];i=input;p=print
p("OK, Please think of something")
while len(d)!=1:
    d=d[1+(i(d[0])[0]=="n")]
x=i("Is it "+d[0]+"?")
if x[0]=="n":
    m=i("Oh. Well you win then -- What were you thinking of?")
    n=[i("Please give me a question about "+m+", so I can tell the difference between "+d[0]+" and "+m),*[[d[0]],[m]][::(i("What is the answer for "+m+"?")[0]=="n")*2-1]]
    p("Thanks")
    q=repr(n).join(q.split(repr(d)))
else:
    p("Good. That was soooo easy.")
q='q=""'+'"'+q+'""'+'"'+chr(10)+'exec(q)'
p(q)
"""
exec(q)

Hãy thử trực tuyến!

Các câu hỏi / câu trả lời / câu trả lời được lưu trữ trong một mảng, trong đó nếu mảng lưu trữ ba mục (ví dụ ['Does it eat ants',['a pangolin'],['a dog']]) thì nó sẽ có câu trả lời cho câu hỏi và lặp lại chỉ với nội dung của mục thứ hai hoặc thứ ba, tùy thuộc vào câu trả lời. Khi đến một mảng chỉ có một mục, nó sẽ đặt câu hỏi và vì nó có toàn bộ mã nguồn của nó nên một chuỗi có thể sử dụng phương thức chia tách để chèn phần mở rộng vào mảng để thêm nhánh mới .

Ban đầu tôi đã viết điều này không nhận ra yêu cầu quine, vì vậy đọc lại câu hỏi và phải tìm cách tôi có thể thực thi mã và sử dụng nó như một chuỗi là khó khăn, nhưng cuối cùng tôi đã vấp phải ý tưởng về định dạng quine có thể mở rộng tốt đẹp:

q="""
print("Some actual stuff")
q='q=""'+'"'+q+'""'+'"'+chr(10)+'exec()'
print(q)
"""
exec(q)

1

Python 3 , 497 byte

t=["a pangolin"];c='''p=print;i=input;a=lambda q:i(q)[0]in"Yy"
def q(t):
  if len(t)<2:
    g=t[0]
    if a(f"Is it {g}?"):p("Good. That was soooo easy.")
    else:s=i("Oh. Well you win then -- What were you thinking of?");n=i(f"Please give me a question about {s}, so I can tell the difference between {s} and {g}.");t[0]=n;t+=[[g],[s]][::1-2*a(f"What is the answer for {s}?")];p("Thanks")
  else:q(t[2-a(t[0])])
p("Ok, please think of something");q(t);p(f"t={t};c=''{c!r}'';exec(c)")''';exec(c)

Khá giống với câu trả lời của Harmless cho đại diện cho cây. Nó đệ quy hỏi câu hỏi tiếp theo, trong khi đi sâu hơn vào danh sách, cho đến khi chỉ có một câu trả lời.

Phiên bản Ungolfed (không có quining)

tree = ['a pangolin']

def ask(question):
  answer = input(question + '\n')
  if answer.lower() in ['yes', 'no']:
    return answer.lower() == 'yes'
  else:
    print('Please answer "yes" or "no".')
    return ask(question)
    
def query(tree):
  if len(tree) == 1:
    guess = tree.pop()
    if ask(f'Is it {guess}?'):
      print('Good. That was soooo easy.')
      tree.append(guess)
    else:
      thing = input('Oh. Well you win then -- What were you thinking of?\n')
      new_question = input(f'Please give me a question about {thing}, so I can tell the difference between {thing} and {guess}.\n')
      answer = ask(f'What is the answer for {thing}?')
      print('Thanks')
      tree.append(new_question)
      if answer:
        tree.append([thing])
        tree.append([guess])
      else:
        tree.append([guess])
        tree.append([thing])
  else:
    if ask(tree[0]):
      query(tree[1])
    else:
      query(tree[2])
      
while True:
  input('Ok, please think of something\n')
  query(tree)
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.