Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Липилин Матвей и Денис Саяфаров из ФТ-201 (крутые ребята) #138

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
5 changes: 5 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions .idea/tic-tac-toe2.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 16 additions & 10 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,22 @@
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<table class="table">
<tbody id="fieldWrapper">
<div class="container">
<label for="boardSize">Размер поля</label>
<input type="number" id="boardSize" min="3" max="10" value="3">
<label for="ai">Играть с компьютером</label>
<input type="checkbox" id="ai">
</div>
<div class="container">
<table class="table">
<tbody id="fieldWrapper">

</tbody>
</table>
</div>
<div>
<button class="resetButton" id="reset">Сначала</button>
</div>
<script src="index.js"></script>
</tbody>
</table>
</div>
<div>
<button class="resetButton" id="reset">Сначала</button>
</div>
<script src="index.js"></script>
</body>
</html>
203 changes: 189 additions & 14 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,49 @@
// здесь был Денчик

const CROSS = 'X';
const ZERO = 'O';
const EMPTY = ' ';

const container = document.getElementById('fieldWrapper');
const aiCheckbox = document.getElementById('ai');
const inputSize = document.getElementById('boardSize');

function readBoardSize() {
return +inputSize.value;
}

let field = [];

let OCCUPIED_CELLS = 0;
let BOARD_SIZE = readBoardSize();
let PLAYER = CROSS;
let WINNER = null;

resetGame(BOARD_SIZE);
startGame();
addSizeChangeListener();
addResetListener();

function startGame () {
renderGrid(3);
function startGame() {
renderGrid(BOARD_SIZE);
}

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++) {
Expand All @@ -26,41 +58,166 @@ function renderGrid (dimension) {
}
}

function cellClickHandler (row, col) {
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] === curPlayer) {
count++;
} else {
count = 0;
}
if (count === WIN_LENGTH) {
return true;
}
}
}

// Проверка по вертикали
for (let i = 0; i < BOARD_SIZE; i++) {
let count = 0;
for (let j = 0; j < BOARD_SIZE; j++) {
if (field[j][i] === curPlayer) {
count++;
} else {
count = 0;
}
if (count === WIN_LENGTH) {
return true;
}
}
}

// Проверка по диагонали
for (let i = 1; i < BOARD_SIZE - 1; i++) {
for (let j = 1; j < BOARD_SIZE - 1; j++) {
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] === curPlayer && field[i + 1][j - 1] === curPlayer) {
return true;
}
}
}
}

return false;
}

function cellClickHandler(row, col) {
// Пиши код тут
console.log(`Clicked on cell: ${row}, ${col}`);

if (WINNER !== null) {
return;
}
if (field[row][col] !== EMPTY) {
return;
}

field[row][col] = PLAYER;
OCCUPIED_CELLS++;

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) && 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);
}
}

/* Пользоваться методом для размещения символа в клетке так:
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, WINNER === field[i][j] ? 'red' : '#333');
}
}
}

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!');
resetGame(readBoardSize());
startGame();
addResetListener();
addSizeChangeListener();
}

function resetGame(newSize) {
WINNER = null;
field = [];
BOARD_SIZE = newSize;
for (let i = 0; i <= BOARD_SIZE; i++) {
field.push(new Array(BOARD_SIZE).fill(EMPTY));
}

PLAYER = CROSS;
OCCUPIED_CELLS = 0;
WINNER = null;
}

/* Test Function */

/* Победа первого игрока */
function testWin () {
function testWin() {
clickOnCell(0, 2);
clickOnCell(0, 0);
clickOnCell(2, 0);
Expand All @@ -71,7 +228,7 @@ function testWin () {
}

/* Ничья */
function testDraw () {
function testDraw() {
clickOnCell(2, 0);
clickOnCell(1, 0);
clickOnCell(1, 1);
Expand All @@ -84,6 +241,24 @@ function testDraw () {
clickOnCell(2, 2);
}

function clickOnCell (row, col) {
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}`);
}