Tic Tac Toe Bagian 0: Membandingkan Langsing dan Bereaksi
Tic Tac Toe Bagian 1: Svelte dan Canvas 2D
Tic Tac Toe Bagian 2: Stateless Undo / Redo
Tic Tac Toe, bagian 3: Undo / Redo dengan penyimpanan perintah
Tic Tac Toe Bagian 4: Berinteraksi dengan Flask Backend Menggunakan HTTP
Kelanjutan artikel Tic Tac Toe, bagian 1 , di mana kami memulai pengembangan game ini di Svelte . Di bagian ini kita akan menyelesaikan permainan sampai akhir. Tambahkan tim Undo / Redo , akses acak ke setiap langkah permainan, bergantian bergerak dengan lawan, menampilkan status permainan, menentukan pemenang.
Undo / Redo Perintah
Kode REPL
Pada titik ini, perintah Undo / Redo telah ditambahkan ke aplikasi. Menambahkan metode push dan redo ke toko sejarah .
undo: () => update(h => { h.undo(); return h; }), redo: () => update(h => { h.redo(); return h; }),
Metode push , redo , canUndo , canRedo ditambahkan ke kelas History .
canUndo() { return this.current > 0; } canRedo() { return this.current < this.history.length - 1; } undo() { if (this.canUndo()) this.current--; } redo() { if (this.canRedo()) this.current++; }
Metode sejarah telah ditambahkan ke metode push menghapus semua negara dari saat ini ke yang terakhir. Jika kita menjalankan perintah Undo beberapa kali dan klik di lapangan bermain, maka semua negara di sebelah kanan saat ini ke yang terakhir akan dihapus dari toko dan negara baru akan ditambahkan.
push(state) {
Tombol Undo dan Redo telah ditambahkan ke komponen App . Jika eksekusi perintah tidak memungkinkan, maka perintah tersebut dinonaktifkan.
<div> {#if $history.canUndo()} <button on:click={history.undo}>Undo</button> {:else} <button disabled>Undo</button> {/if} {#if $history.canRedo()} <button on:click={history.redo}>Redo</button> {:else} <button disabled>Redo</button> {/if} </div>
Ubah saja
Kode REPL
Tampilan silang atau jari kaki secara bergantian setelah klik mouse dilakukan.
Metode clickCell () telah dihapus dari repositori riwayatnya , semua kode metode telah ditransfer ke handler handleClick () dari komponen Board .
function handleClick(event) { let x = Math.trunc((event.offsetX + 0.5) / cellWidth); let y = Math.trunc((event.offsetY + 0.5) / cellHeight); let i = y * width + x; const state = $history.currentState(); const squares = state.squares.slice(); squares[i] = state.xIsNext ? 'X' : 'O'; let newState = { squares: squares, xIsNext: !state.xIsNext, }; history.push(newState); }
Dengan demikian, kesalahan yang dibuat sebelumnya dihilangkan, repositori tergantung pada logika permainan ini. Sekarang kesalahan ini telah diperbaiki, dan repositori dapat digunakan kembali di game dan aplikasi lain tanpa perubahan.
Sebelumnya, keadaan langkah permainan hanya dijelaskan oleh array nilai 9. Sekarang keadaan permainan ditentukan oleh objek yang berisi array dan properti xIsNext. Inisialisasi objek ini di awal permainan terlihat seperti ini:
let state = { squares: Array(9).fill(''), xIsNext: true, };
Dan juga dapat dicatat bahwa penyimpanan histori sekarang dapat memahami kondisi yang dijelaskan dengan cara apa pun.
Akses acak untuk memindahkan riwayat
Kode REPL
Di toko sejarah , metode setCurrent (saat ini) ditambahkan, yang dengannya kami mengatur keadaan saat ini dari permainan.
setCurrent(current) { if (current >= 0 && current < this.history.length) this.current = current; }
setCurrent: (current) => update(h => { h.setCurrent(current); return h; }),
Dalam komponen Aplikasi , tambahkan tampilan riwayat gerakan dalam bentuk tombol.
<ol> {#each $history.history as value, i} {#if i==0} <li><button on:click={() => history.setCurrent(i)}>Go to game start</button></li> {:else} <li><button on:click={() => history.setCurrent(i)}>Go to move #{i}</button></li> {/if} {/each} </ol>
Menentukan pemenang, menampilkan status permainan
Kode REPL
Fungsi yang ditambahkan untuk menentukan pemenang calculWinner () dalam file helpers.js terpisah:
export function calculateWinner(squares) { const lines = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6], ]; for (let i = 0; i < lines.length; i++) { const [a, b, c] = lines[i]; if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { return squares[a]; } } return null; }
Derivatif status telah ditambahkan untuk menentukan status permainan, di sini hasil pertandingan ditentukan: pemenang atau seri:
export const status = derived( history, $history => { if ($history.currentState()) { if (calculateWinner($history.currentState().squares)) return 1; else if ($history.current == 9) return 2; } return 0; } );
Output dari status game telah ditambahkan ke komponen Aplikasi :
<div class="status"> {#if $status === 1} <b>Winner: {!$history.currentState().xIsNext ? 'X' : 'O'}</b> {:else if $status === 2} <b>Draw</b> {:else} Next player: {$history.currentState().xIsNext ? 'X' : 'O'} {/if} </div>
Dalam komponen Dewan , pembatasan berikut telah ditambahkan ke gagang klik handleClick () : tidak mungkin untuk mengklik di sel yang diisi bahkan di akhir permainan.
const state = $history.currentState(); if ($status == 1 || state.squares[i]) return;
Game sudah berakhir! Pada artikel selanjutnya, kami akan mempertimbangkan implementasi game yang sama menggunakan pola Command, mis. dengan menyimpan perintah Undo / Redo alih-alih menyimpan status individual.
Repositori GitHub
https://github.com/nomhoi/tic-tac-toe-part2
Memasang game di komputer lokal:
git clone https://github.com/nomhoi/tic-tac-toe-part2.git cd tic-tac-toe-part2 npm install npm run dev
Kami meluncurkan game di browser di alamat: http: // localhost: 5000 / .