Dagaz: Episode (Bagian 1)

Kami mengguncang filter mental Anda, dan hasilnya adalah jawaban. Metode ini berhasil, akan selalu efektif. Semua yang perlu dilakukan adalah menyingkirkan beban tambahan dari prasangka ...

Raymond Jones " Tingkat Kebisingan "

Dagaz tidak muncul dari awal. Saya selalu menyukai permainan papan dan teka-teki, dan saya melakukan pemrograman sebanyak yang saya bisa ingat, tetapi pikiran tentang mesin "universal" tertentu tidak mungkin terlintas dalam pikiran saya. Saya skeptis dengan ide ini. Sampai aku melihat Zillions . Sayangnya, produk itu, pada waktu itu, tidak lagi berkembang, kode sumbernya tidak tersedia, dan memang, program hanya bekerja di bawah Windows. Setelah beberapa waktu, saya memutuskan untuk mengambil proyek terbuka.

Seperti yang sudah saya katakan, saya tidak punya kode sumber, tapi saya sedikit menyentuh Zillions dan saya menangkap ide utamanya - penggunaan kembali maksimum kode aplikasi, yang memungkinkan menggunakan konstruksi yang sama di berbeda, yang akan tampak sangat berbeda satu sama lain kasus. Itu semua tentang penggunaan yang benar. Dan saya membuat rencana .

Catur


Keluarga permainan yang penting namun sangat diremehkan ini meletakkan batu fondasi untuk proyek tersebut. Semua game "catur" mirip satu sama lain dan hanya berbeda dalam detailnya. Dalam hal desain game, mereka semua disatukan oleh tiga ide utama:

  • Dengan cek
  • Ambil Prioritas
  • Langkah majemuk

Paragraf pertama tidak menimbulkan pertanyaan khusus, tetapi jika pengembangannya difokuskan pada permainan catur, mungkin akan mengejutkan. Tidak di semua game, penangkapan terjadi di bidang yang sama di mana bagian menyelesaikan langkah. Dengan langkah prioritas, segalanya menjadi sedikit lebih menarik. Pada catur, aturan ini memungkinkan Anda untuk membangun permainan kombinasional yang kompleks, memikat musuh ke dalam perangkap yang beroperasi dengan prinsip "berikan lebih sedikit - ambil lebih banyak."


Tentu saja, mekanisme gerakan prioritas diimplementasikan di Zillions (dan bermigrasi dari sana ke Dagaz). Tanpa itu, hampir semua gim catur (tentu saja termasuk dalam gim papan pria yang wajib untuk implementasi) tidak bisa berfungsi dengan benar. Semuanya tentang detail. Mari kita lihat bagaimana mekanisme ini diterapkan:

Dalam zillions
(move-priorities jump-type normal-type) ... (define checker-shift ( $1 (verify empty?) ;        add ;   )) (define checker-jump ( $1 (verify enemy?) ;         capture ;   ( capture  -   ) $1 (verify empty?) ;           add ;   )) ... (piece (name Man) (image White "images/stapeldammen/white.bmp" Red "images/stapeldammen/red.bmp") (moves (move-type jump-type) (checker-jump nw) (checker-jump ne) (checker-jump sw) (checker-jump se) (move-type normal-type) (checker-shift nw) (checker-shift ne) ) ) 

Ini adalah deskripsi yang hampir lengkap dari game checker paling sederhana. Konsep mode pemindahan ( tipe bergerak ) diperkenalkan di ZRF , dan konstruksi prioritas pemindahan memungkinkan kita untuk mengatakan bahwa jika ada pemindahan dengan prioritas (pengambilan) yang lebih tinggi, prioritas yang lebih rendah ( pemindahan yang tenang) tidak boleh dipertimbangkan. Level prioritas dapat didefinisikan dan lebih dari dua, dalam hal ini, desainnya cukup universal, tetapi bekerja pada game di Dagaz, saya menemukan beberapa keterbatasan mekanisme ini.


