
Sekali waktu, orang-orang datang dengan bahasa XML dan melihat bahwa itu bagus. Dan mereka mulai menggunakannya sedapat mungkin, dan bahkan di tempat yang seharusnya tidak. Format untuk penyimpanan dan transfer data, konfigurasi, layanan web, basis data ... Tampaknya terlihat - XML, XML di mana-mana. Waktu berlalu, orang-orang berubah pikiran, menemukan berbagai format data lain (atau menyembunyikan XML di dalam arsip), dan kegilaan XML tampak tenang. Namun sejak itu, hampir semua sistem telah mampu XML dan mengintegrasikan sistem seperti itu (yang mengatakan Apache Camel?) Apakah cara terbaik dan termudah menggunakan dokumen XML.
Di mana XML berada, ada XSLT, bahasa yang dirancang untuk mengubah dokumen XML. Bahasa ini khusus, tetapi memiliki sifat
kelengkapan menurut Turing . Oleh karena itu, bahasa ini cocok untuk penggunaan "tidak normal". Di sini, misalnya, ada
solusi untuk masalah 8 ratu . Jadi, Anda bisa menulis game.
Untuk yang tidak sabar: program kerja pada
JSFiddle , sumber di
GitHub .
Setiap program mengkonversi input ke output. Tiga bagian dapat dibedakan dalam program: preprocessor, prosesor, dan postprocessor. Preprosesor menyiapkan data input untuk diproses lebih lanjut. Prosesor ini terlibat dalam pekerjaan utama konversi data, jika perlu, "mencampur" input pengguna dan sinyal eksternal dan peristiwa, termasuk dalam satu siklus. Postprocessor diperlukan untuk mengubah hasil prosesor menjadi bentuk yang sesuai untuk persepsi manusia (atau oleh program lain).

