Javascript 基于minimax算法的Tic-tac-toe
我对极大极小算法感到困惑。我已经花了两天时间,仍然找不到错误。你能看一下我的代码来帮我找到任何bug吗Javascript 基于minimax算法的Tic-tac-toe,javascript,algorithm,angular,tic-tac-toe,minimax,Javascript,Algorithm,Angular,Tic Tac Toe,Minimax,我对极大极小算法感到困惑。我已经花了两天时间,仍然找不到错误。你能看一下我的代码来帮我找到任何bug吗 export default class TicTacToeController { /*@ngInject*/ constructor($scope) { this.board = new Array(3); this.players = { ai: "x", player: "o" }; this.move = {
export default class TicTacToeController {
/*@ngInject*/
constructor($scope) {
this.board = new Array(3);
this.players = {
ai: "x",
player: "o"
};
this.move = {
row: "",
cell: ""
};
this.currentPlayer = this.players.ai;
this.humanMove = false;
this.fillBoard();
this.board[0][0] = "x";
this.board[0][1] = "o";
this.board[0][2] = "x";
this.board[1][0] = "x";
this.board[1][1] = "x";
this.board[1][2] = "o";
this.board[2][0] = "o";
$scope.$watch("ticTac.currentPlayer", player => {
if(player === this.players.player) {
this.humanMove = true;
} else {
this.aiMove(this.board);
}
})
}
fillBoard() {
for (var i = 0; i < 3; i++) {
this.board[i] = new Array(3);
for (var j = 0; j < 3; j++) {
this.board[i][j] = " ";
}
}
}
evaluate(board) {
//check rows
for (var row = 0; row < 3; row++) {
if (board[row][0] === board[row][1] && board[row][1] === board[row][2]) {
if (board[row][0] === this.players.ai) {
return 10;
} else if (board[row][0] === this.players.player) {
return -10;
}
}
}
//check columns
for (var col = 0; col < 3; col++) {
if (board[0][col] === board[1][col] && board[1][col] === board[2][col]) {
if (board[0][col] === this.players.ai) {
return 10;
} else if (board[0][col] === this.players.player) {
return -10;
}
}
}
//check for diagonals
if (board[0][0] === board[1][1] && board[1][1] === board[2][2]) {
if (board[0][0] === this.players.ai) {
return 10;
} else if (board[0][0] === this.players.player) {
return -10;
}
}
if (board[0][2] === board[1][1] && board[1][1] === board[2][0]) {
if (board[0][2] === this.players.ai) {
return 10;
} else if (board[0][2] === this.players.player) {
return -10;
}
}
//if no player won return 0
return 0;
}
minimax(board, isMax) {
var score = this.evaluate(board);
if (score === 10 || score === -10) {
return score;
}
if(!this.isMoveLeft(board)) {
return 0;
}
if (isMax) {
var best = -1000;
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (board[i][j] === " ") {
board[i][j] = this.players.ai;
best = Math.max(best, this.minimax(board, !isMax));
board[i][j] = " ";
}
}
}
return best;
} else {
var best = 1000;
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (board[i][j] === " ") {
board[i][j] = this.players.player;
best = Math.min(best, this.minimax(board, !isMax));
board[i][j] = " ";
}
}
}
return best;
}
}
isMoveLeft(board) {
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (board[i][j] === " ")
return true;
}
}
return false;
}
makeBestMove(board) {
var bestVal = -1000;
this.move.row = -1;
this.move.cell = -1;
for(var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if(board[i][j] === " ") {
board[i][j] === this.currentPlayer;
var moveVal = this.minimax(board, false);
board[i][j] === " ";
if(moveVal > bestVal) {
this.move.row = i;
this.move.cell = j;
bestVal = moveVal;
}
}
}
}
return this.move;
}
aiMove(board) {
var currentMove;
if(!this.isMoveLeft(this.board)) {
return;
}
currentMove = this.makeBestMove(board);
board[currentMove.row][currentMove.cell] = this.currentPlayer;
this.currentPlayer = this.players.player;
}
makeMove(row, cell) {
if(this.board[row][cell] === " ") {
this.board[row][cell] = this.players.player;
}
this.currentPlayer = this.players.ai;
}
}
export default TicTacToeController;
导出默认类控制器{
/*@Nginect*/
构造函数($scope){
this.board=新阵列(3);
这是一个游戏玩家={
ai:“x”,
玩家:“o”
};
此.move={
行:“,
单元格:“
};
this.currentPlayer=this.players.ai;
this.humanMove=false;
这个.fillBoard();
此.board[0][0]=“x”;
此.board[0][1]=“o”;
此.board[0][2]=“x”;
此.board[1][0]=“x”;
此.board[1][1]=“x”;
此.board[1][2]=“o”;
此.board[2][0]=“o”;
$scope.$watch(“ticTac.currentPlayer”,player=>{
if(player==this.players.player){
this.humanMove=true;
}否则{
本.艾莫夫(本.董事会);
}
})
}
填充板(){
对于(变量i=0;i<3;i++){
此.board[i]=新阵列(3);
对于(var j=0;j<3;j++){
此.board[i][j]=“”;
}
}
}
评估(委员会){
//检查行
对于(变量行=0;行<3;行++){
如果(板[行][0]==板[行][1]&板[行][1]==板[行][2]){
if(board[row][0]==this.players.ai){
返回10;
}else if(board[row][0]==this.players.player){
返回-10;
}
}
}
//检查列
for(变量col=0;col<3;col++){
如果(单板[0][col]==单板[1][col]&&board[1][col]==单板[2][col]){
if(board[0][col]==this.players.ai){
返回10;
}else if(棋盘[0][col]==this.players.player){
返回-10;
}
}
}
//检查对角线
如果(单板[0][0]==单板[1][1]&&单板[1][1]==单板[2][2]){
if(board[0][0]==this.players.ai){
返回10;
}else if(棋盘[0][0]==this.players.player){
返回-10;
}
}
如果(单板[0][2]==单板[1][1]&单板[1][1]==单板[2][0]){
if(board[0][2]==this.players.ai){
返回10;
}else if(棋盘[0][2]==this.players.player){
返回-10;
}
}
//如果没有玩家赢了,返回0
返回0;
}
极小极大(单板,isMax){
var得分=本次评估(董事会);
如果(分数===10 | |分数===-10){
返回分数;
}
如果(!this.isMoveLeft(板)){
返回0;
}
if(isMax){
var-best=-1000;
对于(变量i=0;i<3;i++){
对于(var j=0;j<3;j++){
如果(板[i][j]=“”){
board[i][j]=this.players.ai;
best=Math.max(best,this.minimax(board,!isMax));
董事会[i][j]=”;
}
}
}
回报最好;
}否则{
var最佳值=1000;
对于(变量i=0;i<3;i++){
对于(var j=0;j<3;j++){
如果(板[i][j]=“”){
board[i][j]=this.players.player;
best=Math.min(best,this.minimax(board,!isMax));
董事会[i][j]=”;
}
}
}
回报最好;
}
}
isMoveLeft(板){
对于(变量i=0;i<3;i++){
对于(var j=0;j<3;j++){
如果(板[i][j]=“”)
返回true;
}
}
返回false;
}
makeBestMove(板){
var-bestVal=-1000;
this.move.row=-1;
this.move.cell=-1;
对于(变量i=0;i<3;i++){
对于(var j=0;j<3;j++){
如果(板[i][j]=“”){
板[i][j]==此.currentPlayer;
var moveVal=此.minimax(板,假);
板[i][j]=”;
如果(移动值>最佳值){
this.move.row=i;
this.move.cell=j;
bestVal=moveVal;
}
}
}
}
把这个还给我;
}
艾莫夫(董事会){
var-currentMove;
如果(!this.isMoveLeft(this.board)){
返回;
}
currentMove=此.makeBestMove(板);
线路板[currentMove.row][currentMove.cell]=此.currentPlayer;
this.currentPlayer=this.players.player;
}
makeMove(行、单元格){
if(此.board[行][单元格]==“”){
this.board[行][单元格]=this.players.player;
}
this.currentPlayer=this.players.ai;
}
}
导出默认控制器;
启动板看起来:
正如您所看到的,下一个最佳移动应该是(2,2),但minimax算法将值设置为(2,0)
我试图调试,但仍然找不到错误。在您的
makeBestMove
方法中,以下几行:
board[i][j] === this.currentPlayer;
...
board[i][j] === " ";
应使用等于以下的赋值:
board[i][j] = this.currentPlayer;
...
board[i][j] = " ";
=
是一个比较运算符。因此,您正在比较这些值并获得true
,而不做任何更改
目前,由于您在调用minimax
之前未进行分配,因此每次都会返回相同的best
结果