Ich habe Probleme bei der Implementierung dieser TicTacToe AI, die I found here. Ich bin relativ neu in Javascript, also bin ich mir sicher, dass ich etwas falsch mit dem Variablen-Scoping mache.TicTacToe Minimax AI in Javascript
Der Code wont im Snippet aber heres my codepen
choices = {
0: '#ul',
1: '#um',
2: '#ur',
3: '#ml',
4: '#mm',
5: '#mr',
6: '#ll',
7: '#lm',
8: '#lr'
}
function getGrid() {
var divs = []
for (var i = 0; i < 9; i++) {
divs.push($(choices[i]).html())
}
return divs
}
function getGame() {
var divs = []
for (var i = 0; i < 9; i++) {
divs.push([$(choices[i]).html(), i])
}
return divs
}
function convertGameToGrid(game) {
var divs = []
for (var i = 0; i < game.length; i++) {
divs.push(game[i][0])
}
return divs
}
function checkGrid(divs) {
var options = [
[divs[0], divs[1], divs[2]],
[divs[3], divs[4], divs[5]],
[divs[6], divs[7], divs[8]],
[divs[0], divs[3], divs[6]],
[divs[1], divs[4], divs[7]],
[divs[2], divs[5], divs[8]],
[divs[0], divs[4], divs[8]],
[divs[2], divs[4], divs[6]]
]
for (var i = 0; i < options.length; i++) {
if (options[i][0] == 'X' && options[i][1] == 'X' && options[i][2] == 'X') {
return 'X'
} else if (options[i][0] == 'O' && options[i][1] == 'O' && options[i][2] == 'O') {
return 'O'
}
}
for (var i = 0; i < 9; i++) {
if (divs[i] == '') {
return false //still moves
}
}
return 'Tie' //no winner and no moves
}
var player = 'O'
var ai = 'X'
$(document).ready(function() {
function playerTurn(i) {
return function() {
var g = getGrid()
var cG = checkGrid(g)
if (!cG) {
if ($(choices[i]).html() == '') {
$(choices[i]).html(player)
var g = getGrid()
var cG = checkGrid(g)
if (cG == player) {
console.log('You win')
} else if (cG == 'Tie') {
console.log('Tie')
} else {
aiTurn()
}
}
}
}
}
for (var i = 0; i < 9; i++) {
$(choices[i]).on('click', playerTurn(i));
}
function score(g, depth) {
var cG = checkGrid(g)
console.log(cG, g)
if (cG == ai) {
return 10 - depth
} else if (cG == player) {
return depth - 10
} else {
return 0
}
}
function minimax(game, depth) {
var g = convertGameToGrid(game)
if (checkGrid(g)) {
return score(g, depth)
}
depth += 1
var scores = []
var moves = []
var availMoves = getAvailMoves(game)
console.log('moves', availMoves)
for (var i = 0; i < availMoves.length; i++) {
var possibleGame = game
if (depth % 2 == 0) {
possibleGame[availMoves[i]][0] = ai
} else {
possibleGame[availMoves[i]][0] = player
}
var m = minimax(possibleGame, depth)
scores.push(m)
console.log('mm: ', depth, i, scores)
moves.push(availMoves[i])
}
//even depths are ai, odd are player
if (depth % 2 == 0) {
var max_score_index = 0
var max_score = -100000000
for (var i = 0; i < scores.length; i++) {
if (scores[i] > max_score) {
max_score_index = i
max_score = scores[i]
}
}
if (depth == 0) { //we need the best move
return moves[max_score_index]
} else { //otherwise this function needs scores
return scores[max_score_index]
}
} else {
var min_score_index = 0
var min_score = 100000000
for (var i = 0; i < scores.length; i++) {
if (scores[i] < min_score) {
min_score_index = i
min_score = scores[i]
}
}
return scores[max_score_index]
}
}
function getAvailMoves(game) {
var moves = []
for (var i = 0; i < game.length; i++) {
if (game[i][0] == '') {
moves.push(game[i][1])
}
}
return moves
}
function aiTurn() {
//Dumb ai
// c = Math.floor(Math.random()*9)
// while ($(choices[c]).html()) {
// c = Math.floor(Math.random()*9)
// }
//new strategy taken from http://neverstopbuilding.com/minimax
console.log('ai')
var c;
game = getGame()
c = minimax(game, -1)
$(choices[c]).html('X')
var g = getGrid()
var cG = checkGrid(g)
if (cG == ai) {
console.log('You lose')
} else if (cG == 'Tie') {
console.log('Tie')
}
}
})
#ttt-box {
position: relative;
height: 304px;
width: 304px;
margin: 30px auto;
background-color: #bbb;
border: solid #000 4px;
border-radius: 20%;
}
#l1,
#l2,
#l3,
#l4 {
position: absolute;
background-color: #000;
}
#l1 {
left: 99px;
width: 3px;
height: 296px;
}
#l2 {
left: 199px;
width: 3px;
height: 296px;
}
#l3 {
top: 99px;
width: 296px;
height: 3px;
}
#l4 {
top: 199px;
width: 296px;
height: 3px;
}
#ul,
#um,
#ur,
#ml,
#mm,
#mr,
#ll,
#lm,
#lr {
cursor: pointer;
position: absolute;
width: 99px;
height: 99px;
font-size: 70px;
text-align: center;
}
#ul {
top: 0;
left: 0;
}
#um {
top: 0;
left: 101px;
}
#ur {
top: 0;
left: 201px;
}
#ml {
top: 101px;
left: 0;
}
#mm {
top: 101px;
left: 101px;
}
#mr {
top: 101px;
left: 201px;
}
#ll {
top: 201px;
left: 0;
}
#lm {
top: 201px;
left: 101px;
}
#lr {
top: 201px;
left: 201px;
}
<body>
<div class="container">
<div id="content">
<div id="ttt-box">
<div id="l1"></div>
<div id="l2"></div>
<div id="l3"></div>
<div id="l4"></div>
<div id="boxes">
<div id="ul"></div>
<div id="um"></div>
<div id="ur"></div>
<div id="ml"></div>
<div id="mm"></div>
<div id="mr"></div>
<div id="ll"></div>
<div id="lm"></div>
<div id="lr"></div>
</div>
</div>
</div>
</div>
</body>
Der Code insbesondere ausgeführt, dass ich denke, ist unter dem Abschnitt zu brechen. Nach dem Zug des ersten Spielers denke ich, dass das console.log 8 ausdrucken soll! Wegen der vielen verschiedenen Wege, die es zu nehmen gilt, druckt es nur acht Mal, als ob es einen einzigen Weg hinunter gegangen wäre.
var availMoves = getAvailMoves(game) console.log('moves',availMoves) for (var i=0;i<availMoves.length;i++) { var possibleGame = game if (depth%2==0) { possibleGame[availMoves[i]][0] = ai } else { possibleGame[availMoves[i]][0] = player } var m = minimax(possibleGame,depth) scores.push(m) console.log('mm: ', depth,i, scores) moves.push(availMoves[i]) }
Edit: Was ist ich bemerkt, dass manchmal die Minimax-Rekursion undefiniert zurückkehrt. Ich habe versucht, herauszufinden, warum das so ist (siehe mein Codepen), aber ich war erfolglos.
Edit2: Es scheint zu undefiniert zurückzukehren, weil es diese Rekursionen vollständig überspringt. Ich kann immer noch keinen Weg finden, das zu beheben.
Danke! Das war definitiv ein Problem. Es wurde mein "undefiniertes" Problem gelöst, aber es funktioniert immer noch nicht richtig, ich werde versuchen, später mehr herauszufinden. Gibt es im Debugger etwas Besseres als nur die Konsole? Mein Code wirft keine Fehler, also gibt es nichts, was ich in der Konsole nachverfolgen kann, aber wenn Sie mehr Ratschläge über den besten Weg haben, JS zu debuggen, nehme ich es gerne an –
Sie bekommen den Debugger sehr ähnlich die Konsole, durch die Entwickler-Tools. Wählen Sie in IE- und FireFox-Entwicklertools die Registerkarte "Debugger" aus. Wählen Sie in den Chrome-Entwicklertools die Registerkarte "Quellen" aus. Dort können Sie Haltepunkte setzen, Variablenwerte untersuchen und den Code durchgehen. Es gibt nichts Besseres als den Code in Aktion zu sehen, um Probleme zu lösen. –
Danke für all deine Hilfe Jack, ich habe alles in Ordnung gebracht, mein anderes Problem war ein Fehler bei der Tiefenkopie und ich brauchte den Debugger nicht, aber ich werde ihn definitiv benutzen –