Крестики-нолики, часть 0: Сравнение Svelte и React Крестики-нолики, часть 1: Svelte и Canvas 2D Крестики-нолики, часть 2: Отмена/Повтор с сохранением состояния Крестики-нолики, часть 3: Отмена/Повтор с хранилищем команд Крестики-нолики.Теги: #программирование #Логические игры #JavaScript #Развлекательные головоломки #svelte #SvelteJS #javascipt #javasciptЧасть 4. Взаимодействие с серверной частью Flask с использованием HTTP Продолжение статьи Крестики-нолики, часть 1 , в котором мы начали разработку этой игры на Стройный .
В этой части мы пройдем игру до конца.
Давайте добавим команды Отменить повторить , произвольный доступ к любому шагу игры, чередование ходов с противником, отображение статуса игры, определение победителя.
Команды отмены/повтора Код для REPL На этом этапе в приложение были добавлены команды Отменить/Повторить.
На хранении история добавлены методы толкать И переделывать .
Для класса История добавлены методы толкать , переделывать , можно отменить , можноПовторить .undo: () => update(h => { h.undo(); return h; }), redo: () => update(h => { h.redo(); return h; }),
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++; }
В методе толкать сорт История добавлено удаление всех состояний от текущего до последнего.Если мы выполним команду несколько раз Отменить и кликните по игровому полю, тогда все состояния справа от текущего до последнего будут удалены из хранилища и добавлено новое состояние.
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); }
В компоненте Приложение добавлены кнопки Отменить И Повторить .Если выполнение команд невозможно, они деактивируются.
<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>
Изменение курса Код для REPL Поочередное появление крестика или нуля после щелчка мыши.Метод кликЯчейка() их складские помещения были удалены история , весь код метода перенесен в обработчик дескрипторКлик() компонент Доска .
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); }
Таким образом, была устранена ранее допущенная ошибка; хранилище зависело от логики этой конкретной игры.Теперь эта проблема решена, и хранилище можно повторно использовать в других играх и приложениях без изменений.
Раньше состояние игрового шага описывалось только массивом из 9 значений.
Теперь состояние игры определяется объектом, содержащим массив и свойство xIsNext. Инициализация этого объекта в начале игры выглядит так:
let state = { squares: Array(9).
fill(''), xIsNext: true, };
Также можно отметить, что хранилище история теперь может воспринимать состояния, описанные любым способом.Произвольный доступ к истории перемещений Код для REPL На хранении история добавил метод setCurrent (текущий) , с помощью которого мы устанавливаем выбранное текущее состояние игры.
setCurrent(current) { if (current >= 0 && current < this.history.length) this.current = current; }
setCurrent: (current) => update(h => { h.setCurrent(current); return h; }),
В компоненте Приложение добавлено отображение истории ходов в виде кнопок.
<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>
Определение победителя, отображение статуса игры Код для REPL Добавлена функция определения победителя вычислитьПобедитель() в отдельном файле 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; }
Добавлен производное хранилище положение дел для определения статуса игры здесь определяется исход игры: победитель или ничья: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; } );
В компоненте Приложение добавлен вывод статуса игры:<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>
В компоненте Доска в обработчике кликов дескрипторКлик() добавлены ограничения: невозможно нажать в заполненную ячейку и в конце игры.
const state = $history.currentState(); if ($status == 1 || state.squares[i]) return;
Игра закончена! В следующей статье мы рассмотрим реализацию той же игры с использованием паттерна Command, т.е.с сохранением команд Undo/Redo вместо хранения отдельных состояний.
Репозиторий на GitHub https://github.com/nomhoi/tic-tac-toe-part2 Установка игры на локальный компьютер:
git clone https://github.com/nomhoi/tic-tac-toe-part2.git cd tic-tac-toe-part2 npm install npm run dev
Запустите игру в браузере по адресу: http://localhost:5000/ .
-
Революция Игровых Проектов На Kickstarter
19 Oct, 24 -
Как Я Устроился На Работу В Stack Exchange
19 Oct, 24 -
Как Ускорить Windows Vista
19 Oct, 24