돌연변이 판 골린


28

이것은 기계 학습을 설명하기 위해 스스로를 수정하는 퀴인 또는 퀴인처럼 작동하는 프로그램을 고안해야하는 코드 골프 과제입니다.

배경

여기 에 설명 된 '판 골린 게임'이라는 기본 인공 지능 프로그램이 있습니다 . 기본 아이디어는 프로그램을 처음 실행할 때 다음과 같이 묻는 것입니다.

좋아, 뭔가 생각 해봐

천골 린인가요?

그런 다음 다음 중 하나에 회신 할 수 있습니다.

어떤 경우에는 다음과 같이 말합니다.

좋은. 너무 쉬워요.

또는 그렇지 않은 경우 :

오. 그럼 당신은 이깁니다-당신은 무엇을 생각하고 있었습니까?

당신이 말할 수있는 :

그것은 말할 것이다

개에 관한 질문을 해주세요. 개와 판 골린의 차이점을 알 수 있습니다

당신은 대답 할 수 있습니다

개미를 먹나요?

그런 다음 묻습니다.

개에 대한 답은 무엇입니까?

당신이 말할 것

아니

그리고 그것은 말할 것이다

감사

다음에 실행될 때 위의 질문을하고 그러한 질문의 이진 트리를 작성합니다.

도전

충분한 배경. 이 과제는 자체 수정 판 골린 프로그램을 작성하는 것입니다. 규칙은 다음과 같습니다.

  1. (상술 한 바와 같이) 프로그램에 출력되어야한다 STDERR. 최종 응답은 항상 "좋은 것입니다. 너무 쉬웠습니다." 또는 "감사합니다". 그런 다음 현재 버전의 프로그램 또는에 질문을 통합 한 새 버전의 프로그램을 출력해야합니다 STDOUT. 쓰기 지원하지 않는 언어로 작성된 무응답 STDOUTSTDERR읽는 것은 나 STDIN유효합니다.

  2. 즉, UNIX에서 다음과 같이 프로그램을 호출 할 수 있습니다.

예:

$ mylanguage myprogram > myprogram.1
[dialog goes here]
$ mylanguage myprogram1 > myprogram.2
[dialog goes here]
  1. 프로그램은 지정된 프롬프트를 정확하게 사용해야합니다 (프롬프트를 줄이면 스킬이 표시되지 않기 때문에). 프롬프트는 다음과 같이 따옴표없이 % s로 대체됩니다.

명부:

"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. 예 / 아니오 대답을 기대하지 않을 때, 프로그램은 받아 들여야 y또는 yes'예'에 대한 모든 경우에, 그리고 n또는 no'아니오'에 대한 어떤 경우이다. 부적합한 입력으로하는 일은 당신에게 달려 있습니다. 예를 들어 , '예'로 시작 y하거나 Y'예'로 대답하고 아니오로 대답하는 것을 결정할 수 있습니다 .

  2. 제공된 것들과 질문의 이름은 ASCII 문자, 숫자, 공백, 하이픈, 물음표, 쉼표, 마침표, 콜론 및 세미콜론으로 구성되어 있다고 가정 할 수 있습니다 ^[-?,.;: a-zA-Z]+$. 그 이상 (특히 선택한 언어의 인용 문자)에 대처할 수 있다면 잘 지내지 만 추가 점수는 얻지 못합니다.

  3. 모든 파일을 읽거나 쓸 수 없습니다 귀하의 프로그램 (제외 STDIN, STDOUTSTDERR또는 네트워크에서); 특히 디스크에서 자체 코드를 읽거나 쓸 수 없습니다. 상태는 프로그램 코드 자체에 저장해야합니다.

  4. 프로그램이 실행되고 정답을 정확하게 추측하면 정확히 quine으로 수행 해야합니다 . 즉 STDOUT, 변경하지 않고 정확히 자신의 코드에 기록해야합니다 .

  5. 프로그램을 실행하고 잘못 대답을 추측 할 때, 그것은 해야한다 에 자신의 코드 내에서 제공되는 새로운 질문과 답을 인코딩 및 쓰기 STDOUT가 원래의 추측과 제공하는 새로운 객체를 구별 할 수 있도록에서, 자신의 코드에 이전에 주어진 모든 객체를 구별하는 것 외에도.

  6. 여러 객체에 대해 학습 할 수 있도록 소프트웨어의 여러 순차적 실행에 대처할 수 있어야합니다. 여러 실행의 예는 여기 를 참조 하십시오 .

  7. 테스트 실행은 헤드링크에서 제공됩니다 ( STDINSTDERR대화 상자 만 포함 ).

  8. 표준 허점 은 제외됩니다.


프로그램이 여러 번 변이하고 2 마리 이상의 동물을 지원할 수 있어야합니까? 그렇다면 프로그램에 대해 이미 두 마리 이상의 동물이있을 때 "에 대해 질문 해주십시오 ..." 대화 의 예를들 수 있습니까?
Cristian Lupascu

사용자가 "개"대신 "개"만 말하면 어떻게 되나요? "a / an"을 탐지하기 위해 문장을 분석할까요? 아니면 답을 문자 그대로 취급 할 수 있습니까? 나는 당신이 준 프롬프트가 주어 졌다고 가정합니다 (% s).
coredump

1
@coredump 사용자가 "개"가 아니라 "개"라고 대답하면 답장이 문법으로 표시되지 않습니다. 그것은 문제가되지 않습니다.
abligh

