井字游戏,带有Minimax和Javascript

加雷斯·珍妮

在FreeCodeCamp上学习时,我尝试使用Javascript制作Tic Tac Toe游戏,而我的第5次尝试仍未能使其成功。我认为我在做正确的事,但是计算机AI仍然在做出非常愚蠢的决定和失败。

这是我的整个AI功能,可以使用控制台日志调用该功能,以查看从AI推荐的操作。但是,当我为已经采取的动作硬编码值并要求下一个动作时,它并没有选择我期望的值。

    /*
 Attempt to inplement a Tic Tac Toe minimax game
 5th attempt, so hopefully this time it works!
 */

var util = require("util");

//These are all the winning square sequences, as string to make various things easier
var validRows = [
    ['00','01','02'],  // left column
    ['10','11','12'],  // middle column
    ['20','21','22'],  // right column
    ['00','10','20'],  // top row
    ['01','11','21'],  // middle row
    ['02','12','22'],  // bottom row
    ['00','11','22'],  // Diag TL to BR
    ['20','11','02']   // Diag BL to TR
];

//Our scoring arrays for evaulating moves
var max1 = ['100','010','001'];
var min1 = ['200','020','002'];
var max2 = ['110','011'];
var min2 = ['220','022'];
var max3 = ['111'];
var min3 = ['222'];

//All the valid squares
var validSquaresFactory = ['00','10','20','01','11','21','02','12','22'];

//Store all the moves somewhere
//var computerMoves = ['10','22'];
//var userMoves = ['00','02'];

//Store all the moves somewhere
var computerMoves = ['11','22'];
var userMoves = ['00','01'];

function Board(minOrMax,computerMoves,userMoves){
    this.computer = computerMoves;
    this.user = userMoves;
    this.minOrMax = minOrMax;
    this.remaining = this.genRemaining();
    this.complete = this.genComplete();
    var results = this.getScore();
    this.score = results[0];
    this.winOrLoose = results[1];
}

Board.prototype.genRemaining = function(){
    //Create an array of all moves taken
    var takenMoves = this.computer.concat(this.user);
    //Calculate all remaining squares
    var validSquares = validSquaresFactory.filter(function(object){
        return takenMoves.indexOf(object) === -1;
    });
    return validSquares;
}

Board.prototype.genComplete = function(){
    return ((this.computer.length + this.user.length) === 9);
}

Board.prototype.flipMinOrMax = function(){
    return (this.minOrMax === 'max') ? 'min' : 'max'
}

Board.prototype.genArrays = function(minOrMax,square){
    var tempUser = this.user.slice(0);
    var tempComputer = this.computer.slice(0);
    if(minOrMax === 'min'){
        tempUser.push(square);
    } else {
        tempComputer.push(square);
    }
    return [tempComputer,tempUser];
}

Board.prototype.generateBoards = function(minOrMax){
    var boards = [];
    var that = this;
    this.remaining.forEach(function(remainingSquare){
        var moves = that.genArrays(minOrMax,remainingSquare);
        boards.push(new Board(minOrMax,moves[0],moves[1]));
    })
    //console.log(boards);
    return boards;
}

Board.prototype.getScore = function(){
    var that = this;
    var winOrLoose = false;
    var returnScore =  validRows.reduce(function(storage,row,index,array){
        var score = row.reduce(function(storage1,square){
            if (that.computer.indexOf(square) !== -1) {
                storage1 += '1';
            } else if (that.user.indexOf(square) !== -1) {
                storage1 += '2';
            } else {
                storage1 += '0';
            }
            return storage1;
        },'')
        var finalScore = 0;
        if(max1.indexOf(score) != -1){
            finalScore = 1;
        } else if(min1.indexOf(score) != -1){
            finalScore = -1;
        } else if(max2.indexOf(score) != -1){
            finalScore = 10;
        } else if(min2.indexOf(score) != -1){
            finalScore = -10;
        } else if(max3.indexOf(score) != -1){
            winOrLoose = true;
            finalScore = 100;
        } else if(min3.indexOf(score) != -1){
            winOrLoose = false;
            finalScore = -100;
        }
        storage.push(finalScore);
        return storage;
    },[])
    var condensedReturnScore =  returnScore.reduce(function(storage,score){
        return storage+score;
    })
    return [condensedReturnScore,winOrLoose];
}


