Apa langkah Anda selanjutnya?

18

Tantangan ini adalah untuk menulis fungsi minimax dalam bahasa pilihan Anda, untuk menghasilkan langkah terbaik berikutnya dalam permainan NxN dari tic-tac-toe yang diberikan status papan saat ini . Input papan dapat diterima sebagai Matriks, Koleksi 2D atau apa pun yang masuk akal bagi Anda, tetapi mematuhi aturan . Keluaran menjadi langkah terbaik berikutnya untuk siapa pun giliran saat ini , di mana X dianggap telah dimulai .

Latar Belakang Cepat pada Algoritma Minimax

Ide dasar dari algoritma minimax adalah untuk menghitung semua hasil yang mungkin sebagai DAG kemudian membobotnya dengan manfaat bahwa urutan gerakan harus ke pemain, dikunci oleh langkah pertama yang dibuat. Semua hasil yang mungkin kemudian 'tertekuk' oleh langkah pertama, dan diberi skor berdasarkan jumlah semua hasil (-1 untuk kekalahan, 0 untuk dasi dan 1 untuk menang). Dalam implementasi yang membutuhkan banyak pemain untuk bermain, Anda menghitung semua gerakan yang mungkin dilakukan oleh pemain, dan semua respons yang mungkin dilakukan oleh lawan juga. Misalnya, dalam permainan tic-tac-toe (setelah langkah pertama) ada 8 gerakan pertama yang bisa Anda buat, dan semuanya mungkin tampak sama ketika hanya menganalisis belokan berikutnya. Tetapi dengan mengulangi semua hasil yang mungkin untuk setiap rangkaian gerakan yang memungkinkan yang menghasilkan hasil akhir dan merangkum semuanya,

Untuk ringkasan yang lebih baik, lebih mendalam dan kontekstual dari algoritma mini-max dalam hal tic-tac-toe, baca lebih lanjut di sini: http://neverstopbuilding.com/minimax

XKCD (3x3 Solusi Saja)

Semua kemungkinan gerakan untuk permainan tic-tac-toe 3x3.

Aturan

  • Bahasa apa pun dapat digunakan, tetapi tidak ada perpustakaan minimax eksternal yang diizinkan.
  • Output dapat berupa koordinat (0-n, 0-n) atau angka (1-n * n) yang mengindikasikan langkah terbaik berikutnya.
    • Selain itu, Anda harus dapat mengidentifikasi kapan skenario kasus terbaik adalah kekalahan atau seri alih-alih menang.
    • Cara Anda menyatakan kehilangan atau dasi adalah, sekali lagi, terserah Anda.
  • Input harus menggunakan X dan O tradisional, dan Anda harus menganggap X bergerak terlebih dahulu; ruang kosong dapat diwakili oleh apa pun.
  • Anda dapat mengasumsikan input apa pun yang masuk ke program Anda memiliki nO dan n + 1 X, dengan kata lain Anda mungkin menganggap Anda mendapatkan papan yang dibentuk dengan baik.
  • Keadaan dewan saat ini harus menjadi satu-satunya input untuk program Anda, jika Anda menggunakan rekursi, metode pembantu harus dibuat untuk memfasilitasi persyaratan input. Lihat /codegolf//a/92851/59376 untuk klarifikasi.
  • Nilai 10> = n> = 1 harus didukung; jika program Anda "time out" untuk n> 10, saya menemukan ini dapat diterima juga, karena beberapa bahasa memiliki kekuatan pemrosesan yang jauh lebih rendah (Terutama menggunakan konsol yang menghadap web).

Menilai

  • Ini adalah kode-golf, sehingga byte-count terendah dari program menang dan celah standar tidak diizinkan secara universal.
  • Dalam kasus seri, program yang mendukung 'n' terbesar akan menang.

Contoh Input

2x2

[[X,O]
 [-,-]]

Output: 2 atau [0,1] (3 atau [1,1] juga bisa dibilang benar) (Beberapa bentuk indikasi lokasi, sewenang-wenang selama Anda dapat dengan mudah menjelaskan format yang Anda gunakan)


3x3

[[X,O,X]
 [O,X,-]
 [-,-,-]]

Output: -1 (Kerugian)


Sekali lagi format input apa pun yang Anda inginkan diizinkan, tetapi X dan O harus digunakan, contoh yang diberikan tidak dimaksudkan untuk membatasi format itu, hanya untuk menginspirasi.

