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)
});