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

fix some bug #2

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions html/chessboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
<script type="text/javascript" src="../js/evaluate.js"></script>
<script type="text/javascript" src="../js/AI.js"></script>
<script type="text/javascript" src="../js/AIController.js"></script>
<script type="text/javascript" src="../js/winnercheck.js"></script>
</body>
</html>
118 changes: 73 additions & 45 deletions js/AI.js
Original file line number Diff line number Diff line change
@@ -1,74 +1,102 @@
//alert("this is ai");
const Constants = {
// for judgement convenience
// let wrappedBoard = [];
let StepGenerator = (function(){

let StepGenerator = {};

let Constants = {
ChessBoard:{
ROW_NUM:15,
COL_NUM:15
COL_NUM:15,
},
Chesspiece:{
BLACK: 1,
WHITE: 0,
EMPTY: 'e'
EMPTY: 'e',
BORDER: 'b'
}
};

// for judgement convenience
let wrappedBoard = [];

function wrapBoard(board){
let padding = new Array(Constants.ChessBoard.COL_NUM + 4).fill(
Constants.Chesspiece.EMPTY);
for(let row of board){
row.unshift(Constants.Chesspiece.EMPTY, Constants.Chesspiece.EMPTY);
row.push(Constants.Chesspiece.EMPTY, Constants.Chesspiece.EMPTY);
let UtilMethods = {
// wrappedBoard
isPositionEmpty(board, rowPos, colPos){
return (board[rowPos][colPos] === Constants.Chesspiece.EMPTY);
},
// like this 'b' 'b'
hasOneStepNeighbour(board, color, rowPos, colPos){
return (board[rowPos-1][colPos-1] == color) ||
(board[rowPos-1][colPos] == color) ||
(board[rowPos-1][colPos+1] == color) ||
(board[rowPos][colPos-1] == color) ||
(board[rowPos][colPos+1] == color) ||
(board[rowPos+1][colPos-1] == color) ||
(board[rowPos+1][colPos] == color) ||
(board[rowPos+1][colPos+1] == color);
},
// like this 'b' 'e' 'b'
hasTwoStepNeighbour(board, color, rowPos, colPos){
return (board[rowPos-2][colPos-2] == color) ||
(board[rowPos-2][colPos] == color) ||
(board[rowPos-2][colPos+2] == color) ||
(board[rowPos][colPos-2] == color) ||
(board[rowPos][colPos+2] == color) ||
(board[rowPos+2][colPos-2] == color) ||
(board[rowPos+2][colPos] == color) ||
(board[rowPos+2][colPos+2] == color);
}
return [padding, padding, ...board, padding, padding];
}

// like this 'b' 'b'
function hasOneStepNeighbour(board, color, rowPos, colPos){
return (board[rowPos-1][colPos-1] == color) ||
(board[rowPos-1][colPos] == color) ||
(board[rowPos-1][colPos+1] == color) ||
(board[rowPos][colPos-1] == color) ||
(board[rowPos][colPos+1] == color) ||
(board[rowPos+1][colPos-1] == color) ||
(board[rowPos+1][colPos] == color) ||
(board[rowPos+1][colPos+1] == color);
}

// like this 'b' 'e' 'b'
function hasTwoStepNeighbour(board, color, rowPos, colPos){
return (board[rowPos-2][colPos-2] == color) ||
(board[rowPos-2][colPos] == color) ||
(board[rowPos-2][colPos+2] == color) ||
(board[rowPos][colPos-2] == color) ||
(board[rowPos][colPos+2] == color) ||
(board[rowPos+2][colPos-2] == color) ||
(board[rowPos+2][colPos] == color) ||
(board[rowPos+2][colPos+2] == color);
}
StepGenerator.Constants = Constants;
StepGenerator.UtilMethods = UtilMethods;

StepGenerator.copyAndWrapBoard = (function(){
let padding = new Array(Constants.ChessBoard.COL_NUM + 4).fill(
Constants.Chesspiece.BORDER);

return function(board) {
let res = [padding, padding];
for(let row of board){
res.push([
Constants.Chesspiece.BORDER,
Constants.Chesspiece.BORDER,
...row,
Constants.Chesspiece.BORDER,
Constants.Chesspiece.BORDER
]);
}
res.push(padding, padding);
return res;
};
})();

// return type
// [
// [rowPos, colPos],
// ]

// range: [0,15)
function generateAllNextPossibleMove(wrappedBoard, color){
StepGenerator.generateAllNextPossibleMove = function(wrappedBoard, color){
let oneStepNeighbours = [],
twoStepNeighbours = [];

let rowEnd = Constants.ChessBoard.ROW_NUM + 2,
colEnd = Constants.ChessBoard.COL_NUM + 2;
for(let i = 2; i < rowEnd;i++){
for(let j = 2;j < colEnd;j++){
if(hasOneStepNeighbour(wrappedBoard, color, i, j)){
oneStepNeighbours.push([i-2, j-2]);
}else if(hasTwoStepNeighbour(wrappedBoard, color, i, j)){
twoStepNeighbours.push([i-2, j-2]);

//console.log(wrappedBoard);
for(let i = 2; i < rowEnd; i++){
for(let j = 2; j < colEnd; j++){
if(UtilMethods.isPositionEmpty(wrappedBoard, i, j)){
if(UtilMethods.hasOneStepNeighbour(wrappedBoard, color, i, j)){
oneStepNeighbours.push([i-2, j-2]);
}else if(UtilMethods.hasTwoStepNeighbour(wrappedBoard, color, i, j)){
twoStepNeighbours.push([i-2, j-2]);
}
}
}
}
return [...oneStepNeighbours, ...twoStepNeighbours];
}
}

return StepGenerator;

})();
75 changes: 50 additions & 25 deletions js/AIController.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,29 @@ generateAllNextPossibleMove(wrapBoard(matrix), color) //落子位置函数

*/

const MIN = -4294967295;
const MAX = 4294967295;
const MIN = Number.NEGATIVE_INFINITY;
const MAX = Number.POSITIVE_INFINITY;

var alpha = Number.NEGATIVE_INFINITY,
beta = Number.POSITIVE_INFINITY;

var pointCounter = 0;

//board 当前棋盘, deep 思考步数
var FunctionMaxMin = function(board, color, deep) {
var best = MIN;
var points = generateAllNextPossibleMove(wrapBoard(board), color);
//console.log(board);
var boardTemp = StepGenerator.copyAndWrapBoard(board);
var points = StepGenerator.generateAllNextPossibleMove(boardTemp, color);
var bestPoints = [];
console.log(points);
//console.log(points);
for(var i = 0; i < points.length; i++){
var now_point = points[i];
board[now_point[0]][now_point[1]] = color; //电脑下子的颜色
var value = min(board, Math.abs(color-1), deep-1);
boardTemp[now_point[0]+2][now_point[1]+2] = color; //下子的颜色

var value = min(boardTemp, Math.abs(color-1), alpha, beta, deep-1);

pointCounter++;

if(value == best){
bestPoints.push(now_point);
Expand All @@ -32,51 +41,67 @@ var FunctionMaxMin = function(board, color, deep) {
else{
console.log('ignore');
}
board[now_point[0]][now_point[1]] = 'e';
boardTemp[now_point[0]+2][now_point[1]+2] = 'e';
}
console.log(bestPoints.length);
console.log("搜索节点数:"+pointCounter);
var result = bestPoints[Math.floor(Math.random() * bestPoints.length)];
return result;
if(result == undefined)
return [];
return [result[0]+1, result[1]+1]; //此处是为了方便手动下棋,电脑下棋应当把 +1 部分都去掉,直接return result
}

//max函数
var max = function(board, color, deep){
var v = evaluate(board);
if(deep <= 0)
var max = function(board, color, alpha, beta, deep){
var v = ModuleEvaluate.evaluate(board);
if(deep <= 0 || ModuleWinnerCheck.checkWinnerInAiController(board, color))
return v;

var best = MIN;
var points = generateAllNextPossibleMove(wrapBoard(board), color);
var points = StepGenerator.generateAllNextPossibleMove(board, color);

for( var i = 0; i < points.length; i++){

pointCounter++;

var p = points[i];
board[p[0]][p[1]] = color;
var v = min(board, Math.abs(color-1), deep-1);
board[p[0]][p[1]] = 'e';
board[p[0]+2][p[1]+2] = color;
var v = min(board, Math.abs(color-1), alpha, best > beta? best : beta, deep-1);
board[p[0]+2][p[1]+2] = 'e';
if(v > best)
best = v;
if(v > alpha)
break;
//alpha:上一层(min层)的当前最小值,v:当前层(mx层)的下一层的最小值
/*我方在当前位置的下子,应当使对方紧接着的下子所产生的优势不超过对方上一步下子所产生的优势*/
}

return best;
}
};

//min函数
var min = function(board, color, deep){
var v = evaluate(board);
if(deep <= 0)
var min = function(board, color, alpha, beta, deep){
var v = ModuleEvaluate.evaluate(board);
if(deep <= 0 || ModuleWinnerCheck.checkWinnerInAiController(board, color))
return v;

var best = MAX;
var points = generateAllNextPossibleMove(wrapBoard(board), color);
var points = StepGenerator.generateAllNextPossibleMove(board, color);

for( var i = 0; i < points.length; i++){

pointCounter++;

var p = points[i];
board[p[0]][p[1]] = color;
var v = max(board, Math.abs(color-1), deep-1);
board[p[0]][p[1]] = 'e';
board[p[0]+2][p[1]+2] = color;
var v = max(board, Math.abs(color-1), best < alpha? best : alpha, beta, deep-1);
board[p[0]+2][p[1]+2] = 'e';
if(v < best)
best = v;
if(v < beta)
break;
//beta:上一层(max层)的当前最大值,v:当前层(min层)的下一层的最大值
/*对方在当前位置的下子,应当使我方紧接着的下子所产生的优势超过我方上一步下子所产生的优势*/
}

return best;
}
};
Loading