Dalam permainan ini, diciptakan oleh Solomon Golomb, selain catur, ada juga bidak catur. Kesulitannya terletak pada kenyataan bahwa mengambil, sementara tetap menjadi prioritas bagi catur, tidak seperti pada bidak catur (jika tidak akan terlalu mudah untuk menjebak dan memakannya). Prioritas naif menggunakan prioritas kata kunci bergerak tidak akan berfungsi dalam game ini.

Faktanya, jika bidak catur tidak termasuk dalam gerakan prioritas, jika ada kemungkinan mengambil bidak catur dan bidak catur, kita tidak akan dapat memainkan bidak catur, karena tangkapan catur merupakan prioritas. Jika gerakan catur dianggap sebagai prioritas yang sama, kami akan diwajibkan untuk mengambil bidak catur setiap kali ada kesempatan. Kedua hal ini bertentangan dengan aturan main.

Dalam Zillions, masalah ini praktis tidak terpecahkan. Dan itulah alasan utama saya berpikir untuk memperkenalkan mekanisme ekstensi JavaScript ke Dagaz. Idenya, dalam dirinya sendiri, cukup sederhana: karena beberapa mekanik permainan agak sulit untuk diekspresikan dalam ZRF, mengapa tidak memperkenalkan fase pasca-pemrosesan gerakan? Modul ekstensi, dalam hal ini, memindai seluruh daftar gerakan yang dihasilkan secara keseluruhan dan dapat membuat keputusan untuk menolak gerakan tertentu. Inilah yang terlihat untuk Shashmat :

Kode sederhana dan kompak
 var CheckInvariants = Dagaz.Model.CheckInvariants; Dagaz.Model.CheckInvariants = function(board) { var design = Dagaz.Model.design; var types = []; types.push(design.getPieceType("Bishop")); types.push(design.getPieceType("Camel")); var isPriority = false; _.each(board.moves, function(move) { if (isCapturing(board, move)) { if (_.indexOf(types, getType(board, move)) < 0) isPriority = true; } }); if (isPriority) { _.each(board.moves, function(move) { if (!isCapturing(board, move)) { move.failed = true; } }); } CheckInvariants(board); } 

Di masa depan, gagasan ekstensi dikembangkan dan berkembang dengan warna yang luar biasa. Saya mendapatkan mekanisme yang nyaman dan kuat untuk mengkodekan banyak game yang penerapannya pada ZRF murni akan sangat bermasalah, tetapi apakah ini berarti bahwa penentuan prioritas dalam gaya ZRF sudah usang? Tentu tidak! Pertama, menulis satu baris dalam ZRF lebih mudah daripada lima puluh dalam JavaScript, tetapi yang lebih penting, "keras" prioritas gaya ZRF bekerja sedemikian rupa sehingga gerakan prioritas rendah bahkan tidak dihasilkan! Ini penting dalam hal kinerja. Menghasilkan gerakan di Dagaz adalah operasi yang sangat mahal.

Game lain dengan prioritas yang menantang

Dablot adalah gim yang agak mirip dengan Draft Italia , tetapi lebih kuno. Selain tokoh biasa, ada "pangeran" dan "raja" di dalamnya, dan tokoh yang lebih muda tidak memiliki hak untuk mengalahkan sesepuh. Tetapi itu bukan kesulitannya. Untuk raja-raja (dan dalam beberapa jenis gim untuk pangeran juga), menangkap adalah opsional! Di sini masalah yang sama muncul dengan Shashmat . Jika kita menyatakan raja sebagai prioritas, kita akan melanggar aturan permainan, jika tidak, kita tidak akan bisa mengalahkan raja dengan kemungkinan pertempuran alternatif dengan figur sederhana. Hanya mesin ekstensi Dagaz yang menyelesaikan masalah ini.

Omong-omong, dengan "Draft Italia" semuanya tidak begitu sederhana. Dalam banyak variasi draft ada aturan yang menyatakan bahwa pemain berkewajiban untuk mengambil jumlah potongan maksimum. Artinya, dia tidak bisa hanya mengganggu rantai tangkapan, tetapi harus memilih jalan yang akan diambilnya lebih banyak! Untuk alasan yang akan saya bahas di bawah ini, aturan ini tidak dapat diimplementasikan dalam Zillions dalam bentuk universal dan pengembang dipaksa untuk meng-hardcode-nya. Dalam konsep Italia, "aturan mayoritas" terdengar lebih rumit: "Anda harus mengalahkan jumlah maksimum draft lawan, dan dengan opsi pertempuran yang sama Anda harus mengalahkan jumlah maksimum dames."

