Крестики-нолики на js — различия между версиями

Материал из Department of Theoretical and Applied Mechanics
Перейти к: навигация, поиск
(Визуализация)
(Код программы)
Строка 13: Строка 13:
 
<syntaxhighlight lang="javascript" line start="1" enclose="div">
 
<syntaxhighlight lang="javascript" line start="1" enclose="div">
  
var area = document.getElementById('area');
+
var origBoard;
var cell = document.getElementsByClassName('cell');
 
var currentPlayer = document.getElementById('curPlyr');
 
  
var player = "x";
+
 
var stat = {
+
const huPlayer = 'O';
     'x': 0,
+
const aiPlayer = 'X';
     'o': 0,
+
 
     'd': 0
+
const winCombos = [
 +
    [0, 1, 2],
 +
    [3, 4, 5],
 +
    [6, 7, 8],
 +
     [0, 3, 6],
 +
    [1, 4, 7],
 +
    [2, 5, 8],
 +
     [0, 4, 8],
 +
     [6, 4, 2]
 +
]
 +
 
 +
const cells = document.querySelectorAll('.cell');
 +
startGame();
 +
 +
 
 +
function startGame() {
 +
    document.querySelector(".endgame").style.display = "none";
 +
    origBoard = Array.from(Array(9).keys());
 +
 
 +
    for (let index = 0; index < cells.length; index++) {
 +
        cells[index].innerText = '';
 +
        cells[index].style.removeProperty('background-color');
 +
        cells[index].addEventListener('click', turnClick, false);
 +
    }
 
}
 
}
var winIndex = [
 
    [1,2,3],
 
    [4,5,6],
 
    [7,8,9],
 
    [1,4,7],
 
    [2,5,8],
 
    [3,6,9],
 
    [1,5,9],
 
    [3,5,7]
 
];
 
  
for(var i = 1; i <= 9; i++) {
+
function turnClick(square) {
     area.innerHTML += "<div class='cell' pos=" + i + "></div>";
+
 
 +
     if (typeof origBoard[square.target.id] == 'number') {
 +
        turn(square.target.id, huPlayer)
 +
        if (!checkTie()) turn(bestSpot(), aiPlayer);
 +
    }
 
}
 
}
  
for (var i = 0; i< cell.length; i++) {
+
function turn(squareId, player) {
     cell[i].addEventListener('click', cellClick, false);
+
     origBoard[squareId] = player;
 +
    document.getElementById(squareId).innerText = player;
 +
    let gameWon = checkWin(origBoard, player);
 +
    if (gameWon) gameOver(gameWon)
 
}
 
}
  