Guci Gurita Ajaib
sumber
Maaf DJMCMayhem, saya sebenarnya mencoba untuk menandai hal-hal itu tetapi saya tidak bisa, karena saya baru di sini.
Magic Octopus Urn
Bonus juga dihapus, tidak menambahkan apa pun selain kebosanan.
Magic Octopus Mm
Apakah format output berikut diperbolehkan: diagram posisi papan dengan masing-masing ruang kosong pada awalnya menunjukkan karakter unik yang menunjukkan jika bermain di sana mengarah ke win / loss / draw (mis. W, L dan D)
Ton Hospel
1
Dalam contoh 3x3, O harus kehilangan apa pun yang ia mainkan, tetapi Anda mengatakan output harus [2,1], mengapa begitu?
Dada
Diedit, tangkapan yang bagus. Tidak tahu apa yang saya pikirkan, itu adalah contoh negatif.
Magic Octopus Urn

Jawaban:

8

Perl, 101 98 byte

Termasuk +4untuk-0p

Jalankan dengan input pada STDIN

tictactoe.pl
OXO
---
--X
^D

Output adalah diagram yang sama, tetapi dengan setiap gerakan diperbarui dengan statusnya, 1mewakili menang, 2mewakili imbang dan 3mewakili kerugian. Untuk kasus ini

OXO
223
21X

jadi 3 gerakan imbang, 1 menang dan 1 kalah (saya akan memperbarui solusi jika format output ini tidak dapat diterima, tetapi kode dasarnya akan tetap sama)

tictactoe.pl:

#!/usr/bin/perl -0p
m%@{[map"O.{$_}"x"@-"."O|",1-/.(
)(.)/,@-]}Z%sx||s%-%$_="$`X$'";y/XO/OX/;do$0%eg?/1/?3:1+/2/:2

Ini sudah sangat lambat dan menggunakan banyak memori untuk papan kosong 3 * 3 (mengapa sebenarnya, rekursi tidak terlalu dalam. Pasti ada kebocoran memori). Menambahkan biaya memo 6 byte tetapi jauh lebih waras:

#!/usr/bin/perl -0p
$$_||=m%@{[map"O.{$_}"x"@-"."O|",1-/.(\n)(.)/,@-]}Z%sx||s%-%$_="$`X$'";y/XO/OX/;do$0%eg?/1/?3:1+/2/:2
Ton Hospel
sumber
Wow, melihat bahwa itu pl dan kemungkinan akan benar-benar tidak berjalan selama n = 10 dengan banyak kosong ... Anda melakukan kedua hal yang saya berharap untuk melihat seseorang melakukannya. Input string dan memetakan hasil untuk semua gerakan, bukan hanya yang terbaik. Bravo.
Magic Octopus Urn
Jika salah satu fungsi rekursif 'bocor' bagaimana bisa ok ??? Bahasa yang terlalu tinggi membuat tidak melihat register 32 bit di CPU (atau sesuatu seperti itu instruksi sederhana)
RosLuP
@RosLup Kebocoran dalam konteks ini tidak berarti kehilangan memori yang tidak terjangkau. Perl agak aneh ketika melepaskan memori, cukup sering melakukan ini lebih lambat dari yang Anda harapkan dan menggunakan lebih banyak memori daripada yang Anda harapkan. Ini juga cenderung mengalokasikan lebih dari yang dibutuhkan secara langsung dengan harapan bahwa Anda akan menumbuhkan struktur data Anda. Dalam hal ini menggunakan rekursi "normal" dengan fungsi alih-alih penyalahgunaan do$0akan menggunakan memori 10 kali lebih sedikit. Pikiran Anda, kasus ini sangat ekstrim itu mungkin sebenarnya kebocoran memori nyata.
Ton Hospel
Tidak hanya satu yang tidak melihat register atau instruksi dasar (dari instruksi hlls) tetapi kehilangan kontrol penggunaan memori ... Bagi saya mereka tidak skala ...
RosLuP
Sudah cukup lama, Anda memenangkan pria saya, sedih kami tidak mendapatkan lebih banyak upaya.
Magic Gurita Guci
2

Javascript (ES6), 320 294 byte

