Крестики-Нолики, Часть 2: Отмена/Повтор С Сохранением Состояния

Крестики-нолики, часть 0: Сравнение Svelte и React Крестики-нолики, часть 1: Svelte и Canvas 2D Крестики-нолики, часть 2: Отмена/Повтор с сохранением состояния Крестики-нолики, часть 3: Отмена/Повтор с хранилищем команд Крестики-нолики.

Часть 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/ .

Теги: #программирование #Логические игры #JavaScript #Развлекательные головоломки #svelte #SvelteJS #javascipt #javascipt
Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.