function generateMove(){
    var board = new Board('max',computerMoves,userMoves);
    var scores = [];
    var boards = board.generateBoards('max');
    boards.forEach(function(board){
            scores.push(testMove(board,4));
    });

    scores = scores.map(function(score,index){
        return [board.remaining[index],score];
    });
    var returnValue = scores.reduce(function(storage,score){
        return (score[1].score > storage[1].score) ? score : storage;
    });
    return [returnValue[0],returnValue[1].score];
}


function testMove(masterBoard,count){
    count --;
    var boards = [];
    boards = masterBoard.generateBoards(generateMinOrMax(masterBoard.minOrMax));
    //console.log('/////////Master Board/////////');
    //console.log(masterBoard);
    //console.log(boards);
    //console.log('//////////////////////////////');
    boards = boards.map(function (move) {
        if (move.complete === true || count === 0 || move.winOrLoose === true){
            return move;
        } else {
            var returnScore = testMove(move,count);
            return returnScore;
        }
    });
    returnBoard = boards.reduce(function(storage,board,index,array){
        if(board.minOrMax === 'max'){
            return (board.score > storage.score) ? board : storage;
        } else {
            return (board.score < storage.score) ? board : storage;
        }
    });
    return returnBoard;
}


function generateMinOrMax(minOrMax){
    return (minOrMax === 'max') ? 'min' : 'max'
}

我已经检查了评分功能,从我能看到的结果看,它正在为我尝试的任何动作返回预期的分数,但是由于计算出的可能性之差,很难有效地进行调试。

在这方面的任何帮助/指针将不胜感激,因为我真的用它撞到了砖墙,看不到树木的阿甘等

如果你想使用GUI测试这一点,这是对codepen在- http://codepen.io/gazzer82/pen/yYZmvJ?editors=001

加雷斯·珍妮

因此,当我每天对此表示怀疑之后,我一发布此内容,便立即发现了问题。首先,在我的reduce函数中为minormax使用了错误的变量,因此它未正确翻转,并且未将winOrLoose值正确设置为-100。这是更正的版本。

*
 Attempt to inplement a Tic Tac Toe minimax game
 5th attempt, so hopefully this time it works!
 */

var util = require("util");

//These are all the winning square sequences, as string to make various things easier
var validRows = [
    ['00','01','02'],  // left column
    ['10','11','12'],  // middle column
    ['20','21','22'],  // right column
    ['00','10','20'],  // top row
    ['01','11','21'],  // middle row
    ['02','12','22'],  // bottom row
    ['00','11','22'],  // Diag TL to BR
    ['20','11','02']   // Diag BL to TR
];

//Our scoring arrays for evaulating moves
var max1 = ['100','010','001'];
var min1 = ['200','020','002'];
var max2 = ['110','011'];
var min2 = ['220','022'];
var max3 = ['111'];
var min3 = ['222'];

//All the valid squares
var validSquaresFactory = ['00','10','20','01','11','21','02','12','22'];

//Store all the moves somewhere
//var computerMoves = ['10','22'];
//var userMoves = ['00','02'];

//Store all the moves somewhere
var computerMoves = ['00','20','01'];
var userMoves = ['10','11','02'];
//01,21,22 - 01//

function Board(minOrMax,computerMoves,userMoves){
    this.computer = computerMoves;
    this.user = userMoves;
    this.minOrMax = minOrMax;
    this.remaining = this.genRemaining();
    this.complete = this.genComplete();
    var results = this.getScore();
    this.score = results[0];
    this.winOrLoose = results[1];
}

Board.prototype.genRemaining = function(){
    //Create an array of all moves taken
    var takenMoves = this.computer.concat(this.user);
    //Calculate all remaining squares
    var validSquares = validSquaresFactory.filter(function(object){
        return takenMoves.indexOf(object) === -1;
    });
    return validSquares;
}

Board.prototype.genComplete = function(){
    return ((this.computer.length + this.user.length) === 9);
}

Board.prototype.flipMinOrMax = function(){
    return (this.minOrMax === 'max') ? 'min' : 'max'
}

Board.prototype.genArrays = function(minOrMax,square){
    var tempUser = this.user.slice(0);
    var tempComputer = this.computer.slice(0);
    if(minOrMax === 'min'){
        tempUser.push(square);
    } else {
        tempComputer.push(square);
    }
    return [tempComputer,tempUser];
}