(b,p,d,M,S=-2)=>(T=(p,q,r,s)=>b[p][q]==(n=b[r][s|0])&&n!='-',w=0,b.map((r,y)=>(l=r.length-1,m=15,r.map((c,x)=>(m&=8*T(l-x,x,l)+4*T(x,x,0)+2*T(x,y,0,y)+T(y,x,y))),w|=m)),w?-1:(b.map((r,y)=>r.map((c,x)=>S<1&&c=='-'&&(r[x]='O.X'[p+1],(s=-f(b,-p,1))>S&&(S=s,M=[x,y]),r[x]=c))),S=S+2?S:0,d?S:[M,S]))

Memasukkan

1) Array array karakter yang menggambarkan papan saat ini, seperti:

[['X', '-'], ['-', 'O']]

2) Integer yang menggambarkan giliran saat ini: 1 = X, -1 =O

Keluaran

Array terbuat dari:

  • sebuah array yang menggambarkan langkah terbaik dalam [x, y]format
  • hasil pertandingan sebagai bilangan bulat: 1 = menang, -1 = kalah, 0 = seri

Contoh

Dalam contoh berikut, Xdijamin menang dengan bermain [1, 2].

let f =
(b,p,d,M,S=-2)=>(T=(p,q,r,s)=>b[p][q]==(n=b[r][s|0])&&n!='-',w=0,b.map((r,y)=>(l=r.length-1,m=15,r.map((c,x)=>(m&=8*T(l-x,x,l)+4*T(x,x,0)+2*T(x,y,0,y)+T(y,x,y))),w|=m)),w?-1:(b.map((r,y)=>r.map((c,x)=>S<1&&c=='-'&&(r[x]='O.X'[p+1],(s=-f(b,-p,1))>S&&(S=s,M=[x,y]),r[x]=c))),S=S+2?S:0,d?S:[M,S]))

console.log(JSON.stringify(f(
  [['O','X','O'],
   ['-','-','-'],
   ['-','-','X']],
  1
)));

PERMAINAN ANEH. PINDAH SATU-SATUNYA PEMENANG YANG TIDAK BERMAIN.
BAGAIMANA TENTANG GAME OF CHESS BAGUS?

Arnauld
sumber
Bagus, entri pertama bagus. Hanya komentar yang saya miliki yang berpotensi untuk menyimpan byte dengan informasi yang diberikan 'X akan selalu bergerak lebih dulu'. Dan apakah Anda sudah mencoba dengan papan non 3x3;)?
Magic Octopus Urn
@carusocomputing - Tidak yakin untuk memahami apa yang ada dalam pikiran Anda dengan 'X akan selalu bergerak dulu'. Ini dapat digunakan untuk menyimpulkan sisi mana yang bergerak mengingat papan saja, tetapi komputasi yang sebenarnya akan membutuhkan lebih banyak byte; jadi saya kira Anda sedang berbicara tentang sesuatu yang lain. Jawab ya, saya melakukan beberapa tes dengan papan yang sedikit lebih besar. Itu seharusnya berfungsi seperti yang diharapkan selama ... err ... tidak ada terlalu banyak posisi kosong. :-)
Arnauld
Tantangannya mengatakan The current state of the board must be the only input to your program. Kode Anda membutuhkan dua input, yang melanggar aturan ini.
Dada
1
@Dada - Saya bertanya-tanya tentang hal itu, tetapi saya berasumsi warna aktif adalah bagian dari keadaan papan (seperti posisi catur selalu datang dengan warna aktif + en passant square + ketersediaan castling). Jadi saya kira OP harus menjelaskan hal itu. (Dan jika Anda benar, itu terdengar seperti kesulitan tambahan yang tidak perlu, IMHO.)
Arnauld
1
Mmm .. saya sangat suka penjelasan board state dalam jawabannya. Berpikir tentang itu, beberapa lanagues hanya dapat menggunakan string sebagai input, memiliki papan seperti XXOOXO-OO akan sulit untuk diuraikan dalam jumlah byte yang rendah tanpa informasi tambahan seperti dimensi papan. Saya akan memperbolehkan input tambahan yang berkontribusi pada status dewan, meskipun saya masih berpikir informasi 'menganggap X bergerak lebih dulu' berbeda dari 'mengingat siapa yang mengubahnya'. Beberapa bahasa akan memanfaatkannya sebagai asumsi;).
Magic Gurita Guci