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

Материал из Department of Theoretical and Applied Mechanics
Перейти к: навигация, поиск
(Визуализация)
(Код программы)
 
(не показана 1 промежуточная версия 1 участника)
Строка 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;
 
 
}
 
}
 +
</syntaxhighlight>
 +
</div>

Текущая версия на 16:30, 15 июня 2021

Описание[править]

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

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

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

Визуализация[править]

Код программы[править]

Код программы на языке JavaScript:
  1 var origBoard;
  2 
  3 
  4 const huPlayer = 'O';
  5 const aiPlayer = 'X';
  6 
  7 const winCombos = [
  8     [0, 1, 2],
  9     [3, 4, 5],
 10     [6, 7, 8],
 11     [0, 3, 6],
 12     [1, 4, 7],
 13     [2, 5, 8],
 14     [0, 4, 8],
 15     [6, 4, 2]
 16 ]
 17 
 18 const cells = document.querySelectorAll('.cell');
 19 startGame();
 20  
 21 
 22 function startGame() {
 23     document.querySelector(".endgame").style.display = "none";
 24     origBoard = Array.from(Array(9).keys());
 25    
 26     for (let index = 0; index < cells.length; index++) {
 27         cells[index].innerText = '';
 28         cells[index].style.removeProperty('background-color');
 29         cells[index].addEventListener('click', turnClick, false);
 30     }
 31 }
 32 
 33 function turnClick(square) {
 34    
 35     if (typeof origBoard[square.target.id] == 'number') {
 36         turn(square.target.id, huPlayer)
 37         if (!checkTie()) turn(bestSpot(), aiPlayer);
 38     }
 39 }
 40 
 41 function turn(squareId, player) {
 42     origBoard[squareId] = player;
 43     document.getElementById(squareId).innerText = player;
 44     let gameWon = checkWin(origBoard, player);
 45     if (gameWon) gameOver(gameWon)
 46 }
 47 
 48 function checkWin(board, player) {
 49     let plays = board.reduce((a, e, i) => 
 50         (e === player) ? a.concat(i) : a, []);
 51     let gameWon = null;
 52     for (let [index, win] of winCombos.entries()) {
 53         if (win.every(elem => plays.indexOf(elem) > -1)) {
 54             gameWon = {index: index, player: player};
 55             break;
 56         }
 57     }
 58 
 59     return gameWon;
 60 	updateStat();
 61 }
 62 
 63 function gameOver(gameWon) {
 64     for (let index of winCombos[gameWon.index]) {
 65         document.getElementById(index).style.backgroundColor =
 66         gameWon.player == huPlayer ? "blue" : "red";
 67     }
 68     for (var i = 0; i < cells.length; i++) {
 69         cells[i].removeEventListener('click', turnClick, false);
 70     }
 71     declareWinner(gameWon.player == huPlayer ? "Вы выиграли!" : "Вы проиграли!")
 72 	updateStat();
 73 }
 74 
 75 function declareWinner(who) {
 76     document.querySelector(".endgame").style.display = "block";
 77     document.querySelector(".endgame .text").innerText = who;
 78 }
 79 
 80 function emptySquares() {
 81     return origBoard.filter(s => typeof s == 'number');
 82 }
 83 
 84 function bestSpot() {
 85    
 86     return minimax(origBoard, aiPlayer).index;
 87 }
 88 
 89 
 90 function checkTie() {
 91     if (emptySquares().length == 0) {
 92         for (var i = 0; i < cells.length; i++) {
 93             cells[i].style.backgroundColor = "green";
 94             cells[i].removeEventListener('click', turnClick, false);
 95         }
 96         declareWinner("Ничья!");
 97         return true;
 98     }
 99     return false;
100 	 updateStat();
101 }
102  
103 
104 
105 function minimax(newBoard, player) {
106     var availSpots = emptySquares(newBoard);
107 
108     if (checkWin(newBoard, player)) {
109         return {score: -10};
110     } else if (checkWin(newBoard, aiPlayer)) {
111         return {score: 10}; 
112     } else if (availSpots.length === 0) {
113         return {score: 0}
114     }
115 
116     var moves = [];
117     for (let index = 0; index < availSpots.length; index++) {
118         var move = {};
119         move.index = newBoard[availSpots[index]];
120         newBoard[availSpots[index]] = player;
121 
122         if (player == aiPlayer) {
123             var result = minimax(newBoard, huPlayer);
124             move.score = result.score;
125         } else {
126             var result = minimax(newBoard, aiPlayer);
127             move.score = result.score;
128         }
129 
130         newBoard[availSpots[index]] = move.index;
131 
132         moves.push(move);
133     }
134 
135     var bestMove;
136     if (player === aiPlayer) {
137         var bestScore = -10000;
138         for(var i = 0; i < moves.length; i++) {
139             if (moves[i].score > bestScore) {
140                 bestScore = moves[i].score;
141                 bestMove = i;
142             }
143         }
144     } else {
145         var bestScore = 10000;
146         for(var i = 0; i < moves.length; i++) {
147             if (moves[i].score < bestScore) {
148                 bestScore = moves[i].score;
149                 bestMove = i;
150             }
151         }
152     }
153 
154     return moves[bestMove];
155 }