Gerakan majemuk adalah komponen penting kedua dari permainan catur. Begitu pentingnya sehingga tes untuk menangkap yang benar dalam " Draft Turki " secara berkala saya jalankan sampai sekarang. Beberapa kali ketika saya memecahkan model dengan perubahan berikutnya, itu sangat membantu.

Bergerak - komposit dan parsial
Mari kita lihat bagaimana gerakan komposit diimplementasikan dalam ZRF
 (define checker-shift ( $1 (verify empty?) (if (in-zone? promotion) (add King) else add ) )) (define checker-jump ( $1 (verify enemy?) capture $1 (verify empty?) (if (in-zone? promotion) (add King) else (add-partial jump-type) ) )) (define king-shift ( $1 (verify empty?) add )) (define king-jump ( $1 (verify enemy?) capture $1 (verify empty?) (add-partial jump-type) )) 

Ini sesederhana itu. Perintah add-partial mengatakan bahwa langkah itu dapat dilanjutkan (dengan bagian yang sama, ini penting) jika masih ada gerakan dengan mode yang ditentukan. Dengan kata lain: "sosok itu harus terus mengambil, sementara ada peluang seperti itu." Segalanya tampak baik-baik saja, tetapi ada satu peringatan. Zillions melihat masing-masing mengambil sebagai langkah "parsial" yang terpisah. Mari kita lihat apa yang dapat menyebabkan hal ini.


Dalam gim ini, jumlah "langkah" yang dilakukan oleh sepotong ditentukan oleh ikon yang berdiri. Sekarang White bergerak dan Damyo berjalan (sepotong yang ditandai dengan manik merah). Di Zillions, setelah menyelesaikan dua gerakan parsial, ia dapat dengan mudah pergi ke sudut kiri atas, dari mana ia tidak lagi dapat membuat langkah terakhir yang tersisa (Anda tidak dapat kembali). Mengambil bagian lawan dalam gerakan parsial kedua juga dilarang. Dalam Zillions tidak ada cara untuk melarang urutan langkah yang mengarah ke jalan buntu.

Di Dagaz, berbeda! Urutan gerakan parsial selalu dirakit menjadi gerakan komposit penuh. Sebuah langkah yang tidak dapat diselesaikan sama sekali tidak akan terjadi! Ini adalah pendekatan yang lebih intensif sumber daya, dan sebagai hasilnya, membuat daftar langkah di Dagaz adalah operasi yang sangat mahal. Tetapi keunggulannya signifikan. Sebagai contoh, bot menerima seluruh gerakan senyawa secara keseluruhan dan tidak boleh melihat ke depan, melakukan gerakan parsial yang tersisa.

Yang lebih penting, pendekatan ini memberikan kesempatan untuk mempertimbangkan seluruh daftar gerakan yang dapat diterima secara kondisional, melakukan pemeriksaan yang lebih kompleks dan melarang beberapa gerakan tergantung pada kehadiran orang lain. Misalnya, "aturan mayoritas", yang saya sebutkan di atas, di Dagaz diimplementasikan dengan cukup sederhana . Selain itu, untuk "Checkers Italia" juga. Para pengembang Zillions "memecahkan" masalah yang mereka tahu untuk permainan catur dengan melakukan hardcoding pada opsi " tangkapan maksimal ", tetapi ada sejumlah besar permainan dengan pemeriksaan rumit lainnya, yang pada waktu itu, mereka tidak tahu!

Dalam proses mengerjakan game baru, konsep gerakan majemuk juga telah dikembangkan. Fanorona dan Pasang menyarankan mekanik permainan yang menarik, di mana sekelompok potongan yang dihapus dari papan harus dipilih oleh pemain yang melakukan gerakan:


