Help me assign a value to an object in a nested loop.
The code that I need to actually debug looks like this:
// Next states
let nextVal = undefined
let nextBoard = undefined
let next_player_value = undefined
shuffle(Board.rowCols).forEach(c => {
shuffle(Board.rowCols[c]).forEach(r => {
if (board[c][r] === undefined) {
board[c][r] = player_state // let's test the current player moving to this location
next_player_value = this.getMinMaxPlayerValue(!player_state)
let minmax = AI.recurseMinMax(next_player_value, board, depth+1)
let value = minmax[0]
if (((player_state===this.getState()) && (nextVal === undefined || value > nextVal)) || // its the AI, and the value increases
((player_state!==this.getState()) && (nextVal === undefined || value < nextVal))) { // its the player, and the value decreases
nextBoard = Object.assign({},board)
nextVal = value
}
board[c][r] = undefined
}
})
})
return [nextVal, nextBoard]
What happens, if you watch the debugger, is that it correctly assigns different possible board positions to nextBoard
, but when it exits the outer block on the way to the return
statement, nextBoard
changes. It doesn't become undefined
! Instead, it becomes the current Board.state
without any new moves in it (the move that should be there is in the undefined
state like every other empty board space).
player_state
is never undefined, but it is an argument to recurseMinMax
(which is the containing function for this code). It is, in fact, always either true
or false
. I can't replace it easily — I have tried changing the assignment to !!player_state
and Object.assign({}, player_state)
.
This is not an issue with nested loops or closures. Here's a couple of examples:
from the console
> let a; b = {}; keys=[1]; values =[2];
keys.forEach(key => {
values.forEach(value => {
b[key]=value;
a = Object.assign({},b)
})
})
< undefined
> a
< Object {1: 2}
Why doesn't this work:
broken example (with array instead of hash)
let nextBoard = undefined
[0,1,2].forEach(i =>{
[0,1,2].forEach(j =>{
if (board[i][j] == null) {
board[i][j] = player;
var value = recurseMinimax(board, !player)[0];
if ((player && (nextVal == null || value > nextVal)) || (!player && (nextVal == null || value < nextVal))) {
nextBoard = Object.assign({},board)
nextVal = value
}
board[i][j] = null;
}
})
})
This breaks just like in my actual code.
It should be the current Board.state
but with one additional move in it, which is assigned at board[i][j] = player;
.
Now here's the funny thing, I can get this to work pretty easily when we're working with an array like this:
working example (with array instead of nested hash)
[0,1,2].forEach(i =>{
[0,1,2].forEach(j =>{
if (board[i][j] == null) {
board[i][j] = player;
var value = recurseMinimax(board, !player)[0];
if ((player && (nextVal == null || value > nextVal)) || (!player && (nextVal == null || value < nextVal))) {
nextBoard = board.map(function(arr) {
return arr.slice();
});
nextVal = value
}
board[i][j] = null;
}
})
})
This one works just fine.
The problem is, my actual board is not a nested array, it is a nested hash:
Board.state = {};
['a','b','c'].forEach(c => {
Board.state[c]={};
[1,2,3].forEach(r => Board.state[r]=undefined)
});