Board.prototype.generateBoards = function(minOrMax){
    var boards = [];
    var that = this;
    this.remaining.forEach(function(remainingSquare){
        var moves = that.genArrays(minOrMax,remainingSquare);
        boards.push(new Board(minOrMax,moves[0],moves[1]));
    })
    //console.log(boards);
    return boards;
}

Board.prototype.getScore = function(){
    var that = this;
    var winOrLoose = false;
    var returnScore =  validRows.reduce(function(storage,row,index,array){
        var score = row.reduce(function(storage1,square){
            if (that.computer.indexOf(square) !== -1) {
                storage1 += '1';
            } else if (that.user.indexOf(square) !== -1) {
                storage1 += '2';
            } else {
                storage1 += '0';
            }
            return storage1;
        },'')
        var finalScore = 0;
        if(max1.indexOf(score) != -1){
            finalScore = 1;
        } else if(min1.indexOf(score) != -1){
            finalScore = -1;
        } else if(max2.indexOf(score) != -1){
            finalScore = 10;
        } else if(min2.indexOf(score) != -1){
            finalScore = -10;
        } else if(max3.indexOf(score) != -1){
            winOrLoose = true;
            finalScore = 100;
        } else if(min3.indexOf(score) != -1){
            winOrLoose = true;
            finalScore = -100;
        }
        storage.push(finalScore);
        return storage;
    },[])
    var condensedReturnScore =  returnScore.reduce(function(storage,score){
        return storage+score;
    })
    return [condensedReturnScore,winOrLoose];
}


function generateMove() {
    var board = new Board('max', computerMoves, userMoves);
    if (board.remaining.length === 1) {
        return [board.remaining[0], 0];
    } else {
        var scores = [];
        var boards = board.generateBoards('max');
        boards.forEach(function (board) {
            scores.push(testMove(board, 4));
        });

        scores = scores.map(function (score, index) {
            return [board.remaining[index], score];
        });
        var returnValue = scores.reduce(function (storage, score) {
            return (score[1].score > storage[1].score) ? score : storage;
        });
        return [returnValue[0], returnValue[1].score];
    }
}


function testMove(masterBoard,count){
    count --;
    var boards = [];
    boards = masterBoard.generateBoards(generateMinOrMax(masterBoard.minOrMax));
    boards = boards.map(function (move) {
        if (move.complete === true || count <= 0 || move.winOrLoose === true){
            return move;
        } else {
            var returnScore = testMove(move,count);
            return returnScore;
        }
    });
    returnBoard = boards.reduce(function(storage,board,index,array){
        if(generateMinOrMax(masterBoard.minOrMax) === 'max'){
            return (board.score > storage.score) ? board : storage;
        } else {
            return (board.score < storage.score) ? board : storage;
        }
    });
    return returnBoard;
}


function generateMinOrMax(minOrMax){
    return (minOrMax === 'max') ? 'min' : 'max'
}

function getScore(user,computer,minOrMax){
    var that = this;
    that.computer = computer;
    that.user = user;
    that.minOrMax = minOrMax;
    var returnScore =  validRows.reduce(function(storage,row,index,array){
        var score = row.reduce(function(storage1,square){
            if (that.computer.indexOf(square) !== -1) {
                storage1 += '1';
            } else if (that.user.indexOf(square) !== -1) {
                storage1 += '2';
            } else {
                storage1 += '0';
            }
            return storage1;
        },'')
        var finalScore = 0;
        if(max1.indexOf(score) != -1){
            finalScore = 1;
        } else if(min1.indexOf(score) != -1){
            finalScore = -1;
        } else if(max2.indexOf(score) != -1){
            finalScore = 10;
        } else if(min2.indexOf(score) != -1){
            finalScore = -10;
        } else if(max3.indexOf(score) != -1){
            finalScore = 100;
        } else if(min3.indexOf(score) != -1){
            finalScore = -100;
        }
        storage.push(finalScore);
        return storage;
    },[])
    var condensedReturnScore =  returnScore.reduce(function(storage,score){
        if(that.minOrMax === 'max'){
            return (score >= storage) ? score : storage;
        } else {
            return (score <= storage) ? score : storage;
        }
    })
    return condensedReturnScore;
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章