Saya telah menulis permainan tic-tac-toe di Java, dan metode saya saat ini untuk menentukan akhir dari permainan memperhitungkan skenario yang mungkin berikut untuk permainan yang akan berakhir:
- Papan penuh, dan belum ada pemenang yang diumumkan: Pertandingan seri.
- Cross menang.
- Circle menang.
Sayangnya, untuk melakukannya, ia membaca sekumpulan skenario yang telah ditentukan sebelumnya dari tabel. Ini tidak selalu buruk mengingat hanya ada 9 ruang di papan, dan dengan demikian tabelnya agak kecil, tetapi adakah cara algoritmik yang lebih baik untuk menentukan apakah permainan sudah berakhir? Penentuan apakah seseorang menang atau tidak adalah inti masalahnya, karena memeriksa apakah 9 ruang penuh itu sepele.
Metode tabel mungkin bisa menjadi solusinya, tetapi jika tidak, apa? Juga, bagaimana jika papannya tidak berukuran n=9
? Bagaimana jika yang papan yang jauh lebih besar, katakanlah n=16
, n=25
, dan sebagainya, menyebabkan jumlah item berturut-turut ditempatkan untuk menang menjadi x=4
, x=5
, dll? Algoritme umum yang digunakan untuk semua n = { 9, 16, 25, 36 ... }
?
sumber
3
). Jadi, Anda dapat melacak hitungan masing-masing, dan hanya mulai memeriksa kemenangan jika jumlahnya lebih tinggi.Jawaban:
Anda tahu langkah menang hanya dapat terjadi setelah X atau O melakukan langkah terbaru mereka, jadi Anda hanya dapat mencari baris / kolom dengan diag opsional yang terdapat dalam gerakan itu untuk membatasi ruang pencarian Anda saat mencoba menentukan papan pemenang. Juga karena ada sejumlah gerakan tetap dalam permainan seri tic-tac-toe setelah langkah terakhir dilakukan jika itu bukan langkah kemenangan, itu secara default adalah permainan seri.
sunting: kode ini adalah untuk papan n kali n dengan n berturut-turut untuk menang (papan 3x3 persyaratan 3 berturut-turut, dll)
edit: menambahkan kode untuk memeriksa anti diag, saya tidak dapat menemukan cara non loop untuk menentukan apakah intinya ada di anti diag jadi itulah mengapa langkah itu hilang
sumber
Anda dapat menggunakan kotak ajaib http://mathworld.wolfram.com/MagicSquare.html jika ada baris, kolom, atau diag yang berjumlah 15 maka pemain telah menang.
sumber
Bagaimana dengan pseudocode ini:
Setelah pemain meletakkan bidak pada posisi (x, y):
Saya akan menggunakan array char [n, n], dengan O, X dan spasi untuk kosong.
sumber
i==1
dann==3
,rdiag
harus diperiksa pada(1, 3)
dan(1, 3-1+1)
sama dengan koordinat yang benar, tetapi(1, 3-(1+1))
tidak.Ini mirip dengan jawaban Osama ALASSIRY , tetapi ia memperdagangkan ruang-konstan dan waktu-linier untuk ruang-linier dan waktu-konstan. Artinya, tidak ada perulangan setelah inisialisasi.
Inisialisasi pasangan
(0,0)
untuk setiap baris, setiap kolom, dan dua diagonal (diagonal & anti-diagonal). Pasangan-pasangan ini mewakili akumulasi(sum,sum)
potongan di baris, kolom, atau diagonal yang sesuai, di manaKetika seorang pemain menempatkan bidak, perbarui pasangan baris yang sesuai, pasangan kolom, dan pasangan diagonal (jika di diagonal). Jika ada pasangan baris, kolom, atau diagonal yang baru diperbarui sama dengan salah satu
(n,0)
atau(0,n)
kemudian A atau B menang.Analisis asimtotik:
Untuk penggunaan memori, Anda menggunakan
4*(n+1)
bilangan bulat.Latihan: Dapatkah Anda melihat cara menguji hasil imbang dalam O (1) kali per gerakan? Jika demikian, Anda bisa mengakhiri permainan lebih awal dengan hasil imbang.
sumber
O(sqrt(n))
waktu tetapi harus dilakukan setelah setiap gerakan, di mana n adalah ukuran papan. Jadi Anda berakhir denganO(n^1.5)
. Untuk solusi ini Anda mendapatkanO(n)
waktu secara keseluruhan.Inilah solusi saya yang saya tulis untuk proyek yang sedang saya kerjakan di javascript. Jika Anda tidak keberatan dengan biaya memori beberapa array, ini mungkin solusi tercepat dan paling sederhana yang akan Anda temukan. Ini mengasumsikan Anda mengetahui posisi langkah terakhir.
sumber
Saya baru saja menulis ini untuk kelas pemrograman C.
Saya mempostingnya karena tidak ada contoh lain di sini yang akan berfungsi dengan kisi persegi panjang ukuran apa pun , dan nomor N -in-a-row yang berurutan untuk menang.
Anda akan menemukan algoritme saya, seperti itu, dalam
checkWinner()
fungsinya. Itu tidak menggunakan angka ajaib atau apa pun yang mewah untuk memeriksa pemenang, itu hanya menggunakan empat untuk loop - Kode dikomentari dengan baik jadi saya akan membiarkannya berbicara sendiri, saya kira.sumber
Jika papannya n × n maka ada n baris, n kolom, dan 2 diagonal. Periksa masing-masing untuk semua-X atau semua-O untuk menemukan pemenang.
Jika hanya membutuhkan x < n kotak berturut-turut untuk menang, maka ini sedikit lebih rumit. Solusi paling jelas adalah memeriksa setiap x × x persegi untuk mencari pemenang. Berikut beberapa kode yang menunjukkan itu.
(Saya tidak benar-benar menguji ini * batuk *, tetapi berhasil dikompilasi pada percobaan pertama, yay me!)
sumber
Saya tidak tahu Java dengan baik, tapi saya tahu C, jadi saya mencoba ide kotak ajaib adk (bersama dengan pembatasan pencarian Hardwareguy ).
Ini mengkompilasi dan menguji dengan baik.
Itu menyenangkan, terima kasih!
Sebenarnya, jika dipikir-pikir, Anda tidak membutuhkan bujur sangkar ajaib, cukup hitungan untuk setiap baris / kolom / diagonal. Ini sedikit lebih mudah daripada menggeneralisasi persegi ajaib menjadi matriks
n
×n
, karena Anda hanya perlu menghitungnyan
.sumber
Saya ditanyai pertanyaan yang sama dalam salah satu wawancara saya. Pikiran saya: Inisialisasi matriks dengan 0. Simpan 3 array 1) sum_row (ukuran n) 2) sum_column (ukuran n) 3) diagonal (ukuran 2)
Untuk setiap gerakan dengan (X) turunkan nilai kotak dengan 1 dan untuk setiap gerakan dengan (0) tambahkan 1. Pada titik mana pun jika baris / kolom / diagonal yang telah dimodifikasi dalam gerakan saat ini berjumlah -3 atau + 3 berarti seseorang telah memenangkan permainan. Untuk menggambar kita bisa menggunakan pendekatan di atas untuk mempertahankan variabel moveCount.
Apakah Anda pikir saya melewatkan sesuatu?
Edit: Sama dapat digunakan untuk matriks nxn. Jumlahnya harus genap +3 atau -3.
sumber
cara non-loop untuk menentukan apakah titik itu ada di anti diag:
sumber
Saya terlambat ke pesta, tetapi saya ingin menunjukkan satu keuntungan yang saya temukan dengan menggunakan kotak ajaib , yaitu dapat digunakan untuk mendapatkan referensi ke kotak yang akan menyebabkan menang atau kalah pada giliran berikutnya, daripada hanya digunakan untuk menghitung saat permainan selesai.
Ambil kotak ajaib ini:
Pertama, siapkan
scores
larik yang bertambah setiap kali perpindahan dilakukan. Lihat jawaban ini untuk detailnya. Sekarang jika kita secara ilegal memainkan X dua kali berturut-turut pada [0,0] dan [0,1], makascores
arraynya akan terlihat seperti ini:Dan papannya terlihat seperti ini:
Kemudian, yang harus kita lakukan untuk mendapatkan referensi ke kotak mana yang akan dimenangkan / diblokir adalah:
Pada kenyataannya, implementasinya membutuhkan beberapa trik tambahan, seperti menangani kunci bernomor (dalam JavaScript), tetapi saya merasa cukup mudah dan menikmati matematika rekreasional.
sumber
Saya membuat beberapa pengoptimalan di baris, kolom, pemeriksaan diagonal. Ini terutama diputuskan dalam loop bersarang pertama jika kita perlu memeriksa kolom atau diagonal tertentu. Jadi, kami menghindari pengecekan kolom atau diagonal untuk menghemat waktu. Ini membuat dampak besar ketika ukuran papan lebih banyak dan sejumlah besar sel tidak terisi.
Berikut adalah kode java untuk itu.
sumber
Saya suka algoritma ini karena menggunakan representasi papan 1x9 vs 3x3.
sumber
Opsi lain: buat tabel Anda dengan kode. Hingga simetri, hanya ada tiga cara untuk menang: baris tepi, baris tengah, atau diagonal. Ambil ketiganya dan putar dengan segala cara yang memungkinkan:
Simetri ini dapat memiliki lebih banyak kegunaan dalam kode permainan-permainan Anda: jika Anda sampai ke papan yang telah Anda lihat versi rotasinya, Anda bisa mengambil nilai yang di-cache atau langkah terbaik yang di-cache dari yang itu (dan membatalkannya kembali). Ini biasanya jauh lebih cepat daripada mengevaluasi subtree game.
(Membalik ke kiri dan kanan dapat membantu dengan cara yang sama; ini tidak diperlukan di sini karena rangkaian rotasi pola kemenangan adalah simetris cermin.)
sumber
Berikut adalah solusi yang saya buat, ini menyimpan simbol sebagai karakter dan menggunakan nilai int char untuk mengetahui apakah X atau O telah menang (lihat kode Wasit)
Juga di sini adalah tes unit saya untuk memvalidasinya benar-benar berfungsi
Solusi lengkap: https://github.com/nashjain/tictactoe/tree/master/java
sumber
Bagaimana dengan pendekatan berikut untuk 9 slot? Deklarasikan 9 variabel integer untuk matriks 3x3 (a1, a2 .... a9) di mana a1, a2, a3 mewakili baris-1 dan a1, a4, a7 akan membentuk kolom-1 (Anda mengerti). Gunakan '1' untuk menunjukkan Player-1 dan '2' untuk menunjukkan Player-2.
Ada 8 kemungkinan kombinasi kemenangan: Menang-1: a1 + a2 + a3 (jawaban bisa 3 atau 6 berdasarkan pemain mana yang menang) Menang-2: a4 + a5 + a6 Menang-3: a7 + a8 + a9 Menang-4 : a1 + a4 + a7 .... Menang-7: a1 + a5 + a9 Menang-8: a3 + a5 + a7
Sekarang kita tahu bahwa jika pemain satu melewati a1 maka kita perlu mengevaluasi kembali jumlah 3 variabel: Menang-1, Menang-4 dan Menang-7. Mana 'Menang-?' variabel mencapai 3 atau 6 pertama memenangkan permainan. Jika variabel Win-1 mencapai 6 terlebih dahulu, maka Player-2 menang.
Saya mengerti bahwa solusi ini tidak dapat diskalakan dengan mudah.
sumber
Ini adalah cara yang sangat sederhana untuk memeriksanya.
}
sumber
Jika Anda memiliki bidang asrama 5 * 5 sebagai contoh, saya menggunakan metode pemeriksaan selanjutnya:
Saya pikir, ini lebih jelas, tetapi mungkin bukan cara yang paling optimal.
sumber
Inilah solusi saya menggunakan array 2 dimensi:
sumber
Solusi waktu konstan, berjalan di O (8).
Simpan status papan sebagai bilangan biner. Bit terkecil (2 ^ 0) adalah baris kiri atas papan. Lalu ke kanan, lalu ke bawah.
YAITU
Setiap pemain memiliki bilangan biner sendiri untuk mewakili keadaan (karena tic-tac-toe) memiliki 3 status (X, O & blank) sehingga satu bilangan biner tidak akan berfungsi untuk mewakili status papan untuk beberapa pemain.
Misalnya, papan seperti:
Perhatikan bahwa bit untuk pemain X terpisah dari bit untuk pemain O, ini jelas karena X tidak dapat meletakkan bidak di mana O memiliki bidak dan sebaliknya.
Untuk memeriksa apakah seorang pemain telah menang, kita perlu membandingkan semua posisi yang dicakup oleh pemain itu dengan posisi yang kita tahu adalah posisi menang. Dalam hal ini, cara termudah untuk melakukannya adalah dengan melakukan AND-gating pada posisi pemain dan posisi menang dan melihat apakah keduanya sama.
misalnya.
Catatan:,
X & W = W
jadi X dalam keadaan menang.Ini adalah solusi waktu yang konstan, ini hanya bergantung pada jumlah posisi-menang, karena menerapkan gerbang-AND adalah operasi waktu yang konstan dan jumlah posisi-menang terbatas.
Ini juga menyederhanakan tugas untuk menghitung semua status papan yang valid, hanya semua angka yang diwakili oleh 9 bit. Tetapi tentu saja Anda memerlukan kondisi tambahan untuk menjamin suatu nomor adalah status papan yang valid (mis.
0b111111111
Adalah nomor 9-bit yang valid, tetapi ini bukan status papan yang valid karena X baru saja mengambil semua giliran).Jumlah kemungkinan posisi menang dapat dihasilkan dengan cepat, tetapi di sinilah tempatnya.
Untuk menghitung semua posisi papan, Anda dapat menjalankan loop berikut. Meskipun saya akan meninggalkan menentukan apakah suatu nomor adalah status papan yang valid hingga orang lain.
CATATAN: (2 ** 9 - 1) = (2 ** 8) + (2 ** 7) + (2 ** 6) + ... (2 ** 1) + (2 ** 0)
sumber
Tidak yakin apakah pendekatan ini belum dipublikasikan. Ini harus bekerja untuk setiap papan m * n dan pemain harus mengisi posisi berturut-turut " winnerPos ". Ide ini didasarkan pada jendela yang sedang berjalan.
sumber
Saya pernah mengembangkan algoritme untuk ini sebagai bagian dari proyek sains.
Anda pada dasarnya membagi papan secara rekursif menjadi sekelompok bagian 2x2 yang tumpang tindih, menguji berbagai kemungkinan kombinasi untuk menang di kotak 2x2.
Ini lambat, tetapi memiliki keuntungan untuk bekerja pada papan ukuran apa pun, dengan persyaratan memori yang cukup linier.
Saya berharap saya dapat menemukan implementasi saya
sumber