diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 957218e..5cdd048 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,12 +12,13 @@ jobs: strategy: matrix: - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest, windows-lates, macos-latest] node-version: [14.x, 16.x, 18.x] + architecture: [x64, x86] steps: - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} + - name: Node:${{ matrix.node-version }}, OS:${{ matrix.os }}, arch:${{ matrix.architecture }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} diff --git a/public/index.html b/public/index.html index eae7866..e9f6f59 100644 --- a/public/index.html +++ b/public/index.html @@ -20,26 +20,44 @@

MiniMax with TicTacToe

-
- Grid Size : - - Max Depth : - - +
+
+

Grid : + +

+

Piece win count : + +

+
+
+

Play as : + +

+

Max Depth : + +

+

+ source code - licence MIT
- source code - licence MIT diff --git a/public/script.js b/public/script.js index e5c6f41..e673107 100644 --- a/public/script.js +++ b/public/script.js @@ -1,8 +1,18 @@ -// =================== tic-tac-toe minimax =================== +// =================== html initialization =================== +const PIECE = [' ', '✕', '◯']; + +const htmlBoard = document.querySelector('.board'); +const htmlGridSelect = document.querySelector('.grid-size'); +const htmlWinCountSelect = document.querySelector('.win-piece-count'); +const htmlPlayerSelect = document.querySelector('.player-select'); +const htmlNewGameBtn = document.querySelector('.new-game'); +const htmlMessage = document.querySelector('.message'); + +// =================== tic-tac-toe minimax integration =================== import { TicTacToe } from './TicTacToe.js'; -let game = new TicTacToe(3); -const PIECE = [' ', '✕', '◯']; +let game; +setNewGame('Click a square'); const SUCCESS = 1; const INVALID = 0; @@ -22,8 +32,6 @@ function announceResult(flag) { } } -const htmlMessage = document.querySelector('.message'); - function makeMove(i, j, moveComputer = true) { if (!game.isFinish()) { htmlMessage.innerText = ''; @@ -65,13 +73,28 @@ function makeMove(i, j, moveComputer = true) { game.display(); } -// =================== html initialization =================== -const htmlBoard = document.querySelector('.board'); -const htmlGridSize = document.querySelector('.grid-size'); +htmlPlayerSelect.addEventListener('change', () => { + const selectedPlayer = Number(htmlPlayerSelect.value); + if (selectedPlayer === 0) { + setNewGame('New game, both computer playing'); + } else if (selectedPlayer === 1) { + setNewGame('New game, you are playing as X'); + } else { + setNewGame('New game, you are playing as O'); + } +}); + +htmlWinCountSelect.addEventListener('change', () => { + setNewGame('New game, with new piece win count'); +}); + +htmlWinCountSelect.addEventListener('change', () => { + setNewGame('New game, with new piece win count'); +}); // grid size selector -htmlGridSize.addEventListener('change', () => { - const newGridSize = Number(htmlGridSize.value); +htmlGridSelect.addEventListener('change', () => { + const newGridSize = Number(htmlGridSelect.value); if (newGridSize === 3) { document.querySelector('.depth-value').value = 10; } else if (newGridSize === 4) { @@ -82,12 +105,19 @@ htmlGridSize.addEventListener('change', () => { document.querySelector('.depth-value').value = 3; } + htmlWinCountSelect.innerHTML = ''; + for (let i = newGridSize; i > 1; --i) { + const newOptions = document.createElement('option'); + newOptions.label = i; + newOptions.value = i; + htmlWinCountSelect.appendChild(newOptions); + } + setNewGame( - newGridSize, 'The depth was changed for optimal calculation speed. ' + - 'You can change the depth on your own, but keep in mind ' + - 'a higher "depth and grid" values will cause the computer to take ' + - 'more time to move.' + 'You can change the depth on your own, but keep in mind ' + + 'a higher "depth and grid" values will cause the computer to take ' + + 'more time to move.' ); }); @@ -99,27 +129,45 @@ function generateCells() { const htmlSpan = document.createElement('span'); htmlSpan.addEventListener('click', () => makeMove(i, j)); htmlSpan.className = 'cell'; - htmlSpan.innerHTML = '​'; + + if (game.board[i * game.grid + j] !== '') { + htmlSpan.innerHTML = PIECE[game.board[i * game.grid + j]]; + } else { + htmlSpan.innerHTML = '​'; + } htmlBoard.appendChild(htmlSpan); } } htmlBoard.style.gridTemplateColumns = `repeat(${game.grid}, 1fr)`; + htmlBoard.style.gridTemplateRows = `repeat(${game.grid}, 1fr)`; } generateCells(); -// new game button -const htmlNewGameBtn = document.querySelector('.new-game'); - htmlNewGameBtn.addEventListener('click', () => { - setNewGame(game.grid); + setNewGame(); }); -function setNewGame(gridSize, msg = '') { +function setNewGame(msg = '') { + console.log('====== NEW GAME ======'); htmlMessage.innerText = msg; htmlMessage.style.fontSize = '0.9em'; htmlMessage.style.color = 'white'; - game = new TicTacToe(gridSize); + + game = new TicTacToe({ + gridLength: Number(htmlGridSelect.value), + winCount: Number(htmlWinCountSelect.value), + player: Number(htmlPlayerSelect.value) + }); + + console.log('script.js' + + `gridLength = ${Number(htmlGridSelect.value)}\n` + + `winCount = ${Number(htmlWinCountSelect.value)}\n` + + `player = ${Number(htmlPlayerSelect.value)}` + ); + + console.log('script.js: setNewGame = ', game.currentPlayer, game.player); + generateCells(); } diff --git a/public/style.css b/public/style.css index 31d509e..c2a3d49 100644 --- a/public/style.css +++ b/public/style.css @@ -31,6 +31,13 @@ body { gap: 1em; } +.drop-selections { + display: flex; + justify-content: space-evenly; + width: 50vmin; + padding: 0.1em; +} + .board { background-color: black; @@ -40,13 +47,15 @@ body { border-radius: 4%; overflow: hidden; - grid-template-columns: repeat(4, 1fr); + /* make cells fixed square */ + grid-template-columns: repeat(3, 1fr); + grid-template-rows: repeat(3, 1fr); justify-items: center; align-items: center; - width: min(50vh, 50vw); - height: min(50vh, 50vw); + width: 50vmin; + height: 50vmin; } .cell { @@ -68,7 +77,7 @@ body { .cell { font-weight: bolder; - font-size: 2.5em; + font-size: 2em; } .cell:active { @@ -144,11 +153,15 @@ a { height: 90%; } + .drop-selections { + width: 95vmin; + } + .board { outline-width: thick; - width: min(80vh, 80vw); - height: min(80vh, 80vw); + width: 80vmin; + height: 80vmin; } .message { diff --git a/tests.js b/tests.js index 910993e..53bd400 100644 --- a/tests.js +++ b/tests.js @@ -94,5 +94,4 @@ if (failedTests > 0) { console.log('\nPASSED : ALL'); } -process.exit(1); -// process.exit(failedTests); +process.exit(failedTests);