Reputation: 317
In a project of mine, I have a snippet of some "buggy" code. Function makeMove
updates the global variable board
and function takeMove
resets the board. While the board is changed I push the board value into an array and then reset the board. The problem is that when I access this array, the board values stored inside of it are the values of the reset board when I want the values of the updated board within the array.
I tried shallow copying the updated board and then storing it but that does not work, I am not deep copying the array since I will be using this code for thousands of iterations, and deep copying can take up a lot of performance.
Here is the snippet of code:
let board = [
["C", "H", "B", "Q", "K", "B", "H", "C"],
["P", "P", "P", "P", "P", "P", "P", "P"],
[" ", " ", " ", " ", " ", " ", " ", " "],
[" ", " ", " ", " ", " ", " ", " ", " "],
[" ", " ", " ", " ", " ", " ", " ", " "],
[" ", " ", " ", " ", " ", " ", " ", " "],
["p", "p", "p", "p", "p", "p", "p", "p"],
["c", "h", "b", "q", "k", "b", "h", "c"]
];
function makeMove(from, to) {
let piece = board[from.y][from.x];
board[from.y][from.x] = " ";
pieceBeforeOnToSQ = board[to.y][to.x];
board[to.y][to.x] = piece;
}
function takeMove(from, to) {
let piece = board[to.y][to.x];
board[to.y][to.x] = pieceBeforeOnToSQ;
board[from.y][from.x] = piece;
}
makeMove(position, {
x: index % 8,
y: Math.floor(index / 8)
});
pseudoLegalNodeList.push(board);
takeMove(position, {
x: index % 8,
y: Math.floor(index / 8)
});
Note: The variable pieceBeforeOnToSQ
is global.
If you need any clarifications about the question or code, feel free to ask.
Upvotes: 2
Views: 2421
Reputation: 28722
I would suggest you keep an history array, where you push states in the affected fields of the board were in before the move was made.
When you rewind/undo history, you restore these states by popping them off the array and returning those fields to their original state.
The advantage of this method, versus the method of Titulum is that with this method you also build up a history of made moves, and you can analyze the move later, without having to filter out which moves were especially made from the entire board.
See the example below. You can expand the moves you want by editing the json in the text field and hitting reload
function getOriginalBoard() { return [
["C", "H", "B", "Q", "K", "B", "H", "C"],
["P", "P", "P", "P", "P", "P", "P", "P"],
[" ", " ", " ", " ", " ", " ", " ", " "],
[" ", " ", " ", " ", " ", " ", " ", " "],
[" ", " ", " ", " ", " ", " ", " ", " "],
[" ", " ", " ", " ", " ", " ", " ", " "],
["p", "p", "p", "p", "p", "p", "p", "p"],
["c", "h", "b", "q", "k", "b", "h", "c"]
]
};
let board = getOriginalBoard();
let history = [
];
function makeHistoryEntry(from, to) {
history.push({
from : {
location: from,
value: board[from.y][from.x]
},
to : {
location: to,
value: board[to.y][to.x]
}
});
}
function rewind() {
if(history.length > 0) {
let previousState = history.pop();
let from = previousState.from;
board[from.location.y][from.location.x] = from.value;
let to = previousState.to;
board[to.location.y][to.location.x] = to.value;
renderField();
}
}
function makeMove(from, to) {
makeHistoryEntry(from, to);
let piece = board[from.y][from.x];
board[from.y][from.x] = " ";
board[to.y][to.x] = piece;
renderField();
}
function renderField() {
let play = document.getElementById('play');
let content = [];
content.push('Y -' + ([...Array(board[0].length)].join("---")))
for(let i = 0; i < board.length; i++) {
content.push(i +' : ' + board[i].join(' '));
}
content.push(' -' + ([...Array(board[0].length)].join("---")))
content.push(' X: ' + ([...Array(board[0].length).keys()].join(" ")))
play.innerText = content.join('\n');
}
let movesElement = document.getElementById('moves');
let moves = JSON.parse(movesElement.value);
document.getElementById('next_move').addEventListener('click', (e)=>{
let move = moves.shift();
if(move) {
makeMove(move.from, move.to);
} else { window.alert("No more moves"); }
});
document.getElementById('rewind').addEventListener('click', rewind);
document.getElementById('reload').addEventListener('click', (e) => {
moves = JSON.parse(movesElement.value);
history = [];
board = getOriginalBoard();
renderField();
});
renderField();
#play {
background: #333;
color: #eee;
font-weight: 800;
padding: 12px;
display: inline-block;
}
#moves {
width: 300px;
height: 200px;
}
<pre id="play">
</pre>
<hr>
<button id="reload">reload</button>
<button id="next_move">next move</button>
<button id="rewind">undo</button>
<hr>
<textarea id="moves">
[
{"from":{"x": 7,"y":7}, "to":{"x":6, "y":5}},
{"from":{"x": 0,"y":0}, "to":{"x":0, "y":3}},
{"from":{"x": 1,"y":0}, "to":{"x":1, "y":4}},
{"from":{"x": 0,"y":6}, "to":{"x":0, "y":3}}
]
</textarea>
Upvotes: 2
Reputation: 11476
I propose you implement your code like this:
let moves = [];
function initialState() {
return [
["C", "H", "B", "Q", "K", "B", "H", "C"],
["P", "P", "P", "P", "P", "P", "P", "P"],
[" ", " ", " ", " ", " ", " ", " ", " "],
[" ", " ", " ", " ", " ", " ", " ", " "],
[" ", " ", " ", " ", " ", " ", " ", " "],
[" ", " ", " ", " ", " ", " ", " ", " "],
["p", "p", "p", "p", "p", "p", "p", "p"],
["c", "h", "b", "q", "k", "b", "h", "c"]
];
}
function currentState() {
const board = initialState();
moves.forEach(function (move) {
const currentPiece = board[move.from.y][move.from.x];
board[move.from.y][move.from.x] = " ";
board[move.to.y][move.to.x] = currentPiece;
});
return board;
}
function makeMove(move) {
moves.push(move);
}
function undoMoves(amountOfMoves) {
moves = moves.slice(0, -1 * amountOfMoves);
}
makeMove({
from: {
x: 0,
y: 1
},
to : {
x: 0,
y: 2
}
});
To make a move, a new move
is added to the array of moves
.
To undo a move or multiple moves, you can just call undoMoves(<amount of moves to undo>)
;
Finally, to get an overview of the board, you just call currentState()
;
You can play around with a working example on this JSFiddle.
Upvotes: 1
Reputation: 386624
Why not store the last value with the indices as well, like
[x, y, value]
and keep the last value in the array along with the position.
For going backwards take the values from the end of the array with their position and get a board with certain count of back steps.
Upvotes: 1