1
돈. Runic에서 이것을 시도하는 것은 악몽 일 것입니다. 임의의 입력 문자열 (결과 출력 프로그램에서 문자열 리터럴로 표시되어야 함)에 대처하기 위해 모든 비트를 배선하는 것이 기본적으로 불가능한 이유입니다. Oh와 Runic은 STDERR로 출력 할 수 없습니다.
Draco18s

1
이것은 재미있는 "게임"처럼 보였기 때문에 골프가 아니라 골린 게임을 마음껏 즐길 수 있는 코드 펜을 만들었습니다 . 즐겨!
Skidsdev

답변:


20

일반적인 Lisp, 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)()))

세션 예

스크립트 이름을 지정하고 pango1.lisp다음과 같이 실행하십시오 (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

곰을 추가하는 또 다른 라운드 :

~$ 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

나무 늘보 추가 (답이 "아니오"인 경우 테스트) :

~$ 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

마지막 파일 테스트 :

~$ 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.

비고

  • 먼저 인쇄를 잊었습니다 "Thanks". 여기 있습니다.
  • 보시다시피 질문 뒤에는 (y or n)기존 y-or-n-p기능을 사용하고 있기 때문 입니다. 필요한 경우이 출력을 제거하기 위해 답변을 업데이트 할 수 있습니다.
  • Common Lisp에는 *QUERY-IO*사용자 상호 작용 전용 양방향 스트림 이 있으며 여기서 사용하고 있습니다. 표준 출력과 사용자 상호 작용은 혼란스럽지 않으며 IMHO는 질문의 정신을 따릅니다.
  • SAVE-LISP-AND-DIE실제로 사용 하는 것이 더 나은 방법입니다.

생성 된 출력

마지막으로 생성 된 스크립트는 다음과 같습니다.

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

설명

의사 결정 트리는 다음과 같습니다.

  • 와 같은 문자열 "a pangolin"은 잎을 나타냅니다.
  • 세 가지 요소의 목록 : 폐쇄하지 예 / 아니오 , 질문 문자열로하고, 그리고 문제와 관련된 두 가지 하위 트리입니다.(question if-true if-false)questionif-trueif-false

U기능은 산책반환 가능성이 수정 트리. 각 질문은 사용자와 상호 작용하면서 루트에서 시작하여 리프에 도달 할 때까지 차례로 질문됩니다.

  • 질문에 대한 답변 이 (resp. no ) 인 경우 중간 노드의 반환 값 (Q Y N)(Q (U Y) N)(resp. )입니다.(Q Y (U N))Q

  • 리프에 대해 리턴 된 값은 프로그램이 정답을 올바르게 추측 한 경우 리프 자체이거나 리프가 사용자의 값에 따라 질문과 두 가지 가능한 결과로 대체되는 세련된 트리입니다.

이 부분은 다소 간단했습니다. 소스 코드를 인쇄하기 위해 독자 변수를 사용하여 자체 참조 코드를 작성합니다.*PRINT-CIRCLE*true 로 설정 하면 예쁜 인쇄 중에 무한 재귀를 피할 수 있습니다.WRITEwith 를 사용할 때의 요령 :print-circle T은 쓰기가 마지막 형식인지 여부에 따라 함수가 값을 REPL에 반환 할 수 있다는 것입니다. 따라서 REPL이 원형 구조를 처리하지 않으면 표준 기본값으로 정의 된 것처럼 *PRINT-CIRCLE*무한 재귀가있을 것입니다. 우리는 원형 구조가 REPL로 반환되지 않도록해야하기 때문에 LET의 마지막 위치에 NIL이 있습니다. 이 접근 방식은 문제를 크게 줄입니다.


좋아 보인다! 이 (y or n)필요하지 않습니다,하지만 나는 그것이 개선으로 허용하도록 유혹하고있다.
abligh

@abligh 감사합니다. y / n에 관해서는, 그것은 좋을 것입니다 .IMHO는 이것이 프롬프트 단축을 피하는 것에 관한 # 3과 실제로 모순되지 않습니다.
coredump

9

파이썬 2.7.6, (820) 728 바이트

(다른 버전에서 작동하지만 확실하지 않습니다)

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)

글쎄, Common Lisp 답변만큼 짧지는 않지만 여기에 코드가 있습니다!


4

파이썬 3, 544 바이트

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)

온라인으로 사용해보십시오!

질문 / 응답 / 응답은 배열에 저장됩니다. 여기서 배열이 3 개의 항목 (예 :)을 저장 ['Does it eat ants',['a pangolin'],['a dog']]하면 질문에 대한 답변을 얻고 답에 따라 두 번째 또는 세 번째 항목의 내용 만 반복합니다. 하나의 항목이있는 배열에 도달하면 질문을하고 전체 소스 코드가 문자열로되어 있으므로 split-join 메소드를 사용하여 배열에 확장을 삽입하여 새 분기를 추가 할 수 있습니다 .

나는 원래 quine 요구 사항을 실현하지 않고 이것을 작성했기 때문에 질문을 다시 읽고 코드를 실행하고 문자열로 사용할 수있는 방법을 찾아야했지만 결국 멋진 확장 가능한 quine 형식에 대한 아이디어를 발견했습니다.

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

1

파이썬 3 , 497 바이트

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)

트리 표현에 대한 무해한 답변과 매우 유사합니다. 응답이 하나만 나타날 때까지 목록에 더 깊이 들어가면서 다음 질문을 재귀 적으로 묻습니다.

언 골프 버전 (퀸링 제외)

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)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.