dao-game / commit
More refactoring and getting undo to work.
game.js | 169 ++++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 107 insertions(+), 62 deletions(-) diff --git a/game.js b/game.js index 5f4b8ac..19547fc 100644 --- a/game.js +++ b/game.js @@ -6,7 +6,9 @@ class Coord { * @memberof Coord */ constructor(row, col) { + /** @type {number} */ this.row = row; + /** @type {number} */ this.col = col; } @@ -95,11 +97,25 @@ const gameBoard = { } } +class Move { + /** + * Creates an instance of Move. + * @param {number} sourceIndex + * @param {number} destIndex + * @memberof Move + */ + constructor(sourceIndex, destIndex) { + /** @type {number} */ + this.sourceIndex = sourceIndex; + /** @type {number} */ + this.destIndex = destIndex; + } +} const player = { isRedTurn: false, /** @type {number | undefined} */ selectedPieceId: undefined, - /** @type {Coord[]} */ + /** @type {Move[]} */ moveHistory: [], } @@ -112,37 +128,7 @@ const bluePieces = () => Array.from(document.querySelectorAll('.blue-piece:not(# const redTurnText = () => Array.from(document.querySelectorAll(".red-turn-text")); const blueTurnText = () => Array.from(document.querySelectorAll(".blue-turn-text")); const resetButton = document.getElementById('reset-button'); -resetButton.addEventListener('click', () => { - if (confirm('Reset?')) { - window.location.reload(); - } -}); - -// create board and pieces -(() => { - let isWhite = true; - const table = document.getElementById('table'); - for (let r = 0; r < constants.rows; r++) { - const tr = document.createElement('tr'); - table.appendChild(tr); - for (let c = 0; c < constants.cols; c++) { - const td = document.createElement('td'); - tr.appendChild(td); - td.className = isWhite ? 'white' : 'black'; - isWhite = !isWhite; - } - isWhite = !isWhite; - } - gameBoard.board.forEach((value, index) => { - if (value !== null) { - const isRed = value < 4; - const defaultPiece = isRed ? defaultRedPiece : defaultBluePiece; - const newPiece = defaultPiece.cloneNode(true); - newPiece.id = value; - cells()[index].appendChild(newPiece); - } - }); -})(); +const undoButton = document.getElementById('undo-button'); const listenerManager = { /** @type {{element: Element, type: string, listener: (event: Event) => void}[]} */ @@ -179,6 +165,44 @@ const resetBoard = () => { listenerManager.removeListeners(); }; +/** + * @param {number} sourceIndex + * @param {number} destIndex + */ +const movePiece = async (sourceIndex, destIndex) => { + const pieceId = gameBoard.board[sourceIndex]; + // find current piece + const piece = document.getElementById(pieceId); + // unselect piece + piece.classList.remove(constants.selectedPieceClassName); + + // create clone for new position + const destPiece = piece.cloneNode(true); + // add to destination cell + cells()[destIndex].appendChild(destPiece); + + // start animations + const destAnimation = cells()[destIndex].animate([{ opacity: 0 }, { opacity: 1 }], { duration: 1000, iterations: 1 }) + const sourceAnimation = piece.animate([{ + opacity: 1, + width: '45px', + height: '45px' + }, { + opacity: 0, + width: '5px', + height: '5px' + },], { duration: 1000, iterations: 1 }); + + // await animations + await Promise.all([sourceAnimation.finished, destAnimation.finished]); + + // remove old piece + piece.parentNode.removeChild(piece); + gameBoard.board[sourceIndex] = null; + // set new piece + gameBoard.board[destIndex] = pieceId; +}; + const nextMove = () => { const setActivePlayerPieces = () => { /** @param {Event} event */ @@ -260,36 +284,10 @@ const nextMove = () => { const makeMove = async (destIndex) => { listenerManager.removeListeners(); - // find current piece - const piece = document.getElementById(player.selectedPieceId); - // unselect piece - piece.classList.remove(constants.selectedPieceClassName); - - // create clone for new position - const destPiece = piece.cloneNode(true); - // add to destination cell - cells()[destIndex].appendChild(destPiece); - - // start animations - const destAnimation = cells()[destIndex].animate([{ opacity: 0 }, { opacity: 1 }], { duration: 1000, iterations: 1 }) - const sourceAnimation = piece.animate([{ - opacity: 1, - width: '45px', - height: '45px' - }, { - opacity: 0, - width: '5px', - height: '5px' - },], { duration: 1000, iterations: 1 }); - - // await animations - await Promise.all([sourceAnimation.finished, destAnimation.finished]); - - // remove old piece - piece.parentNode.removeChild(piece); - gameBoard.board[gameBoard.board.indexOf(player.selectedPieceId)] = null; - // set new piece - gameBoard.board[destIndex] = player.selectedPieceId; + const sourceIndex = gameBoard.board.indexOf(player.selectedPieceId); + player.moveHistory.push(new Move(sourceIndex, destIndex)); + + await movePiece(sourceIndex, destIndex); checkForWin(); nextMove(); @@ -415,5 +413,52 @@ const checkForWin = () => { } }; +const init = () => { + // create board and pieces + let isWhite = true; + const table = document.getElementById('table'); + for (let r = 0; r < constants.rows; r++) { + const tr = document.createElement('tr'); + table.appendChild(tr); + for (let c = 0; c < constants.cols; c++) { + const td = document.createElement('td'); + tr.appendChild(td); + td.className = isWhite ? 'white' : 'black'; + isWhite = !isWhite; + } + isWhite = !isWhite; + } + gameBoard.board.forEach((value, index) => { + if (value !== null) { + const isRed = value < 4; + const defaultPiece = isRed ? defaultRedPiece : defaultBluePiece; + const newPiece = defaultPiece.cloneNode(true); + newPiece.id = value; + cells()[index].appendChild(newPiece); + } + }); + + // hook up buttons + resetButton.addEventListener('click', () => { + if (player.moveHistory.length === 0) { + return; + } + + if (confirm('Reset?')) { + window.location.reload(); + } + }); + undoButton.addEventListener('click', () => { + if (player.moveHistory.length === 0) { + return; + } + + const { destIndex, sourceIndex } = player.moveHistory.pop(); + movePiece(destIndex, sourceIndex); + nextMove(); + }); +}; + // start! +init(); nextMove(); \ No newline at end of file