Dalam kasus permainan interaktif di XSLT, masing-masing dari tiga bagian program akan menjadi file XSLT yang terpisah. Pra-prosesor akan menyiapkan lapangan bermain. Prosesor akan menerapkan langkah pemain manusia, membuat langkah pemain komputer dan menentukan pemenang. Postprocessor akan membuat keadaan permainan.
Program XSLT membutuhkan runtime. Runtime paling umum yang mampu mengeksekusi XSLT adalah
browser modern . Kami akan menggunakan XSLT versi 1.0, karena didukung oleh browser di luar kotak.
Sedikit tentang XSLT dan XPath
XSLT adalah bahasa transformasi dokumen XML; XPath digunakan untuk mengakses bagian-bagian dari dokumen XML. Spesifikasi untuk bahasa-bahasa ini diterbitkan di w3.org:
XSLT Versi 1.0 dan
XPath Versi 1.0 .
Dasar-dasar dan contoh penggunaan XSLT dan XPath mudah dicari di internet. Di sini saya menarik perhatian pada fitur-fitur yang perlu dipertimbangkan ketika mencoba menggunakan XSLT sebagai bahasa pemrograman tingkat tinggi tujuan umum "normal".
XSLT memiliki fungsi bernama. Mereka dinyatakan sebagai elemen.
<xsl:template name="function_name"/>
dan disebut dengan cara ini:
<xsl:call-template name="function_name"/>
Fungsi mungkin memiliki parameter.
Pengumuman:
<xsl:template name="add"> <xsl:param name="x"/> <xsl:param name="y"/> <xsl:value-of select="$x + $y"/> </xsl:template>
Panggilan fungsi dengan parameter:
<xsl:call-template name="add"> <xsl:with-param name="x" select="1"/> <xsl:with-param name="y" select="2"/> </xsl:call-template>
Parameter dapat memiliki nilai default.
Parameter bisa "global" yang datang dari luar. Dengan menggunakan parameter ini, input pengguna akan ditransfer ke program.
Bahasa ini juga memungkinkan Anda untuk mendeklarasikan variabel yang mungkin terkait dengan suatu nilai. Parameter dan variabel tidak dapat diubah dan nilai dapat ditetapkan satu kali (seperti di Erlang, misalnya).
XPath mendefinisikan empat tipe data dasar: string, angka, boolean, dan node-set. XSLT menambahkan tipe kelima - fragmen pohon hasil. Fragmen ini terlihat seperti simpul-set, tetapi dengan itu Anda dapat melakukan serangkaian operasi terbatas. Itu dapat disalin seluruhnya ke dokumen output XML, tetapi Anda tidak dapat mengakses node anak.
<xsl:variable name="board"> <cell>1</cell> <cell>2</cell> <cell>3</cell> <cell>4</cell> </xsl:variable>
Variabel board berisi fragmen dokumen XML. Tetapi node anak tidak dapat diakses. Kode ini tidak valid:
<xsl:for-each select="$board/cell"/>
Yang terbaik yang bisa Anda dapatkan adalah akses ke node teks dari fragmen dan bekerja dengannya sebagai string:
<xsl:value-of select="substring(string($board), 2, 1)"/>
akan mengembalikan "2".
Karena itu, dalam permainan kami, papan (atau lapangan bermain) akan disajikan sebagai string sehingga dapat dimanipulasi secara sewenang-wenang.
XSLT memungkinkan Anda untuk mengulang set node menggunakan xsl: untuk-masing konstruk. Tetapi bahasa tidak memiliki yang biasa untuk atau sementara loop. Sebagai gantinya, Anda dapat menggunakan pemanggilan fungsi rekursif (iterasi dan rekursi bersifat isomorfik). Lingkaran formulir untuk x dalam a..b akan diatur seperti ini:
<xsl:call-template name="for_loop"> <xsl:with-param name="x" select="$a"/> <xsl:with-param name="to" select="$b"/> </xsl:call-template> <xsl:template name="for_loop"> <xsl:param name="x"/> <xsl:param name="to"/> <xsl:if test="$x < $to"> <xsl:call-template name="for_loop"> <xsl:with-param name="x" select="$x + 1"/> <xsl:with-param name="to" select="$to"/> </xsl:call-template> </xsl:if> </xsl:template>
Menulis runtime
Agar program dapat berfungsi, Anda perlu: 3 XSLT, XML sumber, input pengguna (parameter), XML keadaan internal, dan XML keluaran.
Kami menempatkan bidang teks dengan pengidentifikasi dalam
file-html : "preprocessor-xslt", "processor-xslt", "postprocessor-xslt", "input-xml", "parameter", "output-xml", "postprocessed-xml". Kami juga menempatkan / menyematkan hasil di halaman (untuk visualisasi).
Tambahkan dua tombol: inisialisasi dan panggilan (langkah) prosesor.
Mari kita menulis beberapa kode JavaScript.
Fitur utama adalah penggunaan transformasi XSLT. function transform(xslt, xml, params) { var processor = new XSLTProcessor(); var parser = new DOMParser(); var xsltDom = parser.parseFromString(xslt, "application/xml");
Fungsi untuk menjalankan preprosesor, prosesor, dan pascaprosesor: function doPreprocessing() { var xslt = document.getElementById("preprocessor-xslt").value; var xml = document.getElementById("input-xml").value; var result = transform(xslt, xml); document.getElementById("output-xml").value = result; } function doProcessing() { var params = parseParams(document.getElementById("parameters").value); var xslt = document.getElementById("processor-xslt").value; var xml = document.getElementById("output-xml").value; var result = transform(xslt, xml, params); document.getElementById("output-xml").value = result; } function doPostprocessing() { var xslt = document.getElementById("postprocessor-xslt").value; var xml = document.getElementById("output-xml").value; var result = transform(xslt, xml); document.getElementById("postprocessed-xml").value = result; document.getElementById("output").innerHTML = result; }
Fungsi helper parseParams () mem-parsing input pengguna ke key = pasangan nilai.
Tombol inisialisasi memanggil function onInit() { doPreprocessing(); doPostprocessing(); }
Tombol mulai prosesor function onStep() { doProcessing(); doPostprocessing(); }
Runtime dasar sudah siap.
Bagaimana cara menggunakannya. Masukkan tiga dokumen XSLT ke bidang yang sesuai. Masukkan dokumen input XML. Tekan tombol "Init". Jika perlu, masukkan nilai yang diperlukan di bidang parameter. Klik tombol Langkah.
Menulis game
Jika orang lain tidak menebak, permainan interaktif dari judul adalah klasik 3 oleh 3 tic-tac-toe.
Lapangan bermain adalah tabel 3 dengan 3, sel-selnya diberi nomor dari 1 hingga 9.
Pemain manusia selalu melintasi (simbol "X"), komputer - nol ("O"). Jika sel ditempati oleh tanda silang atau nol, digit yang sesuai diganti dengan simbol "X" atau "O".
Kondisi permainan terkandung dalam dokumen XML dari formulir ini:
<game> <board>123456789</board> <state></state> <beginner></beginner> <message></message> </game>
Elemen <board /> berisi bidang bermain; <state /> - status permainan (memenangkan salah satu pemain atau imbang atau kesalahan); elemen <beginner /> digunakan untuk menentukan siapa yang memulai gim saat ini (sehingga pemain lain memulai gim berikutnya); <message /> - pesan untuk pemain.
Preprocessor menghasilkan keadaan awal (bidang kosong) dari dokumen XML sewenang-wenang.
Prosesor memvalidasi input pengguna, menerapkan gerakannya, menghitung keadaan permainan, menghitung dan menerapkan gerakan komputer.
Pada kode pseudo, tampilannya seperti ini fn do_move() { let board_after_human_move = apply_move(board, "X", param) let state_after_human_move = get_board_state(board_after_human_move) if state_after_human_move = "" { let board_after_computer_move = make_computer_move(board_after_human_move) let state_after_computer_move = get_board_state(board_after_computer_move) return (board_after_computer_move, state_after_computer_move) } else { return (board_after_human_move, state_after_human_move) } } fn apply_move(board, player, index) { // board index player } fn get_board_state(board) { // "X", , "O", , "tie" } fn make_computer_move(board) { let position = get_the_best_move(board) return apply_move(board, "O", position) } fn get_the_best_move(board) { return get_the_best_move_loop(board, 1, 1, -1000) } fn get_the_best_move_loop(board, index, position, score) { if index > 9 { return position } else if cell_is_free(board, index) { let new_board = apply_move(board, "O", index) let new_score = minimax(new_board, "X", 0) if score < new_score { return get_the_best_move_loop(board, index + 1, index, new_score) } else { return get_the_best_move_loop(board, index + 1, position, score) } } else { return get_the_best_move_loop(board, index + 1, position, score) } } fn cell_is_free(board, index) { // true, board index ( ) } fn minimax(board, player, depth) { let state = get_board_state(board) if state = "X" { // return -10 + depth } else if state = "O" { // return 10 - depth } else if state = "tie" { // return 0 } else { let score = if player = "X" { 1000 } else { -1000 } return minimax_loop(board, player, depth, 1, score) } } fn minimax_loop(board, player, depth, index, score) { if index > 9 { return score } else if cell_is_free(board, index) { // , let new_board = apply_move(board, player, index) let new_score = minimax(new_board, switch_player(player), depth + 1) let the_best_score = if player = "X" { // if new_score < score { new_score } else { score } } else { // if new_score > score { new_score } else { score } } return minimax_loop(board, player, depth, index + 1, the_best_score) } else { // return minimax_loop(board, player, depth, index + 1, score) } } fn switch_player(player) { // ; X -> O, O -> X }
Fungsi pemilihan pemindahan komputer menggunakan algoritma minimax, di mana komputer memaksimalkan nilainya, dan orang itu mengecilkannya. Parameter kedalaman dari fungsi minimax diperlukan untuk memilih gerakan yang mengarah ke kemenangan dalam jumlah gerakan paling sedikit.
Algoritma ini menggunakan sejumlah besar panggilan rekursif dan langkah pertama komputer dihitung pada mesin saya hingga 2-3 detik. Kami entah bagaimana harus mempercepat. Anda cukup mengambil dan menghitung awal gerakan terbaik komputer untuk semua kondisi lapangan perjudian yang memungkinkan. Status seperti itu ternyata 886. Dimungkinkan untuk mengurangi angka ini karena rotasi dan refleksi lapangan, tetapi itu tidak perlu.
Versi baru cepat.
Saatnya menampilkan bidang permainan dengan indah. Apa yang harus digunakan jika ini adalah sesuatu a) harus menggambar grafik (abad ke-21 di halaman, permainan seperti apa tanpa grafis?!) Dan b) diinginkan memiliki format XML? Tentu saja SVG!
Postprocessor menggambar bidang kotak-kotak dan mengatur salib hijau, nol biru dan
gaun hitam kecil
di dalamnya . Itu juga menunjukkan pesan tentang akhir permainan.
Dan sekarang gim ini sepertinya sudah siap. Tetapi ada sesuatu yang tidak beres. Untuk bermain, Anda harus melakukan banyak tindakan yang tidak perlu, membosankan dan menjengkelkan: masukkan nomor sel di bidang untuk kode berikutnya dan tekan tombol. Cukup klik pada sel yang diinginkan!
Kami sedang menyelesaikan
runtime dan
postprocessor .
Dalam runtime, tambahkan fungsi respons dengan mengeklik elemen SVG:
function onSvgClick(arg) { document.getElementById("parameters").value = arg; onStep(); }
Dalam postprocessor kita menambahkan kotak di atas setiap sel (transparansi ditentukan oleh gaya rect.btn), ketika diklik, fungsi dengan nomor sel disebut:
<rect class="btn" x="-23" y="-23" width="45" height="45" onclick="onSvgClick({$index})"/>
Setelah kumpulan selesai, mengklik sel mana pun memulai yang baru. Tombol "Init" hanya perlu ditekan sekali di awal.
Sekarang Anda dapat mempertimbangkan game selesai. Masalahnya kecil: sembunyikan bagian dalamnya, kemas dalam aplikasi elektron, letakkan di Steam, ???, bangun kaya dan terkenal.
Kesimpulan
Seorang programmer yang berpikiran kuat dapat menulis apa pun tentang apa pun
bahkan dalam JavaScript . Tetapi lebih baik menggunakan alat yang cocok untuk setiap tugas.