I am making a simple chess game in Vanilla JS, and am trying to implement an undo move function where, when you press a button, you can take back your move. There are currently two buttons, one to undo your move, and the other to submit your move and pass the game over to your opponent. Simple functionality of most chess games.
Right now the way this works is by assigning a variable to the dynamically generated 8 by 8 board HTML Object before the player makes a move (so let previousState = board
where board
is const board = document.getElementById("board")
). So, before the player even touches the game, the current state of the board
is saved.
Here's the JS:
function drawBoard() {
// Two loops one for even rows one for odd inside of another loop so all rows are drawn
let isWhite = false
let idSwitch = 0
for (let p = 1; p <= 4; p++) {
let oddRow = document.createElement("div")
let evenRow = document.createElement("div")
for (let i = 1; i <= 8; i++) {
idSwitch++
let square = document.createElement("div")
square.classList.add("square")
square.setAttribute("id", `square${idSwitch}`)
if (isWhite) {
isWhite = false
} else {
square.classList.add("black")
isWhite = true
}
oddRow.appendChild(square)
}
board.appendChild(oddRow)
for (let q = 1; q <= 8; q++) {
idSwitch++
let square = document.createElement("div")
square.classList.add("square")
square.setAttribute("id", `square${idSwitch}`)
if (isWhite) {
square.classList.add("black")
isWhite = false
} else {
isWhite = true
}
evenRow.appendChild(square)
}
board.appendChild(evenRow)
}
}
And the HTML:
<section id="board-container">
<div id="board"></div>
</section>
for reference.
Then, when the player makes a move, the variable is supposed to stay exactly the same, so that, if they want to revert to the original, the variable is still there for them.
So, after they move, they have two options. Either pass the move to their opponent, at which point the previousState
variable gets reassigned to the new state of the board (i.e. How the board is after the aforementioned move), or, and herein lies the rub, they can press undo, and the board will revert to how it was before they made their turn (i.e. What the board var
is set to).
Simple right? You assign a var
before they go and then revert the board back to it if they want to take the move back. Otherwise, reset the var
to how the board looks after they go. Rinse and repeat.
The only problem is that, for some reason, the variable changes somewhere between when it is initially defined and after the player moves. What happens is that the player goes, and the variable gets logged to the console. It has the parent element board
and then all the rows and squares, and then all the pieces in their correct posistions in the squares. Then the player moves, and the variable is logged out again, but now that the board element, now that the actual HTML Object, is different, and, for some reason, the variable, which was never reassigned, mirrors how the board now looks. I do not understand why, as it should just stay the same, and not update in tandem with the board. Why does it?
Here's a codepen to check it out yourself: https://codepen.io/jacklouden/pen/qBaLPdo.
Thank you!
Are you familiar with the concepts of variables being by reference or by value? I'm guessing that's your issue.
There is a good SO post on it already.
JavaScript by reference vs. by value
I'll take a direct quote from that post to answer this here.
" Javascript is always pass by value, but when a variable refers to an object (including arrays), the "value" is a reference to the object. Changing the value of a variable never changes the underlying primitive or object, it just points the variable to a new primitive or object. However, changing a property of an object referenced by a variable does change the underlying object."
Try making a copy of your html object and hiding it. I didn't deep dive into what you're doing, but you are doing DOM manipulation, you need to create a new DOM element containing the state. This should give you the reset capability you are looking for.