From 024e32c65c13655746289e9526bb3b87c4426592 Mon Sep 17 00:00:00 2001 From: Matvey Lipilin Date: Mon, 27 Feb 2023 18:12:22 +0500 Subject: [PATCH 01/13] =?UTF-8?q?=D0=B1=D0=B0=D0=B7=D0=B0:?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.gitignore | 5 ++++ .idea/modules.xml | 8 +++++ .idea/tic-tac-toe2.iml | 12 ++++++++ .idea/vcs.xml | 6 ++++ index.js | 68 ++++++++++++++++++++++++++++++++++-------- 5 files changed, 86 insertions(+), 13 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/modules.xml create mode 100644 .idea/tic-tac-toe2.iml create mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..b58b603 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..c0a331e --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/tic-tac-toe2.iml b/.idea/tic-tac-toe2.iml new file mode 100644 index 0000000..0c8867d --- /dev/null +++ b/.idea/tic-tac-toe2.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/index.js b/index.js index 7553909..7a1e7e7 100644 --- a/index.js +++ b/index.js @@ -4,14 +4,41 @@ const EMPTY = ' '; const container = document.getElementById('fieldWrapper'); +let field = []; + +let OCCUPIED_CELLS = 0; +let BOARD_SIZE = 3; +for (let i = 0; i <= BOARD_SIZE; i++) { + field.push(new Array(BOARD_SIZE).fill(EMPTY)); +} + +let PLAYER = CROSS; + + startGame(); addResetListener(); -function startGame () { +function startGame() { renderGrid(3); } -function renderGrid (dimension) { + +function expandBoard() { + BOARD_SIZE += 2; + let newBoard = []; + for (let k = 0; k < BOARD_SIZE; k++) { + newBoard.push(new Array(BOARD_SIZE).fill(EMPTY)); + for (let i = 0; i < BOARD_SIZE - 2; i++) { + for (let j = 0; j < BOARD_SIZE - 2; j++) { + newBoard[i + 1][j + 1] = field[i][j]; + } + } + } + + field = newBoard; +} + +function renderGrid(dimension) { container.innerHTML = ''; for (let i = 0; i < dimension; i++) { @@ -26,41 +53,56 @@ function renderGrid (dimension) { } } -function cellClickHandler (row, col) { +function cellClickHandler(row, col) { // Пиши код тут console.log(`Clicked on cell: ${row}, ${col}`); + field[row][col] = PLAYER; + PLAYER = PLAYER === CROSS ? ZERO : CROSS; + OCCUPIED_CELLS++; + + let cells = BOARD_SIZE * BOARD_SIZE; + if (OCCUPIED_CELLS >= Math.floor(cells / 2)) { + expandBoard(); + renderGrid(); + } + renderBoard(); +} - /* Пользоваться методом для размещения символа в клетке так: - renderSymbolInCell(ZERO, row, col); - */ +function renderBoard() { + for (let i = 0; i < BOARD_SIZE; i++) { + for (let j = 0; j < BOARD_SIZE; j++) { + renderSymbolInCell(field[i][j], i, j); + } + } } -function renderSymbolInCell (symbol, row, col, color = '#333') { +function renderSymbolInCell(symbol, row, col, color = '#333') { const targetCell = findCell(row, col); targetCell.textContent = symbol; targetCell.style.color = color; } -function findCell (row, col) { +function findCell(row, col) { const targetRow = container.querySelectorAll('tr')[row]; return targetRow.querySelectorAll('td')[col]; } -function addResetListener () { +function addResetListener() { const resetButton = document.getElementById('reset'); resetButton.addEventListener('click', resetClickHandler); } -function resetClickHandler () { +function resetClickHandler() { console.log('reset!'); } /* Test Function */ + /* Победа первого игрока */ -function testWin () { +function testWin() { clickOnCell(0, 2); clickOnCell(0, 0); clickOnCell(2, 0); @@ -71,7 +113,7 @@ function testWin () { } /* Ничья */ -function testDraw () { +function testDraw() { clickOnCell(2, 0); clickOnCell(1, 0); clickOnCell(1, 1); @@ -84,6 +126,6 @@ function testDraw () { clickOnCell(2, 2); } -function clickOnCell (row, col) { +function clickOnCell(row, col) { findCell(row, col).click(); } From f2555d81629ef06e554a8126f840fef32c0e4235 Mon Sep 17 00:00:00 2001 From: Matvey Lipilin Date: Mon, 27 Feb 2023 18:14:36 +0500 Subject: [PATCH 02/13] =?UTF-8?q?=D0=B1=D0=B0=D0=B7=D0=B0:=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 7a1e7e7..4240eab 100644 --- a/index.js +++ b/index.js @@ -8,10 +8,6 @@ let field = []; let OCCUPIED_CELLS = 0; let BOARD_SIZE = 3; -for (let i = 0; i <= BOARD_SIZE; i++) { - field.push(new Array(BOARD_SIZE).fill(EMPTY)); -} - let PLAYER = CROSS; @@ -96,8 +92,20 @@ function addResetListener() { function resetClickHandler() { console.log('reset!'); + + resetGame(); } +function resetGame() { + field = []; + BOARD_SIZE = 3; + for (let i = 0; i <= BOARD_SIZE; i++) { + field.push(new Array(BOARD_SIZE).fill(EMPTY)); + } + + PLAYER = CROSS; + OCCUPIED_CELLS = 0; +} /* Test Function */ From fe192e41f6db0998907a26c1e0802dc3e75d8e6a Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 27 Feb 2023 18:16:24 +0500 Subject: [PATCH 03/13] test push commit --- index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.js b/index.js index 7553909..0da7f09 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,5 @@ +// здесь был Денчик + const CROSS = 'X'; const ZERO = 'O'; const EMPTY = ' '; From cc9d58971c03a55636a5618ca041f8a721743143 Mon Sep 17 00:00:00 2001 From: Matvey Lipilin Date: Mon, 27 Feb 2023 18:34:55 +0500 Subject: [PATCH 04/13] =?UTF-8?q?=D0=B1=D0=B0=D0=B7=D0=B0:=203?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.js | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index f78968a..3c3ee9c 100644 --- a/index.js +++ b/index.js @@ -11,6 +11,7 @@ let field = []; let OCCUPIED_CELLS = 0; let BOARD_SIZE = 3; let PLAYER = CROSS; +let WINNER = null; startGame(); @@ -51,16 +52,84 @@ function renderGrid(dimension) { } } +function checkWinner() { + const WIN_LENGTH = 3; + + // Проверка по горизонтали + for (let i = 0; i < BOARD_SIZE; i++) { + let count = 0; + for (let j = 0; j < BOARD_SIZE; j++) { + if (field[i][j] === PLAYER) { + count++; + } else { + count = 0; + } + if (count === WIN_LENGTH) { + return PLAYER; + } + } + } + + // Проверка по вертикали + for (let i = 0; i < BOARD_SIZE; i++) { + let count = 0; + for (let j = 0; j < BOARD_SIZE; j++) { + if (field[j][i] === PLAYER) { + count++; + } else { + count = 0; + } + if (count === WIN_LENGTH) { + return PLAYER; + } + } + } + + // Проверка по диагонали + let count = 0; + for (let i = 0; i < BOARD_SIZE; i++) { + if (field[i][i] === PLAYER) { + count++; + } else { + count = 0; + } + if (count === WIN_LENGTH) { + return PLAYER; + } + } + + // Проверка по диагонали + count = 0; + for (let i = 0; i < BOARD_SIZE; i++) { + if (field[i][BOARD_SIZE - 1 - i] === PLAYER) { + count++; + } else { + count = 0; + } + if (count === WIN_LENGTH) { + return PLAYER; + } + } + + return null; +} + function cellClickHandler(row, col) { // Пиши код тут console.log(`Clicked on cell: ${row}, ${col}`); + if (field[row][col] !== EMPTY) { + return; + } + field[row][col] = PLAYER; PLAYER = PLAYER === CROSS ? ZERO : CROSS; OCCUPIED_CELLS++; + WINNER = checkWinner(); + let cells = BOARD_SIZE * BOARD_SIZE; - if (OCCUPIED_CELLS >= Math.floor(cells / 2)) { + if (WINNER === null && OCCUPIED_CELLS >= Math.floor(cells / 2)) { expandBoard(); renderGrid(); } @@ -70,7 +139,7 @@ function cellClickHandler(row, col) { function renderBoard() { for (let i = 0; i < BOARD_SIZE; i++) { for (let j = 0; j < BOARD_SIZE; j++) { - renderSymbolInCell(field[i][j], i, j); + renderSymbolInCell(field[i][j], i, j, WINNER === field[i][j] ? 'red' : '#333'); } } } From 053a9912f60bd9d269b004dd7bcc445376465534 Mon Sep 17 00:00:00 2001 From: Matvey Lipilin Date: Mon, 27 Feb 2023 18:35:36 +0500 Subject: [PATCH 05/13] fix --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 3c3ee9c..19967bb 100644 --- a/index.js +++ b/index.js @@ -13,7 +13,7 @@ let BOARD_SIZE = 3; let PLAYER = CROSS; let WINNER = null; - +resetGame(); startGame(); addResetListener(); From b9a9596e4cfb1b896fecfa5f9d77b06e3df535b6 Mon Sep 17 00:00:00 2001 From: Matvey Lipilin Date: Mon, 27 Feb 2023 18:37:21 +0500 Subject: [PATCH 06/13] fix2 --- index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 19967bb..6c5f459 100644 --- a/index.js +++ b/index.js @@ -131,9 +131,13 @@ function cellClickHandler(row, col) { let cells = BOARD_SIZE * BOARD_SIZE; if (WINNER === null && OCCUPIED_CELLS >= Math.floor(cells / 2)) { expandBoard(); - renderGrid(); + renderGrid(BOARD_SIZE); } renderBoard(); + + if (WINNER !== null) { + alert(`Победил ${WINNER}`); + } } function renderBoard() { From 02ca43ecaa79fb37a1b59b9e94a4f6d92b09a015 Mon Sep 17 00:00:00 2001 From: Matvey Lipilin Date: Mon, 27 Feb 2023 18:38:15 +0500 Subject: [PATCH 07/13] mega fix --- index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 6c5f459..d9ff39d 100644 --- a/index.js +++ b/index.js @@ -27,10 +27,10 @@ function expandBoard() { let newBoard = []; for (let k = 0; k < BOARD_SIZE; k++) { newBoard.push(new Array(BOARD_SIZE).fill(EMPTY)); - for (let i = 0; i < BOARD_SIZE - 2; i++) { - for (let j = 0; j < BOARD_SIZE - 2; j++) { - newBoard[i + 1][j + 1] = field[i][j]; - } + } + for (let i = 0; i < BOARD_SIZE - 2; i++) { + for (let j = 0; j < BOARD_SIZE - 2; j++) { + newBoard[i + 1][j + 1] = field[i][j]; } } From 79dc1446671240248e55913c368b4c0f7866c69c Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 27 Feb 2023 18:42:02 +0500 Subject: [PATCH 08/13] small amogus fixes --- index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index d9ff39d..7bcbf16 100644 --- a/index.js +++ b/index.js @@ -167,8 +167,9 @@ function addResetListener() { function resetClickHandler() { console.log('reset!'); - resetGame(); + startGame(); + addResetListener(); } function resetGame() { From ba573b946145635e3d75792e0c230062683615f9 Mon Sep 17 00:00:00 2001 From: Matvey Lipilin Date: Mon, 27 Feb 2023 18:43:41 +0500 Subject: [PATCH 09/13] smart fix --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 7bcbf16..65c393e 100644 --- a/index.js +++ b/index.js @@ -123,10 +123,10 @@ function cellClickHandler(row, col) { } field[row][col] = PLAYER; - PLAYER = PLAYER === CROSS ? ZERO : CROSS; OCCUPIED_CELLS++; WINNER = checkWinner(); + PLAYER = PLAYER === CROSS ? ZERO : CROSS; let cells = BOARD_SIZE * BOARD_SIZE; if (WINNER === null && OCCUPIED_CELLS >= Math.floor(cells / 2)) { From eeed716b065e059d100edcfec821e28a0090d047 Mon Sep 17 00:00:00 2001 From: Matvey Lipilin Date: Mon, 27 Feb 2023 18:57:02 +0500 Subject: [PATCH 10/13] smart commit --- index.html | 25 ++++++++++++++---------- index.js | 56 ++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 55 insertions(+), 26 deletions(-) diff --git a/index.html b/index.html index 737a725..b3cd6e7 100644 --- a/index.html +++ b/index.html @@ -6,16 +6,21 @@ -
- - + +
+ + +
+
+
+ - -
-
-
- -
- + + + +
+ +
+ \ No newline at end of file diff --git a/index.js b/index.js index 65c393e..83f04c8 100644 --- a/index.js +++ b/index.js @@ -6,19 +6,24 @@ const EMPTY = ' '; const container = document.getElementById('fieldWrapper'); +function readBoardSize() { + return +document.getElementById('boardSize').value; +} + let field = []; let OCCUPIED_CELLS = 0; -let BOARD_SIZE = 3; +let BOARD_SIZE = readBoardSize(); let PLAYER = CROSS; let WINNER = null; -resetGame(); +resetGame(BOARD_SIZE); startGame(); +addSizeChangeListener(); addResetListener(); function startGame() { - renderGrid(3); + renderGrid(BOARD_SIZE); } @@ -99,15 +104,16 @@ function checkWinner() { } // Проверка по диагонали - count = 0; - for (let i = 0; i < BOARD_SIZE; i++) { - if (field[i][BOARD_SIZE - 1 - i] === PLAYER) { - count++; - } else { - count = 0; - } - if (count === WIN_LENGTH) { - return PLAYER; + for (let i = 1; i < BOARD_SIZE - 1; i++) { + for (let j = 1; j < BOARD_SIZE - 1; j++) { + if (field[i][j] === PLAYER) { + if (field[i - 1][j - 1] === PLAYER && field[i + 1][j + 1] === PLAYER) { + return PLAYER; + } + if (field[i - 1][j + 1] === PLAYER && field[i + 1][j - 1] === PLAYER) { + return PLAYER; + } + } } } @@ -167,14 +173,14 @@ function addResetListener() { function resetClickHandler() { console.log('reset!'); - resetGame(); + resetGame(readBoardSize()); startGame(); - addResetListener(); + addResetListener(); } -function resetGame() { +function resetGame(newSize) { field = []; - BOARD_SIZE = 3; + BOARD_SIZE = newSize; for (let i = 0; i <= BOARD_SIZE; i++) { field.push(new Array(BOARD_SIZE).fill(EMPTY)); } @@ -213,3 +219,21 @@ function testDraw() { function clickOnCell(row, col) { findCell(row, col).click(); } + +function addSizeChangeListener() { + const sizeInput = document.getElementById('boardSize'); + sizeInput.addEventListener('input', sizeChangeHandler); +} + +function sizeChangeHandler() { + const size = readBoardSize(); + if (size < 3 || size > 10) { + alert('Размер поля должен быть в диапазоне от 3 до 10'); + return; + } + + resetGame(size); + startGame(); + + console.log(`Changed size to ${BOARD_SIZE}`); +} \ No newline at end of file From 5e1f2b59996c3ed27208568d3b7577c737f7cced Mon Sep 17 00:00:00 2001 From: Matvey Lipilin Date: Mon, 27 Feb 2023 19:09:37 +0500 Subject: [PATCH 11/13] add ai --- index.html | 3 ++- index.js | 78 ++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 52 insertions(+), 29 deletions(-) diff --git a/index.html b/index.html index b3cd6e7..5450176 100644 --- a/index.html +++ b/index.html @@ -6,10 +6,11 @@ -
+ +
diff --git a/index.js b/index.js index 83f04c8..2dfe63e 100644 --- a/index.js +++ b/index.js @@ -5,9 +5,11 @@ const ZERO = 'O'; const EMPTY = ' '; const container = document.getElementById('fieldWrapper'); +const aiCheckbox = document.getElementById('ai'); +const inputSize = document.getElementById('boardSize'); function readBoardSize() { - return +document.getElementById('boardSize').value; + return +inputSize.value; } let field = []; @@ -26,7 +28,6 @@ function startGame() { renderGrid(BOARD_SIZE); } - function expandBoard() { BOARD_SIZE += 2; let newBoard = []; @@ -57,20 +58,39 @@ function renderGrid(dimension) { } } -function checkWinner() { +function findBestMove() { + let freeCells = []; + for (let i = 0; i < BOARD_SIZE; i++) { + for (let j = 0; j < BOARD_SIZE; j++) { + if (field[i][j] === EMPTY) { + freeCells.push([i, j]); + field[i][j] = ZERO; + if (isWinner(ZERO)) { + field[i][j] = EMPTY; + return [i, j] + } + field[i][j] = EMPTY; + } + } + } + + return freeCells[Math.floor(Math.random() * freeCells.length)]; +} + +function isWinner(curPlayer) { const WIN_LENGTH = 3; // Проверка по горизонтали for (let i = 0; i < BOARD_SIZE; i++) { let count = 0; for (let j = 0; j < BOARD_SIZE; j++) { - if (field[i][j] === PLAYER) { + if (field[i][j] === curPlayer) { count++; } else { count = 0; } if (count === WIN_LENGTH) { - return PLAYER; + return true; } } } @@ -79,51 +99,41 @@ function checkWinner() { for (let i = 0; i < BOARD_SIZE; i++) { let count = 0; for (let j = 0; j < BOARD_SIZE; j++) { - if (field[j][i] === PLAYER) { + if (field[j][i] === curPlayer) { count++; } else { count = 0; } if (count === WIN_LENGTH) { - return PLAYER; + return true; } } } - // Проверка по диагонали - let count = 0; - for (let i = 0; i < BOARD_SIZE; i++) { - if (field[i][i] === PLAYER) { - count++; - } else { - count = 0; - } - if (count === WIN_LENGTH) { - return PLAYER; - } - } - // Проверка по диагонали for (let i = 1; i < BOARD_SIZE - 1; i++) { for (let j = 1; j < BOARD_SIZE - 1; j++) { - if (field[i][j] === PLAYER) { - if (field[i - 1][j - 1] === PLAYER && field[i + 1][j + 1] === PLAYER) { - return PLAYER; + if (field[i][j] === curPlayer) { + if (field[i - 1][j - 1] === curPlayer && field[i + 1][j + 1] === curPlayer) { + return true; } - if (field[i - 1][j + 1] === PLAYER && field[i + 1][j - 1] === PLAYER) { - return PLAYER; + if (field[i - 1][j + 1] === curPlayer && field[i + 1][j - 1] === curPlayer) { + return true; } } } } - return null; + return false; } function cellClickHandler(row, col) { // Пиши код тут console.log(`Clicked on cell: ${row}, ${col}`); + if (WINNER !== null) { + return; + } if (field[row][col] !== EMPTY) { return; } @@ -131,18 +141,30 @@ function cellClickHandler(row, col) { field[row][col] = PLAYER; OCCUPIED_CELLS++; - WINNER = checkWinner(); + if (isWinner(PLAYER)) { + WINNER = PLAYER; + } PLAYER = PLAYER === CROSS ? ZERO : CROSS; + console.log(`Player ${PLAYER} turn`); let cells = BOARD_SIZE * BOARD_SIZE; - if (WINNER === null && OCCUPIED_CELLS >= Math.floor(cells / 2)) { + if (WINNER === null && OCCUPIED_CELLS >= Math.floor(cells / 2) && BOARD_SIZE < 10) { expandBoard(); renderGrid(BOARD_SIZE); } renderBoard(); + if (OCCUPIED_CELLS === cells) { + alert('Ничья'); + WINNER = 'Ничья'; + return; + } + if (WINNER !== null) { alert(`Победил ${WINNER}`); + } else if (PLAYER === ZERO && aiCheckbox.checked) { + let [i, j] = findBestMove(); + clickOnCell(i, j); } } From 6373f9ad9cf61201e274dcc50e960daabd9fa492 Mon Sep 17 00:00:00 2001 From: Matvey Lipilin Date: Mon, 27 Feb 2023 19:15:04 +0500 Subject: [PATCH 12/13] reset fix --- index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/index.js b/index.js index 2dfe63e..f52a6ba 100644 --- a/index.js +++ b/index.js @@ -201,6 +201,7 @@ function resetClickHandler() { } function resetGame(newSize) { + WINNER = null; field = []; BOARD_SIZE = newSize; for (let i = 0; i <= BOARD_SIZE; i++) { From 9df1d58d6c1727c599ccc200467c630f358efdfb Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 27 Feb 2023 19:16:18 +0500 Subject: [PATCH 13/13] an another one so sus small fix by den4ik --- index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.js b/index.js index 2dfe63e..71410a9 100644 --- a/index.js +++ b/index.js @@ -198,6 +198,7 @@ function resetClickHandler() { resetGame(readBoardSize()); startGame(); addResetListener(); + addSizeChangeListener(); } function resetGame(newSize) { @@ -209,6 +210,7 @@ function resetGame(newSize) { PLAYER = CROSS; OCCUPIED_CELLS = 0; + WINNER = null; } /* Test Function */