Juga, Fanorona adalah salah satu permainan langka di mana seorang pemain memiliki hak untuk mengganggu rantai tangkapan. Penangkapan pertama di dalamnya adalah wajib, yang berikutnya, dalam gerakan yang sama - atas kebijakan pemain. Di Dagaz, opsi ini ( sebagian-parsial ) diimplementasikan dengan memindahkan gambar di tempatnya. Missclick dapat berada di sini, dan ini, tampaknya, tidak terlalu nyaman, tetapi dengan diperkenalkannya manajer sesi di proyek, menjadi mungkin untuk memutar kembali gerakan yang salah.

Perkembangan topik selanjutnya adalah gerakan "menembak". Saya pertama kali membuatnya di Hanga Roa dan Ko Shogi , tetapi ternyata kemudian, saya salah! Implementasi yang keliru tidak bekerja di bawah kendali bot (dan karena saya masih tidak punya bot untuk kedua game ini, tidak mengherankan bahwa saya tidak melihat apa-apa). Jauh kemudian, ketika saya melakukan Amazon , saya berhasil melokalisasi masalah dan memperbaikinya. Gagasan ini mencapai puncaknya dalam permainan yang ditemukan oleh salah satu rekan kami di tahun 1957.


Ada masalah lain terkait dengan penerapan gerakan komposit di Dagaz. Faktanya adalah bahwa daftar gerakan yang diizinkan, dari kondisi permainan tertentu, dibentuk segera - semuanya. Di Zillions, dengan gerakan parsialnya, ini tidak terlalu kritis, tetapi di Dagaz, jika bagian tersebut mendapat kesempatan untuk "berputar di tempat", fase generasi gerakan tidak akan pernah selesai (jelas bahwa tidak mungkin untuk memperbaiki masalah ini dengan ekstensi, karena mudah untuk mengatasinya tidak mencapai). Ini adalah salah satu permainan yang penting:


Di sini potongan-potongan tidak dihapus dari papan dan potongan yang sama dapat dilompati berkali-kali berturut-turut. Solusi yang jelas adalah untuk melarang mengunjungi bidang yang sama dua kali per giliran, tetapi saya harus masuk ke kernel untuk mengimplementasikan pemeriksaan tersebut. Ini sedikit seperti penerapan opsi " penangkapan yang ditangguhkan ", tetapi karena saya melakukan draft Rusia jauh sebelumnya, ada sedikit masalah dengan itu.

Sayangnya, ada permainan di mana bahkan cek semacam itu tidak disimpan
Aturan Stapeldammen (ini adalah semacam " Pilar " secara eksplisit menyatakan bahwa bagian yang sama dapat dipukul beberapa kali per giliran. Bagian yang melakukan gerakan kembali ke posisi yang sama beberapa kali dan melanjutkan pertempuran, sementara di musuh ada angka di kolom .. Gerakan majemuk Dagaz tidak dapat mengatasi masalah ini. Logika pertempuran Kutub terlalu rumit untuk kernel, dan itu tidak akan mencapai ekstensi, karena generasi loop dilingkarkan. Tentu saja, ada jalan keluar:


Tidak ada gerakan parsial di Dagaz, tetapi kita dapat meniru mereka dengan melewatkan langkah selanjutnya oleh lawan (pendekatan yang sama digunakan dalam decals ). Dan logika ini mudah diimplementasikan oleh ekstensi . Kami hanya melarang semua gerakan dalam kondisi tertentu, dan opsi pass-turn = terpaksa secara otomatis menghasilkan gerakan kosong. Ini adalah game lain dengan emulasi serupa.


Membagi perpindahan komposit secara artifisial menjadi sebagian tidak baik untuk bot AI, tetapi kadang-kadang, tidak ada jalan keluar lain.

Secara umum, konsep senyawa menggerakkan kehidupan dan berkembang. Baru-baru ini, saya harus membuat pilihan baru lain ( lengkap parsial ) untuk satu pertandingan Mesir kuno.


Selain secara otomatis menyelesaikan pergerakan angka di sepanjang panah, ia juga memiliki solusi teknis menarik lainnya. Tetapi tentang ini lain waktu.

Source: https://habr.com/ru/post/id459456/


All Articles