Tic Tac Toe Teil 2: Staatenloses Rückgängigmachen / Wiederherstellen

Tic Tac Toe Teil 0: Vergleich von Svelte und React
Tic Tac Toe Teil 1: Svelte und Canvas 2D
Tic Tac Toe Teil 2: Staatenloses Rückgängigmachen / Wiederherstellen
Tic Tac Toe, Teil 3: Rückgängig / Wiederherstellen mit Befehlsspeicher
Tic Tac Toe Teil 4: Interaktion mit dem Flask Backend über HTTP

Fortsetzung des Artikels Tic Tac Toe, Teil 1 , in dem wir mit der Entwicklung dieses Spiels auf Svelte begonnen haben . In diesem Teil werden wir das Spiel bis zum Ende beenden. Fügen Sie Undo / Redo- Teams hinzu, greifen Sie zufällig auf einen beliebigen Schritt des Spiels zu, wechseln Sie sich mit dem Gegner ab, zeigen Sie den Status des Spiels an und bestimmen Sie den Gewinner.


Befehle rückgängig machen / wiederholen

REPL-Code


Zu diesem Zeitpunkt wurden der Anwendung Befehle zum Rückgängigmachen / Wiederherstellen hinzugefügt. Push- und Redo- Methoden zum Verlaufsspeicher hinzugefügt.


undo: () => update(h => { h.undo(); return h; }), redo: () => update(h => { h.redo(); return h; }), 

Die Methoden push , redo , canUndo und canRedo werden der History- Klasse hinzugefügt.


 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++; } 

Die Verlaufsmethode wurde der Push- Methode zum Löschen aller Zustände vom aktuellen zum letzten hinzugefügt. Wenn wir den Befehl Rückgängig mehrmals ausführen und in das Spielfeld klicken, werden alle Zustände rechts vom aktuellen bis zum letzten aus dem Speicher gelöscht und ein neuer Zustand hinzugefügt.


 push(state) { // remove all redo states if (this.canRedo()) this.history.splice(this.current + 1); // add a new state this.current++; this.history.push(state); } 

Der App- Komponente wurden Schaltflächen zum Rückgängigmachen und Wiederherstellen hinzugefügt. Wenn die Ausführung von Befehlen nicht möglich ist, werden sie deaktiviert.


 <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> 

Kurswechsel

REPL-Code


Nach einem Mausklick wird abwechselnd ein Kreuz oder ein Zeh angezeigt.


Die clickCell () -Methode wurde aus ihrem Verlaufsrepository entfernt , der gesamte Methodencode wurde an den handleClick () -Handler der Board- Komponente übertragen.


 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); } 

Somit wurde der zuvor gemachte Fehler beseitigt, und das Repository war von der Logik dieses bestimmten Spiels abhängig. Jetzt wurde dieser Fehler behoben und das Repository kann ohne Änderungen in anderen Spielen und Anwendungen wiederverwendet werden.


Bisher wurde der Status eines Spielschritts nur durch ein Array von 9 Werten beschrieben. Jetzt wird der Status des Spiels durch das Objekt bestimmt, das das Array und die xIsNext-Eigenschaft enthält. Die Initialisierung dieses Objekts zu Beginn des Spiels sieht folgendermaßen aus:


 let state = { squares: Array(9).fill(''), xIsNext: true, }; 

Es kann auch angemerkt werden, dass der Verlaufsspeicher nun Zustände wahrnehmen kann, die auf irgendeine Weise beschrieben wurden.


Zufälliger Zugriff zum Verschieben des Verlaufs

REPL-Code


Im Verlaufsspeicher wurde die setCurrent (aktuelle) Methode hinzugefügt, mit der wir den ausgewählten aktuellen Status des Spiels festlegen.


 setCurrent(current) { if (current >= 0 && current < this.history.length) this.current = current; } 

 setCurrent: (current) => update(h => { h.setCurrent(current); return h; }), 

In der App- Komponente wurde die Anzeige des Bewegungsverlaufs in Form von Schaltflächen hinzugefügt.


 <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> 

Gewinnerermittlung

REPL-Code


Funktion hinzugefügt, um den Gewinner zu ermitteln berechneWinner () in einer separaten Datei helpers.js :


 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; } 

Die Statusableitung wurde hinzugefügt, um den Status des Spiels zu bestimmen. Hier wird das Ergebnis des Spiels bestimmt: Gewinner oder Unentschieden:


 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; } ); 

Die Ausgabe des Spielstatus wird in der App- Komponente hinzugefügt:


 <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> 

In der Board- Komponente wurden dem Handle- Handler des handleClick () -Klicks Einschränkungen hinzugefügt: Es ist auch nach dem Ende des Spiels nicht möglich, in die gefüllte Zelle zu klicken.


 const state = $history.currentState(); if ($status == 1 || state.squares[i]) return; 

Das Spiel ist vorbei! Im nächsten Artikel werden wir die Implementierung desselben Spiels unter Verwendung des Befehlsmusters betrachten, d. H. mit dem Speichern von Rückgängig / Wiederherstellen-Befehlen anstelle des Speicherns einzelner Zustände.


GitHub-Repository

https://github.com/nomhoi/tic-tac-toe-part2


Installieren des Spiels auf dem lokalen Computer:


 git clone https://github.com/nomhoi/tic-tac-toe-part2.git cd tic-tac-toe-part2 npm install npm run dev 

Wir starten das Spiel in einem Browser unter der Adresse: http: // localhost: 5000 / .

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


All Articles