目錄
第四部分:之前我們很容易就能擊敗AI,所以現在要強化AI的難度
井字棋遊戲
當初在高中的時候課間無聊經常和同學會下井字棋遊戲,突然想做一下有一個智能陪玩的井字棋遊戲。
然後就發現AI算法好難啊╭( ̄▽ ̄)╯╧═╧,放棄......
去網上找找,發現了一個講解比較詳細的井字棋遊戲搭建\(@^0^@)/
做好之後,結果就沒贏過了`(+﹏+)′
ps:算法真的是慘無人道啊
準備的HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" type="text/css" href="css/jingzi.css"/>
</head>
<body>
<table>
<tr>
<td class="cell" id="0"></td>
<td class="cell" id="1"></td>
<td class="cell" id="2"></td>
</tr>
<tr>
<td class="cell" id="3"></td>
<td class="cell" id="4"></td>
<td class="cell" id="5"></td>
</tr>
<tr>
<td class="cell" id="6"></td>
<td class="cell" id="7"></td>
<td class="cell" id="8"></td>
</tr>
</table>
<div class="endgame">
<div class="text"></div>
</div>
<button onclick="startGame()">重新開始</button>
<script src="js/jingzi.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>
準備的CSS:
*{
margin: 0;
padding: 0;
}
td {
border: 2px solid #333;
width: 100px;
height: 100px;
text-align: center;
vertical-align: middle; //垂直
font-family: "微軟雅黑";
font-style:italic;
font-size: 70px;
cursor: pointer; //光標屬性
}
table {
/*margin: 30px auto;*/
position: absolute;
left: 40%;
top: 100px;
border-collapse: collapse;
}
/*去除最外部邊框*/
table tr:first-child td{
border-top: 0;
}
table tr:last-child td{
border-bottom: 0;
}
table tr td:first-child{
border-left: 0;
}
table tr td:last-child{
border-right: 0;
}
.endgame{
display: none;
width: 200px;
height: 120px;
background-color: rgba(205,132,65,0.8);
position: absolute;
left: 40%;
top:180px;
margin-left: 50px;
text-align: center;
border-radius: 5px;
color: white;
font-size: 2em;
}
第一部分點擊出現O的JS代碼:
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";
//設置陣列點 創建9個數組元素,元素的鍵0到8
origBoard = Array.from(Array(9).keys());
// console.log(origBoard);
for (var i = 0; i < cells.length; i++) {
//把文本先設置爲空
cells[i].innerHTML = "";
//刪除屬性知道已經有人贏了
cells[i].style.removeProperty('background-color');
//點擊方塊
cells[i].addEventListener('click',turnClick,false);
}
}
function turnClick(square){
//控制檯點擊日誌
// console.log(square.target.id);
//人類玩家點擊
turn(square.target.id,huPlayer);
}
//參數是方塊ID,播放器
function turn(squareId,player){
//這些板陣列數組將屬於玩家
origBoard[squareId] = player;
document.getElementById(squareId).innerHTML = player;
}
現階段效果:
第二部分:判斷勝利
/*1. Basic setup 一些變量並添加能力
2. Determine winner 添加邏輯,獲勝者並展示
3. Basic AI and winner notificatior 創建一個基本AI
4. Minimax a lgori thm !*/
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";
//設置陣列點 創建9個數組元素,元素的鍵0到8
origBoard = Array.from(Array(9).keys());
// console.log(origBoard);
for (var i = 0; i < cells.length; i++) {
//把文本先設置爲空
cells[i].innerHTML = "";
//刪除屬性知道已經有人贏了
cells[i].style.removeProperty('background-color');
//點擊方塊
cells[i].addEventListener('click',turnClick,false);
}
}
function turnClick(square){
//控制檯點擊日誌
// console.log(square.target.id);
//人類玩家點擊
turn(square.target.id,huPlayer);
}
//參數是方塊ID,播放器
function turn(squareId,player){
//這些板陣列數組將屬於玩家
origBoard[squareId] = player;
document.getElementById(squareId).innerHTML = player;
//讓遊戲進行檢查
var gameWin = checkWin(origBoard,player);
if(gameWin){
gameOver(gameWin);
}
}
/*檢查是否勝利方法*/
function checkWin(board,player){
//使用reduce累加器
let plays = board.reduce((a,e,i)=>
(e===player) ? a.concat(i):a ,[])
let gameWin = null;
//如果是屬於之前winCombos勝利組合
for (let [index,win] of winCombos.entries()) {
if (win.every(Element => plays.indexOf(Element) > -1)){
//現在我們知道是哪一個組合勝利了
gameWin = {index:index,player:player};
break;
}
}
return gameWin;
}
/*遊戲結束*/
function gameOver(gameWin){
for(let index of winCombos[gameWin.index]){
//人類獲勝則爲藍色
document.getElementById(index).style.backgroundColor =
gameWin.player == huPlayer? "blue":"red";
}
/*事件偵聽器刪除單擊,已經結束了,你不能再點擊*/
for (var i = 0; i < cells.length; i++) {
cells[i].removeEventListener('click',turnClick,false);
}
}
現階段結果:
第三部分:簡單的智能AI
/*1. Basic setup 一些變量並添加能力
2. Determine winner 添加邏輯,獲勝者並展示
3. Basic AI and winner notificatior 創建一個基本AI
4. Minimax a lgori thm !*/
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";
//設置陣列點 創建9個數組元素,元素的鍵0到8
origBoard = Array.from(Array(9).keys());
// console.log(origBoard);
for (var i = 0; i < cells.length; i++) {
//把文本先設置爲空
cells[i].innerHTML = "";
//刪除屬性知道已經有人贏了
cells[i].style.removeProperty('background-color');
//點擊方塊
cells[i].addEventListener('click',turnClick,false);
}
}
function turnClick(square){
//控制檯點擊日誌
// console.log(square.target.id);
//記住原來走過的方塊
if(typeof origBoard[square.target.id] == 'number'){
//人類玩家點擊
turn(square.target.id,huPlayer);
//由人類轉向AI玩家
if(!checkTie()){
//電腦玩家將拐彎,走最合適的地方
turn(bestStep(),aiPlayer);
}
}
}
//參數是方塊ID,播放器
function turn(squareId,player){
//這些板陣列數組將屬於玩家
origBoard[squareId] = player;
document.getElementById(squareId).innerHTML = player;
//讓遊戲進行檢查
var gameWin = checkWin(origBoard,player);
if(gameWin){
gameOver(gameWin);
}
}
/*檢查是否勝利方法*/
function checkWin(board,player){
//使用reduce累加器
let plays = board.reduce((a,e,i)=>
(e===player) ? a.concat(i):a ,[])
let gameWin = null;
//如果是屬於之前winCombos勝利組合
for (let [index,win] of winCombos.entries()) {
if (win.every(Element => plays.indexOf(Element) > -1)){
//現在我們知道是哪一個組合勝利了
gameWin = {index:index,player:player};
break;
}
}
return gameWin;
}
/*遊戲結束*/
function gameOver(gameWin){
for(let index of winCombos[gameWin.index]){
//人類獲勝則爲藍色
document.getElementById(index).style.backgroundColor =
gameWin.player == huPlayer? "blue":"red";
}
/*事件偵聽器刪除單擊,已經結束了,你不能再點擊*/
for (var i = 0; i < cells.length; i++) {
cells[i].removeEventListener('click',turnClick,false);
}
declareWinner(gameWin.player == huPlayer ? "你已經獲得了勝利":"對不起,你輸了");
}
function emptySquares(){
//過濾每一個元素,如果元素爲number,返回所有方塊
return origBoard.filter(s => typeof s=='number');
}
/*AI最優步驟*/
function bestStep(){
return emptySquares()[0];
}
//眼睛功能,檢查是否是平局
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("Tie Game");
return true;
}else{
//平局
return false;
}
}
function declareWinner(who){
document.querySelector(".endgame").style.display = 'block';
document.querySelector(".endgame .text").innerHTML = who;
}
現階段結果:
第四部分:之前我們很容易就能擊敗AI,所以現在要強化AI的難度
這裏需要比較強的算法知識
完整JavaScript代碼:
/*1. Basic setup 一些變量並添加能力
2. Determine winner 添加邏輯,獲勝者並展示
3. Basic AI and winner notificatior 創建一個基本AI
4. Minimax a lgori thm !*/
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";
//設置陣列點 創建9個數組元素,元素的鍵0到8
origBoard = Array.from(Array(9).keys());
// console.log(origBoard);
for (var i = 0; i < cells.length; i++) {
//把文本先設置爲空
cells[i].innerHTML = "";
//刪除屬性知道已經有人贏了
cells[i].style.removeProperty('background-color');
//點擊方塊
cells[i].addEventListener('click',turnClick,false);
}
}
function turnClick(square){
//控制檯點擊日誌
// console.log(square.target.id);
//記住原來走過的方塊
if(typeof origBoard[square.target.id] == 'number'){
//人類玩家點擊
turn(square.target.id,huPlayer);
//由人類轉向AI玩家
if(!checkTie()){
//電腦玩家將拐彎,走最合適的地方
turn(bestStep(),aiPlayer);
}
}
}
//參數是方塊ID,播放器
function turn(squareId,player){
//這些板陣列數組將屬於玩家
origBoard[squareId] = player;
document.getElementById(squareId).innerHTML = player;
//讓遊戲進行檢查
var gameWin = checkWin(origBoard,player);
if(gameWin){
gameOver(gameWin);
}
}
/*檢查是否勝利方法*/
function checkWin(board,player){
//使用reduce累加器
let plays = board.reduce((a,e,i)=>
(e===player) ? a.concat(i):a ,[])
let gameWin = null;
//如果是屬於之前winCombos勝利組合
for (let [index,win] of winCombos.entries()) {
if (win.every(Element => plays.indexOf(Element) > -1)){
//現在我們知道是哪一個組合勝利了
gameWin = {index:index,player:player};
break;
}
}
return gameWin;
}
/*遊戲結束*/
function gameOver(gameWin){
for(let index of winCombos[gameWin.index]){
//人類獲勝則爲藍色
document.getElementById(index).style.backgroundColor =
gameWin.player == huPlayer? "blue":"red";
}
/*事件偵聽器刪除單擊,已經結束了,你不能再點擊*/
for (var i = 0; i < cells.length; i++) {
cells[i].removeEventListener('click',turnClick,false);
}
declareWinner(gameWin.player == huPlayer ? "你已經獲得了勝利":"對不起,你輸了");
}
function emptySquares(){
//過濾每一個元素,如果元素爲number,返回所有方塊
return origBoard.filter(s => typeof s=='number');
}
/*AI最優步驟*/
function bestStep(){
//簡單AI
// return emptySquares()[0];
//智能AI
return minmax(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("Tie Game");
return true;
}else{
//平局
return false;
}
}
function declareWinner(who){
document.querySelector(".endgame").style.display = 'block';
document.querySelector(".endgame .text").innerHTML = who;
}
function minmax(newBoard,player){
//找到索引,空方塊功能設置爲a
var availSpots = emptySquares(newBoard);
if(checkWin(newBoard,player)){
return {score:-10};
}else if(checkWin(newBoard,aiPlayer)){
return {score:20};
}else if(availSpots.length === 0){
return {score:0};
}
//之後進行評估
var moves = [];
//收集每個動作時的空白點
for (var i = 0; i < availSpots.length; i++) {
//然後設置空的索引號
var move = {};
move.index = newBoard[availSpots[i]];
newBoard[availSpots[i]] = player;
if( player == aiPlayer){
//存儲對象,包括得分屬性
var result = minmax(newBoard,huPlayer);
move.score = result.score;
}else{
//存儲對象,包括得分屬性
var result = minmax(newBoard,aiPlayer);
move.score = result.score;
}
newBoard[availSpots[i]] = move.index;
moves.push(move);
}
var bestMove;
//如果是AI玩家,以非常低的數字和循環通過
if(player === aiPlayer){
var bestScore = -1000;
for (var i = 0; i < moves.length; i++) {
if(moves[i].score > bestScore){
bestScore = moves[i].score;
bestMove = i;
}
}
}else{
var bestScore = 1000;
for (var i = 0; i < moves.length; i++) {
if(moves[i].score < bestScore){
bestScore = moves[i].score;
bestMove = i;
}
}
}
return moves[bestMove];
}
結果:不多說了,還沒贏過😂
學習來源:JavaScript井字棋遊戲開發與AI算法
代碼鏈接:https://download.csdn.net/download/qq_36171287/12252143
一起學習,一起進步 -.- ,如有錯誤,可以發評論