function cellClick() {
+
function checkWin(board, player) {
 +
    let plays = board.reduce((a, e, i) =>
 +
        (e === player) ? a.concat(i) : a, []);
 +
    let gameWon = null;
 +
    for (let [index, win] of winCombos.entries()) {
 +
        if (win.every(elem => plays.indexOf(elem) > -1)) {
 +
            gameWon = {index: index, player: player};
 +
            break;
 +
        }
 +
    }
 +
 
 +
    return gameWon;
 +
updateStat();
 +
}
  
    var data = [];
+
function gameOver(gameWon) {
      
+
     for (let index of winCombos[gameWon.index]) {
    if(!this.innerHTML) {
+
         document.getElementById(index).style.backgroundColor =
         this.innerHTML = player;
+
         gameWon.player == huPlayer ? "blue" : "red";
    }else {
 
         alert("Ячейка занята");
 
        return;
 
 
     }
 
     }
 +
    for (var i = 0; i < cells.length; i++) {
 +
        cells[i].removeEventListener('click', turnClick, false);
 +
    }
 +
    declareWinner(gameWon.player == huPlayer ? "Вы выиграли!" : "Вы проиграли!")
 +
updateStat();
 +
}
 +
 +
function declareWinner(who) {
 +
    document.querySelector(".endgame").style.display = "block";
 +
    document.querySelector(".endgame .text").innerText = who;
 +
}
 +
 +
function emptySquares() {
 +
    return origBoard.filter(s => typeof s == 'number');
 +
}
 +
 +
function bestSpot() {
 +
 
 +
    return minimax(origBoard, aiPlayer).index;
 +
}
 +
  
     for(var i in cell){
+
function checkTie() {
        if(cell[i].innerHTML == player){
+
     if (emptySquares().length == 0) {
             data.push(parseInt(cell[i].getAttribute('pos')));
+
        for (var i = 0; i < cells.length; i++) {
 +
            cells[i].style.backgroundColor = "green";
 +
             cells[i].removeEventListener('click', turnClick, false);
 
         }
 
         }
 +
        declareWinner("Ничья!");
 +
        return true;
 
     }
 
     }
 +
    return false;
 +
updateStat();
 +
}
 +
  
     if(checkWin(data)) {
+
 
         stat[player] += 1;
+
function minimax(newBoard, player) {
        restart("Выграл: " + player);
+
    var availSpots = emptySquares(newBoard);
     }else {
+
 
         var draw = true;
+
     if (checkWin(newBoard, player)) {
        for(var i in cell) {
+
         return {score: -10};
            if(cell[i].innerHTML == '') draw = false;
+
     } else if (checkWin(newBoard, aiPlayer)) {
        }
+
         return {score: 10};  
        if(draw) {
+
    } else if (availSpots.length === 0) {
            stat.d += 1;
+
         return {score: 0}
            restart("Ничья");
 
         }
 
 
     }
 
     }
  
     player = player == "x" ? "o" : "x";
+
     var moves = [];
    currentPlayer.innerHTML = player.toUpperCase();
+
    for (let index = 0; index < availSpots.length; index++) {
}
+
        var move = {};
 +
        move.index = newBoard[availSpots[index]];
 +
        newBoard[availSpots[index]] = player;
  
function checkWin(data) {
+
        if (player == aiPlayer) {
    for(var i in winIndex) {
+
            var result = minimax(newBoard, huPlayer);
        var win = true;
+
            move.score = result.score;
         for(var j in winIndex[i]) {
+
         } else {
             var id = winIndex[i][j];
+
             var result = minimax(newBoard, aiPlayer);
             var ind = data.indexOf(id);
+
             move.score = result.score;
 +
        }
  
            if(ind == -1) {
+
        newBoard[availSpots[index]] = move.index;
                win = false
 
            }
 
        }
 
  
         if(win) return true;
+
         moves.push(move);
 
     }
 
     }
    return false;
 
}
 
  
function restart(text) {
+
    var bestMove;
   
+
    if (player === aiPlayer) {
    alert(text);
+
        var bestScore = -10000;
     for(var i = 0; i < cell.length; i++) {
+
        for(var i = 0; i < moves.length; i++) {
        cell[i].innerHTML = '';
+
            if (moves[i].score > bestScore) {
 +
                bestScore = moves[i].score;
 +
                bestMove = i;
 +
            }
 +
        }
 +
     } else {
 +
        var bestScore = 10000;
 +
        for(var i = 0; i < moves.length; i++) {
 +
            if (moves[i].score < bestScore) {
 +
                bestScore = moves[i].score;
 +
                bestMove = i;
 +
            }
 +
        }
 
     }
 
     }
    updateStat();
 
}
 
  
function updateStat() {
+
     return moves[bestMove];
     document.getElementById('sX').innerHTML = stat.x;
 
    document.getElementById('sO').innerHTML = stat.o;
 
    document.getElementById('sD').innerHTML = stat.d;
 
 
}
 
}

Версия 14:36, 13 июня 2021

Описание

Реализация компьютерной игры "Крестики-Нолики" на языке программирования JavaScript.

Исполнители: Гаврилов Виталий , Иванов Тимофей , Ионин Александр

Группа 3630103/4 Кафедра Теоретической механики

Визуализация

Код программы

Код программы на языке JavaScript:

