井字棋是一個很簡單的游戲部凑,通過窮舉露乏,我們輕易的記錄井字棋所有可能的走法。因此我們的AI可以實(shí)現(xiàn)的能力是
先手:盡可能的贏棋
后手:保證不輸棋砚尽,且在玩家出現(xiàn)失誤的情況下贏棋
游戲基本功能
1.有一個下棋(落子)的函數(shù)
2.有一個判斷勝負(fù)的函數(shù)
AI部分
窮舉后施无,可知
作為先手辉词,只要占下一個拐角必孤,玩家在剩下的8個位置中,有7個是必輸?shù)娜鹛伞JO碌囊环N方式敷搪,也最多只是平手。
作為后手則更加簡單幢哨,無論玩家怎么開局赡勘,只要AI走對了前兩步棋,后面就只要專門攔住玩家的棋即可捞镰。
所以需要
1.根據(jù)玩家下子的情況闸与,讓AI下特定的位置(只需兩步)毙替。
2.有一個進(jìn)攻函數(shù)來連成三子取得勝利,用于抓住玩家的失誤或者防止玩家放水践樱。有一個防守函數(shù)來攔住玩家的棋子厂画,使之不能連成三子。
3.有一個隨機(jī)下子函數(shù)來在要平局的情況下填滿棋盤拷邢。
優(yōu)先級:進(jìn)攻>防守>隨機(jī)
** 戳這里試用 **
部分JS代碼:
棋盤數(shù)組袱院,用于判斷勝負(fù)和進(jìn)攻防守函數(shù)。
arr = [[0, 1, 2],[0, 3, 6],[1, 4, 7],[2, 5, 8],[3, 4, 5],[6, 7, 8],[0, 4, 8],[2, 4, 6]]
判斷勝負(fù)函數(shù)(棋子設(shè)置了自定義屬性瞭稼,只要任意一條線上拼接起來為"111"則代表連成一線忽洛,由于玩家不會贏,不需要判斷玩家是否勝利)
function checkSituation() {
if (arr.some(function(item) {
return concatBox(item) == "111";
})) {
result("你輸了 :-(");
} else if ($("button[disabled]").length === 9) {
result("平局");
}
}
進(jìn)攻函數(shù)环肘,防守函數(shù)
// "0"為空子欲虚,"1"為AI棋子,"-1"為玩家棋子
function attack(arr) {
switch (concatBox(arr)) {
case "011":
aiClick(arr[0]);
return true;
case "101":
aiClick(arr[1]);
return true;
case "110":
aiClick(arr[2]);
return true;
}
}
function defense(arr) {
switch (concatBox(arr)) {
case "0-1-1":
aiClick(arr[0]);
return true;
case "-10-1":
aiClick(arr[1]);
return true;
case "-1-10":
aiClick(arr[2]);
return true;
}
}
AI下棋函數(shù)
function aiRound() {
// 連三子
if (arr.some(function(item) {
return attack(item);
})) {
return;
}
// 攔住玩家三子
if (arr.some(function(item) {
return defense(item);
})) {
return;
}
// AI先手
if (AI === "X") {
if (aiSteps === 1) {
switch (true) {
case box(1) == -1 || box(3) == -1:
Xcase = "1";
aiClick(4);
break;
case box(2) == -1 || box(6) == -1:
Xcase = "2";
aiClick(8);
break;
case box(5) == -1 || box(7) == -1:
Xcase = "3";
aiClick(4);
break;
case box(8) == -1:
Xcase = "4";
aiClick(2);
break;
default:
aiClick(8);
break;
}
}
if (aiSteps === 2) {
switch (Xcase) {
case "1":
if (box(3) == -1) { aiClick(2); } else { aiClick(6); }
break;
case "2":
if (box(2) == -1) { aiClick(6); } else { aiClick(2); }
break;
case "3":
if (box(5) == -1) { aiClick(2); } else { aiClick(6); }
break;
case "4":
aiClick(6);
break;
}
}
}
// AI后手
if (AI === "O") {
if (aiSteps === 0) {
if (box(4) == -1) {
aiClick(0);
} else {
aiClick(4);
}
} else if (aiSteps === 1) {
if (parseInt(box(0)) + parseInt(box(2)) + parseInt(box(6)) + parseInt(box(8)) == 2) { aiClick(1); }
else if (twoBox(2, 3) || twoBox(1, 6) || twoBox(1, 3)) { aiClick(0); }
else if (twoBox(0, 5) || twoBox(1, 8) || twoBox(1, 5)) { aiClick(2); }
else if (twoBox(0, 7) || twoBox(3, 8) || twoBox(3, 7)) { aiClick(6); }
else if (twoBox(5, 7) || twoBox(5, 6) || twoBox(2, 7)) { aiClick(8); }
else if (twoBox(0, 8) || twoBox(2, 6)) { aiClick(1); }
else { aiClick(2); }
} else if (aiSteps === 2 || aiSteps === 3) { randomStep(); }
}
}