Trenggiling mutan

28

Ini adalah tantangan kode-golf di mana Anda perlu menyusun program yang bertindak seperti quine atau quine yang memodifikasi dirinya sendiri untuk menggambarkan pembelajaran mesin.

Latar Belakang

Ada program kecerdasan buatan dasar yang disebut 'permainan trenggiling' yang dijelaskan di sini . Ide dasarnya adalah program saat dijalankan pertama kali bertanya:

OKE, tolong pikirkan sesuatu

Apakah itu trenggiling?

Anda kemudian dapat menjawab:

iya nih

Dalam hal ini dikatakan:

Baik. Itu sangat mudah.

Atau jika tidak tertulis:

Oh Nah Anda menang kemudian - Apa yang Anda pikirkan?

Yang bisa Anda katakan:

anjing

Yang dikatakannya

Tolong beri saya pertanyaan tentang seekor anjing, jadi saya bisa membedakan antara anjing dan trenggiling

Anda mungkin membalas

Apakah itu memakan semut?

Kemudian akan bertanya:

Apa jawaban untuk seekor anjing?

Yang akan Anda katakan

tidak

Dan itu akan berkata

Terima kasih

Lain kali itu berjalan, itu akan mengajukan pertanyaan di atas, dan akan membangun pohon biner dari pertanyaan seperti itu.

Tantangan

Cukup latar belakangnya. Tantangan ini adalah menulis program trenggiling yang memodifikasi sendiri. Aturannya adalah sebagai berikut:

  1. Output program (seperti dijelaskan di atas) seharusnya STDERR. Respons terakhir akan selalu "Bagus. Itu sangat mudah." atau "Terima kasih". Setelah ini, harus menampilkan versi program saat ini, atau versi baru dari program yang memasukkan pertanyaan STDOUT. Tidak ada jawaban yang ditulis dalam bahasa yang tidak mendukung penulisan STDOUTdan STDERRatau pembacaan dari yang STDINvalid.

  2. Dengan kata lain di bawah UNIX Anda dapat menjalankan program seperti ini:

contoh:

$ mylanguage myprogram > myprogram.1
[dialog goes here]
$ mylanguage myprogram1 > myprogram.2
[dialog goes here]
  1. Program harus menggunakan persis prompt yang ditentukan (karena memendekkan prompt tidak menunjukkan keahlian). Prompt adalah (tanpa tanda kutip, dan di mana% s diganti) sebagai berikut:

daftar:

"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. Ketika mengharapkan jawaban ya / tidak, program Anda harus menerima yatau yesdalam hal apa pun untuk 'ya', dan natau nodalam hal apa pun untuk 'tidak'. Apa yang Anda lakukan dengan input yang tidak sesuai adalah terserah Anda. Sebagai contoh, Anda mungkin memutuskan untuk mengambil jawaban yang dimulai dengan yatau Ysebagai 'ya', dan apa pun yang tidak.

  2. Anda dapat mengasumsikan bahwa nama-nama barang yang disediakan dan pertanyaan hanya terdiri dari huruf ASCII, angka, spasi, tanda hubung, tanda tanya, koma, titik penuh, titik dua, dan titik koma, yaitu cocok dengan regex berikut ^[-?,.;: a-zA-Z]+$. Jika Anda dapat mengatasi lebih dari itu (terutama karakter kutipan dalam bahasa yang Anda pilih), Anda akan menjadi sombong, tetapi tidak mendapatkan poin tambahan.

  3. Program Anda mungkin tidak membaca atau menulis file apapun (termasuk STDIN, STDOUT, dan STDERR), atau dari jaringan; khusus itu tidak dapat membaca atau menulis kode sendiri dari disk. Keadaannya harus disimpan dalam kode program itu sendiri.

  4. Ketika program dijalankan dan menebak jawabannya dengan benar, ia harus melakukan persis seperti quine, yaitu harus menulis STDOUTpersis kode sendiri, tidak berubah.

  5. Ketika program dijalankan dan menebak jawaban salah, ia harus menyandikan pertanyaan dan jawaban baru yang disediakan dalam kode sendiri dan menuliskannya STDOUTdalam kode sendiri, sehingga mampu membedakan antara tebakan aslinya dan objek baru yang disediakan, dalam Selain membedakan antara semua objek yang diberikan sebelumnya.

  6. Anda harus dapat mengatasi beberapa kali menjalankan perangkat lunak sehingga dapat mempelajari banyak objek. Lihat di sini untuk contoh beberapa proses.

  7. Uji coba diberikan di tautan di kepala (jelas hanya mencakup dialog STDINdan STDERR).

  8. Celah standar tidak termasuk.

abligh
sumber
Haruskah program dapat bermutasi beberapa kali dan mendukung lebih dari 2 hewan? Jika demikian, dapatkah Anda memberikan contoh dialog "Tolong beri saya pertanyaan tentang ..." ketika sudah ada dua hewan atau lebih yang diketahui oleh program?
Cristian Lupascu
Bagaimana jika pengguna hanya mengatakan "anjing" bukan "anjing"? Haruskah kita menguraikan kalimat untuk mendeteksi "a / an" atau bisakah kita memperlakukan jawabannya secara harfiah? Saya berasumsi begitu diberi prompt yang Anda berikan (% s).
coredump
1
@coredump jika pengguna mengatakan "anjing" bukan "anjing", maka balasannya tidak akan menjadi tata bahasa. Itu bukan masalah.
abligh
1
Oof. Mencoba melakukan ini di Runic akan menjadi mimpi buruk. Alasan utama adalah bahwa kabel semua bit untuk mengatasi string input sewenang-wenang (yang kemudian harus hadir sebagai string literal dalam program output yang dihasilkan) pada dasarnya tidak mungkin. Oh dan Runic tidak dapat menampilkan ke STDERR.
Draco18s
1
Ini tampak seperti "permainan" yang menyenangkan, jadi alih-alih bermain golf, saya membuat codepen di mana Anda bisa memainkan Permainan Pangolin sesuka hati Anda. Nikmati!
Skidsdev