<syntaxhighlight lang="javascript" line start="1" enclose="div">

var origBoard;


const huPlayer = 'O'; const aiPlayer = 'X';

const winCombos = [

   [0, 1, 2],
   [3, 4, 5],
   [6, 7, 8],
   [0, 3, 6],
   [1, 4, 7],
   [2, 5, 8],
   [0, 4, 8],
   [6, 4, 2]

]

const cells = document.querySelectorAll('.cell'); startGame();


function startGame() {

   document.querySelector(".endgame").style.display = "none";
   origBoard = Array.from(Array(9).keys());
  
   for (let index = 0; index < cells.length; index++) {
       cells[index].innerText = ;
       cells[index].style.removeProperty('background-color');
       cells[index].addEventListener('click', turnClick, false);
   }

}

function turnClick(square) {

   if (typeof origBoard[square.target.id] == 'number') {
       turn(square.target.id, huPlayer)
       if (!checkTie()) turn(bestSpot(), aiPlayer);
   }

}

function turn(squareId, player) {

   origBoard[squareId] = player;
   document.getElementById(squareId).innerText = player;
   let gameWon = checkWin(origBoard, player);
   if (gameWon) gameOver(gameWon)

}

function checkWin(board, player) {

   let plays = board.reduce((a, e, i) => 
       (e === player) ? a.concat(i) : a, []);
   let gameWon = null;
   for (let [index, win] of winCombos.entries()) {
       if (win.every(elem => plays.indexOf(elem) > -1)) {
           gameWon = {index: index, player: player};
           break;
       }
   }
   return gameWon;

updateStat(); }

function gameOver(gameWon) {

   for (let index of winCombos[gameWon.index]) {
       document.getElementById(index).style.backgroundColor =
       gameWon.player == huPlayer ? "blue" : "red";
   }
   for (var i = 0; i < cells.length; i++) {
       cells[i].removeEventListener('click', turnClick, false);
   }
   declareWinner(gameWon.player == huPlayer ? "Вы выиграли!" : "Вы проиграли!")

updateStat(); }

function declareWinner(who) {

   document.querySelector(".endgame").style.display = "block";
   document.querySelector(".endgame .text").innerText = who;

}

function emptySquares() {

   return origBoard.filter(s => typeof s == 'number');

}

function bestSpot() {

   return minimax(origBoard, aiPlayer).index;

}


function checkTie() {

   if (emptySquares().length == 0) {
       for (var i = 0; i < cells.length; i++) {
           cells[i].style.backgroundColor = "green";
           cells[i].removeEventListener('click', turnClick, false);
       }
       declareWinner("Ничья!");
       return true;
   }
   return false;

updateStat(); }


function minimax(newBoard, player) {

   var availSpots = emptySquares(newBoard);
   if (checkWin(newBoard, player)) {
       return {score: -10};
   } else if (checkWin(newBoard, aiPlayer)) {
       return {score: 10}; 
   } else if (availSpots.length === 0) {
       return {score: 0}
   }
   var moves = [];
   for (let index = 0; index < availSpots.length; index++) {
       var move = {};
       move.index = newBoard[availSpots[index]];
       newBoard[availSpots[index]] = player;
       if (player == aiPlayer) {
           var result = minimax(newBoard, huPlayer);
           move.score = result.score;
       } else {
           var result = minimax(newBoard, aiPlayer);
           move.score = result.score;
       }
       newBoard[availSpots[index]] = move.index;
       moves.push(move);
   }
   var bestMove;
   if (player === aiPlayer) {
       var bestScore = -10000;
       for(var i = 0; i < moves.length; i++) {
           if (moves[i].score > bestScore) {
               bestScore = moves[i].score;
               bestMove = i;
           }
       }
   } else {
       var bestScore = 10000;
       for(var i = 0; i < moves.length; i++) {
           if (moves[i].score < bestScore) {
               bestScore = moves[i].score;
               bestMove = i;
           }
       }
   }
   return moves[bestMove];
}