Jawaban:

20

Gangguan umum, 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)()))

Sesi contoh

Beri nama skrip pango1.lispdan jalankan sebagai berikut (menggunakan 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

Babak lain, menambahkan beruang:

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

Menambahkan sloth (kami menguji kasus di mana jawabannya adalah "tidak"):

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

Menguji file terakhir:

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

Komentar

  • Saya pertama kali lupa mencetak "Thanks", ini dia.
  • Seperti yang Anda lihat, pertanyaan diikuti oleh (y or n), yang karena saya menggunakan y-or-n-pfungsi yang ada . Saya dapat memperbarui jawaban untuk menghapus output ini jika diperlukan.
  • Common Lisp memiliki *QUERY-IO*aliran dua arah yang didedikasikan untuk interaksi pengguna, yang saya gunakan di sini. Output standar dan interaksi pengguna tidak berantakan, yang mengikuti IMHO semangat pertanyaan.
  • Menggunakan SAVE-LISP-AND-DIEakan menjadi pendekatan yang lebih baik dalam praktik.

Output yang dihasilkan

Berikut ini skrip yang dihasilkan terakhir:

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

Penjelasan

Pohon keputusan dapat berupa:

  • string, seperti "a pangolin", yang mewakili daun.
  • daftar tiga elemen: di (question if-true if-false)mana ada pertanyaan ya / tidakquestion tertutup , sebagai string, dan dan adalah dua kemungkinan sub-sub yang terkait dengan pertanyaan tersebut.if-trueif-false

The Ufungsi berjalan dan mengembalikan pohon mungkin diubah. Setiap pertanyaan ditanyakan secara bergantian, mulai dari root hingga mencapai daun, saat berinteraksi dengan pengguna.

  • Nilai yang dikembalikan untuk node perantara (Q Y N)adalah (Q (U Y) N)(resp. (Q Y (U N))) Jika jawaban atas pertanyaan Qadalah ya (resp. Tidak ).

  • Nilai yang dikembalikan untuk daun adalah baik daun itu sendiri, jika program menebak jawaban dengan benar, atau pohon yang disempurnakan di mana daun digantikan oleh pertanyaan dan dua hasil yang mungkin, sesuai dengan nilai yang diambil dari pengguna.

Bagian ini agak mudah. Untuk mencetak kode sumber, kami menggunakan variabel pembaca untuk membuat kode referensi-sendiri.Dengan menyetel *PRINT-CIRCLE*ke true, kami menghindari rekursi tak terbatas selama pencetakan cantik.Trik ketika menggunakan WRITEdengan :print-circle Tadalah bahwa fungsi tersebut mungkin juga mengembalikan nilai ke REPL, tergantung pada apakah menulis adalah bentuk terakhir, dan jika REPL tidak menangani struktur lingkaran, seperti itu didefinisikan oleh nilai standar standar *PRINT-CIRCLE*, akan ada rekursi tak terbatas. Kita hanya perlu memastikan struktur lingkaran tidak dikembalikan ke REPL, itu sebabnya ada NIL di posisi terakhir LET. Pendekatan ini sangat mengurangi masalah.

coredump
sumber
Kelihatan bagus! Tidak (y or n)diperlukan, tetapi saya tergoda untuk mengizinkannya karena ini merupakan peningkatan.
abligh
@abligh Terima kasih. Tentang y / n, itu akan menyenangkan, itu membantu dan IMHO ini tidak benar-benar bertentangan dengan # 3 yaitu tentang menghindari memperpendek petunjuknya.
coredump
9

Python 2.7.6, 820 728 byte

(Mungkin bekerja pada versi yang berbeda tapi saya tidak yakin)

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)

Yah, itu tidak sesingkat jawaban Common Lisp, tapi di sini ada beberapa kode!

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

Cobalah secara Online!

Pertanyaan / jawaban / tanggapan disimpan dalam sebuah array, di mana jika array menyimpan tiga item (misalnya ['Does it eat ants',['a pangolin'],['a dog']]) maka ia mendapat jawaban atas pertanyaan dan mengulangi hanya dengan konten item kedua atau ketiga, tergantung pada jawabannya. Ketika sampai ke array dengan hanya satu item, ia mengajukan pertanyaan, dan karena memiliki seluruh kode sumbernya sebagai string, ia dapat menggunakan metode split-join untuk menyisipkan ekstensi ke array untuk menambah cabang baru .

Saya awalnya menulis ini tanpa menyadari persyaratan quine, jadi membaca ulang pertanyaan dan harus menemukan cara agar saya bisa mengeksekusi kode dan menggunakannya sebagai string adalah sulit, tetapi saya akhirnya menemukan ide format quine yang dapat diupgrade yang bagus:

q="""
print("Some actual stuff")
q='q=""'+'"'+q+'""'+'"'+chr(10)+'exec()'
print(q)
"""
exec(q)
Tidak berbahaya
sumber
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)

Mirip dengan jawaban Harmless untuk representasi pohon. Secara rekursif mengajukan pertanyaan berikutnya, sambil masuk lebih dalam ke dalam daftar, sampai hanya ada satu jawaban.

Versi tidak digabungkan (tanpa 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)
Matthew Jensen
sumber