Snake game - my snake leaves a trail on every move - javascript

I’m having trouble getting my snake to turn and not leave a trail. Every time my snake turns to go in a different direction it leaves behind pieces of itself. Each piece is a class of “hover” applied to a div block.
I created a function that I hoped would remove the excess pieces whenever a turn was made. My function removeExtra does remove the excess pieces on every turn (removeExtra is called from the moveSnake function each time an arrow is hit), but it also removes every piece of the snake when it turns. So every time I make a turn the snake starts over in that direction and then expands to its current size. A user could play and never run into any of the snake’s body pieces. If I don’t use this function though it leaves little snake turds all over the board!
Can someone help me fix my removeExtra function so that it only removes the class of hover that is not part of the snake body’s array? (var snake) In the removeExtra function I create an array of every hover class (every snake piece). I then use the length of this in the for loop. I have also tried using the difference between this array and the current snake array (var combo) as the second parameter of the for loop, but this doesn’t consistently clear the snake bits when I make turns.
I realize my code sucks. I’ve made this way more complicated than it should be. I should have used a canvas. But I’ve come this far, and I’m hoping there’s some way to salvage the game and never think about snakes again. If there really is no way to fix the mess I’ve made, just let me know, so that I can move on with my life. Thanks!
Here is the Codepen with the game.
Here is the function that's giving me trouble:
removeExtra = function(){
var array = [];
$(".hover").each(function() {
array.push($(this).attr("data"));
});
var len = array.length
var len2 = snake.length
var combo = len-len2
for (var i=0;i<len;i++){
$('*[data="' + array[i] + '"]').removeClass("hover");
}}
Since this is a work-in-progress (surprise!), just refresh the page if you don’t see any blue “food” pieces. Arrows keys will move the snake. You might have to click the board first.
//In the moveSnake function I had to use code from the below link in order to ignore multiple keydown events.
//https://stackoverflow.com/questions/9098901/how-to-disable-repetitive-keydown-in-jquery
$(document).ready(function() {
makebox();
addSnake();
moveSnake();
addBorder();
addFood();
killSnake();
addToSnake();
});
function makebox() {
var size = 30; //24
var boxSize = 20; //12
for (i = 1; i <= size * size; i++) {
$("#container").append("<div class='box'></div>");
};
$("#container").width(size * boxSize + "px");
$(".box").width(boxSize + "");
$(".box").height(boxSize + "px");
$(".box").each(function(i) {
$(this).attr('data', (i + 1));
});
};
function addBorder() {
//find all of the border divs and add a border class to them
$(".box").each(function() {
if ($(this).attr('data') % 25 == 0) {
$(this).addClass("right-border")
} else if ($(this).attr('data') % 25 == 1) {
$(this).addClass("left-border")
} else if ($(this).attr('data') < 25) {
$(this).addClass("top-border")
} else if ($(this).attr('data') >= 877) {
$(this).addClass("bottom-border")
}
})
}
function addSnake() {
var rightTime, leftTime, downTime, upTime;
moveRight = function() {
down = {}
rightTime = setInterval(function() {
for (var i = 0; i < snake.length; i++) {
snake[i]++
$('*[data="' + snake[i] + '"]').addClass("hover moving")
$('*[data="' + (snake[snake.length - 1] - snake.length) + '"]').removeClass("hover");
}
}, 150)
};
moveLeft = function() {
down = {}
leftTime = setInterval(function() { //snake -= 1
for (var i = 0; i < snake.length; i++) {
snake[i] -= 1
$('*[data="' + snake[i] + '"]').addClass("hover");
$('*[data="' + (snake[snake.length - 1] + snake.length) + '"]').removeClass("hover");
}
}, 150)
};
moveDown = function() {
down = {}
downTime = setInterval(function() { //snake += 25
for (var i = 0; i < snake.length; i++) {
snake[i] += 25
$('*[data="' + snake[i] + '"]').addClass("hover");
$('*[data="' + (snake[snake.length - 1] - 25 * snake.length) + '"]').removeClass("hover");
}
}, 150)
};
moveUp = function() {
down = {}
upTime = setInterval(function() { //snake -= 25
for (var i = 0; i < snake.length; i++) {
snake[i] -= 25
$('*[data="' + snake[i] + '"]').addClass("hover");
$('*[data="' + (snake[snake.length - 1] + 25 * snake.length) + '"]').removeClass("hover");
}
}, 150)
};
addTail = function() {
snake.push(snake[snake.length - 1])
}
var snake = [42]
$('*[data="' + snake[0] + '"]').addClass("hover");
var down = {};
removeExtra = function() {
var array = [];
$(".hover").each(function() {
array.unshift($(this).attr("data"));
});
var len = array.length
var len2 = snake.length
var combo = len - len2
for (var i = 0; i < len; i++) {
$('*[data="' + array[i] + '"]').removeClass("hover");
}
}
moveSnake = function() {
$(document).keydown(function(event) {
var keycode = (event.keyCode ? event.keyCode : event.which);
if (keycode == '39') {
if (down['39'] == null) {
window.clearInterval(leftTime);
window.clearInterval(downTime);
window.clearInterval(upTime);
moveRight();
removeExtra();
down['39'] = true;
}
} else if (keycode == '37') {
if (down['37'] == null) {
window.clearInterval(rightTime);
window.clearInterval(downTime);
window.clearInterval(upTime);
moveLeft();
removeExtra();
down['37'] = true;
}
} else if (keycode == '40') {
if (down['40'] == null) {
window.clearInterval(leftTime);
window.clearInterval(rightTime);
window.clearInterval(upTime);
moveDown();
removeExtra();
down['40'] = true;
}
} else if (keycode == '38') {
if (down['38'] == null) {
window.clearInterval(leftTime);
window.clearInterval(rightTime);
window.clearInterval(downTime);
moveUp();
removeExtra();
down['38'] = true;
}
}
});
addToSnake = function() {
var count = 0;
var config = {
attributes: true,
childList: true,
characterData: true
};
$(".box, .food").each(function() {
var target = this;
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if ($(".food").hasClass("hover") == true) {
$(".box").removeClass("food")
addTail();
addFood();
}
});
});
observer.observe(target, config);
});
}
killSnake = function() {
var config = {
attributes: true,
childList: true,
characterData: true,
subtree: true
};
$(".right-border, .left-border, .top-border, .bottom-border").each(function() {
var target = this;
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log("Game over!")
});
});
observer.observe(target, config);
});
}
}
addFood = function() {
var random = Math.floor(Math.random() * (900 - 1 + 1)) + 1;
$('*[data="' + random + '"]').addClass("food")
};
};
.box {
display: inline-block;
border: 2px grey solid;
}
#container {
display: block;
border: 2px black solid;
border-radius: 5px;
font-size: 0;
margin: 10px auto;
}
.hover {
background-color: black;
}
.food {
background-color: blue;
}
.white {
background-color: white;
}
.right-border,
.left-border,
.top-border,
.bottom-border {
background: red;
border: 2px red solid;
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Snake</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="style.css">
<script type="text/javascript" src="script.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
</head>
<body>
<div class="container">
<center>
<h1>Snake</h1>
<div id="container"></div>
</center>
</div>
</body>
</html>

Related

How to stop the drum of the draw machine

I have very simple slot casino game with five rolls and three rows.
I am stuck with a problem that I have not been able to solve for several hours. It's about the roll animation. I have the following assumption:
The roll has at least 10 symbols, only 3 are displayed on the screen (the rest is above the screen - invisible)
When you click on the space, the drawing starts (I managed to do it)
If the last symbol is just above the roller, the position is reset and so on and on - I did the spinning effect of the roller. Let's say it works
The problem that I encountered is that I don't know how to stop the reel after e.g. 3 seconds.
As you can see I tried to use Reel.stop () but it doesn't work.
By the way - is this code correct? Can something be improved in it?
#edit 1
i change method move_reel, but
#edit 2
adding setTimeout to Reel:stop method
/*var FPS = 60;
setInterval(function() {
render();
}, 1000/FPS);
*/
var tile_1 = new Image();
var tile_1_loaded = false;
tile_1.src = "https://i.ibb.co/tsC6G4R/tile-1.png";
var tile_2 = new Image();
var tile_2_loaded = false;
tile_2.src = "https://i.ibb.co/Ns1ZKg2/tile-2.png";
// GAME SETTINGS
var reels = [];
// REEL
function Reel(x, y, tiles) {
this.x = x;
this.y = y;
this.tiles = tiles;
var start = 0;
this.draw = function(){
for(var i = 0; i < this.tiles.length; i++) {
if (this.tiles[i] == 1) {
tile_name = tile_1;
}
else {
tile_name = tile_2;
}
y_offset = this.y + 100 * i + 19;
ctx.drawImage(tile_name, x, y_offset, 100, 100);
}
}
this.update = function(){
if (this.y < 0) {
this.y += 15;
}
else {
this.y = -715;
}
}
this.stop = function(){
setTimeout(() => {
this.y = y;
}, 2000);
}
}
function drawReels() {
ctx.beginPath();
ctx.rect(0, 0, canvas.width, 300);
ctx.clip();
reels.push(new Reel(0, -715, [1,2,2,1,1,2,2,2,1,2,1,1,2,2,1]));
reels.push(new Reel(100, -715, [1,2,1,2,1,2,1,2,1,2,2,1,2,1,1]));
reels.push(new Reel(200, -715, [2,2,1,1,1,1,1,1,2,2,2,1,1,2,1]));
reels.push(new Reel(300, -715, [1,2,1,2,1,2,1,2,1,2,2,1,2,1,1]));
reels.push(new Reel(400, -715, [1,2,1,2,1,2,1,2,1,2,2,1,2,1,1]));
for(var i = 0; i < reels.length; i++) {
reels[i].draw();
}
}
function spin() {
let animate_reel;
animate_reel = requestAnimationFrame(spin);
for(i = 0; i < reels.length; i++) {
move_reel(i);
}
}
var move_reel = function(index) {
reels[index].update();
reels[index].draw();
reels[index].stop();
}
function handleKey(evt) {
if (evt.keyCode == 32) {
spin();
}
}
function init() {
canvas = document.getElementById("slots");
ctx = canvas.getContext("2d");;
window.addEventListener('keydown', handleKey, true);
tile_1.onload = function() {
tile_1_loaded = true;
if (tile_1_loaded && tile_2_loaded) drawReels();
};
tile_2.onload = function() {
tile_2_loaded = true;
if (tile_1_loaded && tile_2_loaded) drawReels();
};
}
init()
* {
margin: 0;
padding: 0;
}
body {
background: #0d012c;
color: #fff;
text-transform: uppercase;
overflow: hidden;
}
canvas {
display: block;
margin: 0;
padding: 0;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Slots</title>
</head>
<body>
<div id="game">
<canvas id="slots" width="1500" height="640"></canvas>
</div>
</body>
</html>
I suggest you use the global setTimeout() method. It sets a timer which executes a function or specified piece of code once the timer expires.
setTimeout(() => {
console.log("This message was Delayed for 3 seconds.");
}, 3000)

How do I get the move function to work in my game?

<!doctype html>
<html>
<head>
<title>Get home</title>
<style>
table {
border-collapse: collapse;
}
td {
border: solid 1px #888;
width: 30px;
height: 30px;
font-family: sans-serif;
font-size: calc(30px/4.0 + 1px);
text-align: center;
}
.cell0 {
background: #88ff99;
}
.cell1 {
background: #116615;
}
.player {
background: #e11;
}
.home {
background: white;
}
.status {
font-size: 15pt;
font-family: Arial;
}
</style>
<script>
// Will be initialised to a 2-dimensional array
var gameBoard = [];
// Size of game
var size = 10;
// Current fuel and supply
var fuel = 20;
var supply = 0;
// Current position of player (start in the bottom-right)
var positionX = size - 1;
var positionY = size - 1;
// Whether we are playing the game
var playing = true;
// Use this function to make a move where x and y represent the direction of
// a move, e.g.
// move(-1, 0) means going left
// move(1, 0) means going right
// move(0, -1) means going up
// move(0, 1) means going down
function move(x, y) {
//
if (positionX + x < size && positionX + x >= 0 &&
positionY + y < size && positionY + y >= 0) {
// Move is within the board
}
}
// Use this function to update the status
function updateStatus() {
document.getElementById("fuel").innerHTML = fuel;
document.getElementById("store").innerHTML = supply;
}
function setup() {
// Set the gameboard to be empty
gameBoard = [];
var board = document.getElementById("board");
for (var i = 0; i < size; i++) {
// Create a new row of the game
var htmlRow = document.createElement("tr");
board.appendChild(htmlRow);
var row = []
for (var j = 0; j < size; j++) {
// Chose a random type of cell
var type = Math.round(Math.random());
var cell = document.createElement("td");
cell.className = "cell" + type;
// Add the cell to the row
htmlRow.appendChild(cell);
row.push(cell);
}
gameBoard.push(row);
}
// Setup the player
gameBoard[size-1][size-1].className = "player";
// Setup the home
gameBoard[0][0].className = "home";
gameBoard[0][0].innerHTML = "HOME";
// Register the listener and update the state
updateStatus();
document.body.addEventListener("keydown", keyEvent);
}
</script>
</head>
<body onLoad="setup();">
<div class="status">Fuel: <span id="fuel"></div>
<div class="status">Store: <span id="store"></div>
<table id="board"></table>
<div class="status" id="outcome"></div>
</body>
</html>
I'm creating a simple game on HTML, and I can't think of how to get the move function to work, while it automatically updates the game and the map, is anyone able to help. I'm new to coding and I genuinely cant fathom what code to put in to make the move function work, whether it be using arrow keys or creating buttons to make the entity move.
Without making too many changes to the way you have things set up, I added a function that will add the "player" class to elements based on "wsad" or arrow key presses.
<!doctype html>
<html>
<head>
<title>Get home</title>
<style>
table {
border-collapse: collapse;
}
td {
border: solid 1px #888;
width: 30px;
height: 30px;
font-family: sans-serif;
font-size: calc(30px/4.0 + 1px);
text-align: center;
}
.cell0 {
background: #88ff99;
}
.cell1 {
background: #116615;
}
.player {
background: #e11;
}
.home {
background: white;
}
.status {
font-size: 15pt;
font-family: Arial;
}
</style>
<script>
// Will be initialised to a 2-dimensional array
var gameBoard = [];
// Size of game
var size = 10;
// Current fuel and supply
var fuel = 20;
var supply = 0;
// Current position of player (start in the bottom-right)
var positionX = size - 1;
var positionY = size - 1;
// Whether we are playing the game
var playing = true;
function move(direction) {
let x = positionX;
let y = positionY;
switch (direction) {
case "left":
x--;
break;
case "right":
x++;
break;
case "up":
y--;
break;
case "down":
y++;
break;
}
const validMove =
x < size &&
x >= 0 &&
y < size &&
y >= 0;
if (!validMove) return console.error(
"What are you trying to do?" + "\n" +
"Break the implied rules of a game?" + "\n" +
"I expect more from you" + "\n" +
"That's a wall you dummy!"
);
positionX = x;
positionY = y;
gameBoard[y][x].classList.add("player");
}
// Use this function to update the status
function updateStatus() {
document.getElementById("fuel").innerText = fuel;
document.getElementById("store").innerText = supply;
}
function keyEvent(e) {
const keyMoveDict = {
"ArrowLeft": "left",
"ArrowRight": "right",
"ArrowUp": "up",
"ArrowDown": "down",
"a": "left",
"d": "right",
"w": "up",
"s": "down",
}
const movement = keyMoveDict[e.key];
if (movement) move(movement);
}
function setup() {
// Set the gameboard to be empty
gameBoard = [];
var board = document.getElementById("board");
for (var i = 0; i < size; i++) {
// Create a new row of the game
var htmlRow = document.createElement("tr");
board.appendChild(htmlRow);
var row = []
for (var j = 0; j < size; j++) {
// Chose a random type of cell
var type = Math.round(Math.random());
var cell = document.createElement("td");
cell.className = "cell" + type;
// Add the cell to the row
htmlRow.appendChild(cell);
row.push(cell);
}
gameBoard.push(row);
}
// Setup the player
gameBoard[size-1][size-1].className = "player";
// Setup the home
gameBoard[0][0].className = "home";
gameBoard[0][0].innerHTML = "HOME";
// Register the listener and update the state
updateStatus();
document.body.addEventListener("keydown", keyEvent);
}
</script>
</head>
<body onLoad="setup();">
<div class="status">Fuel: <span id="fuel"></span></div>
<div class="status">Store: <span id="store"></span></div>
<table id="board"></table>
<div class="status" id="outcome"></div>
</body>
</html>

How do I get my reset function to stop counting moves after it is pressed?

I'm working on a Slider Puzzle and stumbled on a question. I have been trying to make my reset function to stop counting moves on the page when it is pressed but had no luck. My start function starts the counter and ends when the game ends, so how would my counter end counting but still keep the number of moves on display before the user had pressed the reset button?
var gamePiece;
var notify;
var timer;
var spaceY;
var spaceX;
var ticker;
var totalMoves;
function initialize() {
var puzzleArea = document.getElementById("puzzlearea");
gamePiece = puzzleArea.getElementsByTagName("div"); //retrieve element within puzzlearea
for (var i = 0; i < gamePiece.length; i++) //applies features to each puzzle piece
{
gamePiece[i].className = "puzzlepiece"; //setting up the puzzle piece code
gamePiece[i].style.left = (i % 4 * 100) + "px"; //calculates the position for puzzle pieces from the left of the screen
gamePiece[i].style.top = (parseInt(i / 4) * 100) + "px"; //calculates the position for puzzle pieces from the top of the screen
gamePiece[i].onmouseover = function () //applies features when mouse moves over puzzle pieces
{
if (checkMove(parseInt(this.innerHTML))) //checks whenever a move is made
{
this.style.border = "3px solid red"; //changes to red when a puzzle piece is near an empty space
this.style.color = "#006600"; //text color changes to green when a puzzle piece is near an empty space
this.style.textDecoration = "underline"; //underlines the number of the puzzle piece piece
//console.log(totalMoves);
}
}
gamePiece[i].onmouseout = function () //activates whenever mouse moves out of puzzle piece
{
this.style.border = "2px solid black"; //reverts to its original size border
this.style.color = "#000000"; //reverts to original text color
this.style.textDecoration = "none"; //reverts to original text state
}
gamePiece[i].onclick = function () //activates when mouse clicks on a puzzle piece
{
if (checkMove(parseInt(this.innerHTML))) //checks whether or not the puzzle piece can move into an empty space
{
swap(this.innerHTML - 1); //moves into an empty space if true
totalMoves++;
display();
if (finish()) //checks when the all the 15 pieces are in its right space
{
win(); //alerts the player that they have won the game
}
return;
}
}
}
}
spaceX = '300px';
spaceY = '300px';
function checkMove(position) // returns true whenever a piece can be moved into an empty space
{
if (left(spaceX, spaceY) == (position - 1))
{
// totalMoves++;
return true;
}
if (down(spaceX, spaceY) == (position - 1))
{
// totalMoves++;
return true;
}
if (up(spaceX, spaceY) == (position - 1))
{
//totalMoves++;
return true;
}
if (right(spaceX, spaceY) == (position - 1))
{
//totalMoves++;
return true;
}
}
function Notify() //notifies the user
{
notify--; //decrements the value of
if (notify == 0) //if the value reaches the end then
{
var body = document.getElementsByTagName("body"); //retrieves body element in html
body[0].style.backgroundImage = "none"; //reverts to original page background
alert("Winner! ... Press Start and Play Again"); //tells the user that they have won the game
location.href = "15 Slider Puzzle.html"
return;
} else(notify % 2)
{
var body = document.getElementsByTagName("body");
}
timer = setTimeout(Notify, 100); //notifies the user for 1 secs
}
function win() //notifies user that they have won
{
var body = document.getElementsByTagName("body");
notify = 10; //initializes notify variable
timer = setTimeout(Notify, 10);
}
function finish() //checks when the game reaches its end
{
var flag = true;
for (var i = 0; i < gamePiece.length; i++) //for each puzzle piece
{
var top = parseInt(gamePiece[i].style.top);
var left = parseInt(gamePiece[i].style.left);
if (left != (i % 4 * 100) || top != parseInt(i / 4) * 100) //checks if each piece matches its left and top position
{
flag = false;
break; //breaks the loop
}
}
return flag;
}
function left(x, y) //calculates how far to the left a puzzlepiece should position
{
var cordX = parseInt(x);
var cordY = parseInt(y);
if (cordX > 0)
{
for (var i = 0; i < gamePiece.length; i++)
{
if (parseInt(gamePiece[i].style.left) + 100 == cordX && parseInt(gamePiece[i].style.top) == cordY)
{
return i;
}
}
} else
{
return -1;
}
}
function right(x, y) //calculates how far to the right a puzzlepiece should position
{
var cordX = parseInt(x);
var cordY = parseInt(y);
if (cordX < 300)
{
for (var i = 0; i < gamePiece.length; i++) {
if (parseInt(gamePiece[i].style.left) - 100 == cordX && parseInt(gamePiece[i].style.top) == cordY)
{
return i;
}
}
} else
{
return -1;
}
}
function up(x, y) //calculates how far up a puzzlepiece should position
{
var cordX = parseInt(x);
var cordY = parseInt(y);
if (cordY > 0)
{
for (var i = 0; i < gamePiece.length; i++)
{
if (parseInt(gamePiece[i].style.top) + 100 == cordY && parseInt(gamePiece[i].style.left) == cordX)
{
return i;
}
}
} else
{
return -1;
}
}
function down(x, y) //calculates how far down a puzzlepiece should position
{
var cordX = parseInt(x);
var cordY = parseInt(y);
if (cordY < 300)
{
for (var i = 0; i < gamePiece.length; i++)
{
if (parseInt(gamePiece[i].style.top) - 100 == cordY && parseInt(gamePiece[i].style.left) == cordX)
{
return i;
}
}
} else
{
return -1;
}
}
function swap(position) //moves the puzzle piece by switching position with an empty space
{
var temp = gamePiece[position].style.top;
gamePiece[position].style.top = spaceY;
spaceY = temp;
temp = gamePiece[position].style.left;
gamePiece[position].style.left = spaceX;
spaceX = temp;
}
function start() //starts the move counter when the button is pressed
{
totalMoves = 0;
ticker = document.getElementById("Moves");
}
function display() //helps update the display when a move is successfully made
{
ticker.innerHTML = totalMoves;
}
function reset()
{
}
body {
background-color: white;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
}
#controls,
#overall,
#puzzlearea {
width: 400px;
}
#controls {
padding-top: 10px;
text-align: center;
}
h1 {
margin: 10px 0px;
text-align: center;
}
/* Used to center the puzzle. */
#overall {
margin-left: auto;
margin-right: auto;
}
/* The area that holds the 15 puzzle pieces. */
#puzzlearea {
font-size: 32px;
height: 400px;
padding: 0px;
position: relative;
}
/* This class should be applied to each of the 15 puzzle pieces. */
.puzzlepiece {
border: 2px solid black;
height: 96px;
line-height: 96px;
position: absolute;
text-align: center;
vertical-align: middle;
width: 96px;
}
/* This class should be applied to a puzzle piece that can be moved. */
.movablepiece:hover {
border-color: red;
color: #006600;
text-decoration: underline;
}
<!DOCTYPE HTML>
<html>
<title> 15 Slider Puzzle</title>
<link rel="stylesheet" type="text/css" href="15 Slider.css" />
<script src="15 Slider.js" type="text/javascript"></script>
<head>
<body onload = "initialize()">
<h1>Slider Puzzle</h1>
<div id="overall">
<div id="puzzlearea">
<!-- the following are the fifteen puzzle pieces -->
<div>1</div> <div>2</div> <div>3</div> <div>4</div>
<div>5</div> <div>6</div> <div>7</div> <div>8</div>
<div>9</div> <div>10</div> <div>11</div> <div>12</div>
<div>13</div> <div>14</div> <div>15</div>
</div>
<div id="controls"></div>
<button onclick = "start();">Start</button>
<button onclick = "reset();">Reset</button>
<br>
Number Of Moves: <span id="Moves">0</span>
</div><!--content-->
<br>
</head>
</html>
I have added a var hasStopped which will only add moves if its false and if reset is clicked it will set to true which means the swap will still run but moves will not counted as well.
Also, when you clicked start() again the totalMoves will start counting the moves again. If you want that too.
Here is working demo for you: https://jsfiddle.net/usmanmunir/cs4d3qfm/16/
var gamePiece;
var notify;
var timer;
var spaceY;
var spaceX;
var ticker;
var totalMoves;
var hasStopped = false;
function initialize() {
var puzzleArea = document.getElementById("puzzlearea");
gamePiece = puzzleArea.getElementsByTagName("div"); //retrieve element within puzzlearea
for (var i = 0; i < gamePiece.length; i++) //applies features to each puzzle piece
{
gamePiece[i].className = "puzzlepiece"; //setting up the puzzle piece code
gamePiece[i].style.left = (i % 4 * 100) + "px"; //calculates the position for puzzle pieces from the left of the screen
gamePiece[i].style.top = (parseInt(i / 4) * 100) + "px"; //calculates the position for puzzle pieces from the top of the screen
gamePiece[i].onmouseover = function() //applies features when mouse moves over puzzle pieces
{
if (checkMove(parseInt(this.innerHTML))) //checks whenever a move is made
{
this.style.border = "3px solid red"; //changes to red when a puzzle piece is near an empty space
this.style.color = "#006600"; //text color changes to green when a puzzle piece is near an empty space
this.style.textDecoration = "underline"; //underlines the number of the puzzle piece piece
//console.log(totalMoves);
}
}
gamePiece[i].onmouseout = function() //activates whenever mouse moves out of puzzle piece
{
this.style.border = "2px solid black"; //reverts to its original size border
this.style.color = "#000000"; //reverts to original text color
this.style.textDecoration = "none"; //reverts to original text state
}
gamePiece[i].onclick = function() //activates when mouse clicks on a puzzle piece
{
if (checkMove(parseInt(this.innerHTML))) //checks whether or not the puzzle piece can move into an empty space
{
swap(this.innerHTML - 1); //moves into an empty space if true
if (!hasStopped) {
totalMoves++;
display();
}
if (finish()) //checks when the all the 15 pieces are in its right space
{
win(); //alerts the player that they have won the game
}
return;
}
}
}
}
spaceX = '300px';
spaceY = '300px';
function checkMove(position) // returns true whenever a piece can be moved into an empty space
{
if (left(spaceX, spaceY) == (position - 1))
{
// totalMoves++;
return true;
}
if (down(spaceX, spaceY) == (position - 1))
{
// totalMoves++;
return true;
}
if (up(spaceX, spaceY) == (position - 1))
{
//totalMoves++;
return true;
}
if (right(spaceX, spaceY) == (position - 1))
{
//totalMoves++;
return true;
}
}
function Notify() //notifies the user
{
notify--; //decrements the value of
if (notify == 0) //if the value reaches the end then
{
var body = document.getElementsByTagName("body"); //retrieves body element in html
body[0].style.backgroundImage = "none"; //reverts to original page background
alert("Winner! ... Press Start and Play Again"); //tells the user that they have won the game
location.href = "15 Slider Puzzle.html"
return;
} else(notify % 2)
{
var body = document.getElementsByTagName("body");
}
timer = setTimeout(Notify, 100); //notifies the user for 1 secs
}
function win() //notifies user that they have won
{
var body = document.getElementsByTagName("body");
notify = 10; //initializes notify variable
timer = setTimeout(Notify, 10);
}
function finish() //checks when the game reaches its end
{
var flag = true;
for (var i = 0; i < gamePiece.length; i++) //for each puzzle piece
{
var top = parseInt(gamePiece[i].style.top);
var left = parseInt(gamePiece[i].style.left);
if (left != (i % 4 * 100) || top != parseInt(i / 4) * 100) //checks if each piece matches its left and top position
{
flag = false;
break; //breaks the loop
}
}
return flag;
}
function left(x, y) //calculates how far to the left a puzzlepiece should position
{
var cordX = parseInt(x);
var cordY = parseInt(y);
if (cordX > 0)
{
for (var i = 0; i < gamePiece.length; i++)
{
if (parseInt(gamePiece[i].style.left) + 100 == cordX && parseInt(gamePiece[i].style.top) == cordY)
{
return i;
}
}
} else
{
return -1;
}
}
function right(x, y) //calculates how far to the right a puzzlepiece should position
{
var cordX = parseInt(x);
var cordY = parseInt(y);
if (cordX < 300)
{
for (var i = 0; i < gamePiece.length; i++) {
if (parseInt(gamePiece[i].style.left) - 100 == cordX && parseInt(gamePiece[i].style.top) == cordY)
{
return i;
}
}
} else
{
return -1;
}
}
function up(x, y) //calculates how far up a puzzlepiece should position
{
var cordX = parseInt(x);
var cordY = parseInt(y);
if (cordY > 0)
{
for (var i = 0; i < gamePiece.length; i++)
{
if (parseInt(gamePiece[i].style.top) + 100 == cordY && parseInt(gamePiece[i].style.left) == cordX)
{
return i;
}
}
} else
{
return -1;
}
}
function down(x, y) //calculates how far down a puzzlepiece should position
{
var cordX = parseInt(x);
var cordY = parseInt(y);
if (cordY < 300)
{
for (var i = 0; i < gamePiece.length; i++)
{
if (parseInt(gamePiece[i].style.top) - 100 == cordY && parseInt(gamePiece[i].style.left) == cordX)
{
return i;
}
}
} else
{
return -1;
}
}
function swap(position) //moves the puzzle piece by switching position with an empty space
{
var temp = gamePiece[position].style.top;
gamePiece[position].style.top = spaceY;
spaceY = temp;
temp = gamePiece[position].style.left;
gamePiece[position].style.left = spaceX;
spaceX = temp;
}
function start() //starts the move counter when the button is pressed
{
totalMoves = 0;
hasStopped = false
ticker = document.getElementById("Moves");
}
function display() //helps update the display when a move is successfully made
{
ticker.innerHTML = totalMoves;
}
function reset() {
hasStopped = true
}
body {
background-color: white;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
}
#controls,
#overall,
#puzzlearea {
width: 400px;
}
#controls {
padding-top: 10px;
text-align: center;
}
h1 {
margin: 10px 0px;
text-align: center;
}
/* Used to center the puzzle. */
#overall {
margin-left: auto;
margin-right: auto;
}
/* The area that holds the 15 puzzle pieces. */
#puzzlearea {
font-size: 32px;
height: 400px;
padding: 0px;
position: relative;
}
/* This class should be applied to each of the 15 puzzle pieces. */
.puzzlepiece {
border: 2px solid black;
height: 96px;
line-height: 96px;
position: absolute;
text-align: center;
vertical-align: middle;
width: 96px;
}
/* This class should be applied to a puzzle piece that can be moved. */
.movablepiece:hover {
border-color: red;
color: #006600;
text-decoration: underline;
}
<!DOCTYPE HTML>
<html>
<title> 15 Slider Puzzle</title>
<link rel="stylesheet" type="text/css" href="15 Slider.css" />
<script src="15 Slider.js" type="text/javascript"></script>
<head>
<body onload="initialize()">
<h1>Slider Puzzle</h1>
<div id="overall">
<div id="puzzlearea">
<!-- the following are the fifteen puzzle pieces -->
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
<div>11</div>
<div>12</div>
<div>13</div>
<div>14</div>
<div>15</div>
</div>
<div id="controls"></div>
<button onclick="start();">Start</button>
<button onclick="reset();">Reset</button>
<br> Number Of Moves: <span id="Moves">0</span>
</div>
<!--content-->
<br>
</head>
</html>
Use this as a demo https://jsfiddle.net/ugonnaezema/0gpeo1sj/2/
Initialize a new variable to check if the reset button has been pressed
var isResetPressed = false;
Set isResetPressed to false when initialize is called, then check if the reset button is pressed
function initialize() {
var puzzleArea = document.getElementById("puzzlearea");
gamePiece = puzzleArea.getElementsByTagName("div"); //retrieve element within puzzlearea
isResetPressed = false;
for (var i = 0; i < gamePiece.length; i++) //applies features to each puzzle piece
{
...
gamePiece[i].onclick = function () //activates when mouse clicks on a puzzle piece
{
if (checkMove(parseInt(this.innerHTML))) //checks whether or not the puzzle piece can move into an empty space
{
swap(this.innerHTML - 1); //moves into an empty space if true
if (isResetPressed)
{
totalMoves = totalMoves;
}
else
{
totalMoves++;
}
display();
if (finish()) //checks when the all the 15 pieces are in its right space
{
win(); //alerts the player that they have won the game
}
return;
}
}
...
Set up the reset function as follows
function reset()
{
display();
isResetPressed = true;
}
Ok, in your reset function, pop the current moves into a temp variable and display that, then totalMovves = 0;
You could either manually change the display to use the old value:
ticker.innerHTML = totalMoves;
totalMoves = 0;
But I would do this by altering the Display function to look like below:
function display(var moves = totalMoves) //helps update the display when a move is successfully made
{
ticker.innerHTML = moves;
}
Or you could simply change the order of your commands
function reset(){
display();
totalMoves = 0;
}

Unable to update image position in css using javascript

There are some runner(animation-image) in my program which move from position x to y when clicked on start button, i want to add a (reverse)button on completion that when clicked on that the image moves from y to x.
Here is the link of my js-fiddle: https://jsfiddle.net/o6egL4qr/
I have added the reverse button but when clicked on that the image doesn't move at all.
class raceManager {
raceCount = 0;
races = [];
addRace() {
var mainContainer = document.getElementById('mainContainer');
mainContainer.appendChild(document.createElement('br'));
var race = new raceClass(this.raceCount);
this.races.push(race);
this.raceCount++;
}
}
class raceClass {
runners = [];
count;
runnerCount = 0;
raceDiv = document.createElement('div');
raceNum = document.createElement('div');
startRaceButton = document.createElement('input');
addRunnerButton = document.createElement('input');
revRaceButton = document.createElement('input');
tableDiv = document.createElement('div');
tableNum = document.createElement('div');
startInterval;
startTime;
revStartTime;
reverseInterval;
constructor(number) {
// store the race no.
this.count = number;
// delcare the race div id
this.raceNum.id = 'raceNum' + this.count;
// delcare the table div id
this.tableNum.id = 'tableNum' + this.count;
// Add raceDiv to the race
document.getElementById('races').appendChild(this.raceDiv);
// Add tableDiv to the race
document.getElementById('tables').appendChild(this.tableDiv);
this.applyDivProperty();
this.initializeButtons();
}
applyDivProperty() {
// apply properties to the tableNum
this.tableNum.style.display = "inline-block";
// apply properties to the raceDiv
this.raceDiv.id = "Race" + this.count;
document.getElementById(this.raceDiv.id).classList.add("raceDivClass");
this.raceDiv.appendChild(this.raceNum);
document.getElementById(this.raceNum.id).innerHTML = '<p>Race: ' + this.count + '</p>';
// append the add race button
this.raceDiv.appendChild(this.addRunnerButton);
// apply properties to the tableDiv
this.tableDiv.id = "Table" + this.count;
document.getElementById(this.tableDiv.id).classList.add("tableClass");
this.tableDiv.appendChild(this.tableNum);
document.getElementById(this.tableNum.id).innerHTML = '<p>Table: ' + this.count + '</p>';
}
initializeButtons() {
// initialize add runner button
this.addRunnerButton.type = 'Button';
this.addRunnerButton.value = 'Add Runner';
this.addRunnerButton.id = 'AddRunner' + this.count;
this.addRunnerButton.onclick = this.addRunner.bind(this);
// initialize start race buttton
this.startRaceButton.type = 'Button';
this.startRaceButton.value = 'Start Race';
this.startRaceButton.id = "startRaceButton" + this.count;
this.startRaceButton.onclick = this.startRace.bind(this);
// initialize reverse race buttton
this.revRaceButton.type = 'Button';
this.revRaceButton.value = 'Reverse Race';
this.revRaceButton.id = "revRaceButton" + this.count;
this.revRaceButton.onclick = this.revRace.bind(this);
}
addRunner() {
var track = new Runner(this); //Initialize the runner object
this.runners.push(track); //Store the runner object in runners array of Race class
if (this.runnerCount > 0) {
// append the start race button
this.raceDiv.appendChild(this.startRaceButton);
}
this.runnerCount++;
}
startRace() {
this.startTime = Date.now();
this.startInterval = setInterval(() => {
this.runners.forEach(function(element) {
element.animate();
});
document.getElementById(this.startRaceButton.id).disabled = "true";
document.getElementById(this.addRunnerButton.id).disabled = "true";
}, 50);
}
stop() {
clearInterval(this.startInterval);
// append the start race button
this.raceDiv.appendChild(this.revRaceButton);
}
revRace() {
this.revStartTime = Date.now();
this.reverseInterval = setInterval(() => {
this.runners.forEach(function(element) {
element.animateReverse();
});
document.getElementById(this.revRaceButton.id).disabled = "true";
}, 50);
}
stopRev() {
clearInterval(this.reverseInterval);
}
}
class Runner {
count = 0;
parent;
track;
sprite;
timeTaken;
trackWidth;
element;
speed;
table;
printCount = 1;
stepCount = 1;
trackNum;
tbl;
lastStep;
constructor(race) {
// initialize the divs
this.parent = race;
this.track = document.createElement('div');
this.sprite = document.createElement('div');
this.table = document.createElement('table');
// assigns #id to table and track corresponding with parent div.
this.table.id = race.tableNum.id + '_Table_' + this.parent.runnerCount;
this.track.id = race.raceNum.id + '_Track_' + this.parent.runnerCount;
this.createUI();
this.timeTaken = ((Math.random() * 5) + 3);
this.speed = this.trackWidth / (this.timeTaken * 1000);
console.log(this.trackWidth, this.timeTaken);
console.log(this.timeTaken * 100);
}
createUI() {
this.count = this.parent.runnerCount;
this.createTable();
this.createTrack();
this.createSprite();
}
createTable() {
var parentDiv1 = document.getElementById(this.parent.tableNum.id);
parentDiv1.appendChild(this.table);
this.table.setAttribute = "border"
this.table.border = "1";
document.getElementById(this.table.id).classList.add("tableClass");
this.tbl = document.getElementById(this.table.id);
this.addRow("Track " + (this.count + 1), "");
this.addRow("Time", "Distance");
}
addCell(tr, val) {
var td = document.createElement('td');
td.innerHTML = val;
tr.appendChild(td)
}
addRow(val_1, val_2) {
var tr = document.createElement('tr');
this.addCell(tr, val_1);
this.addCell(tr, val_2);
this.tbl.appendChild(tr)
}
createTrack() {
var parentDiv = document.getElementById(this.parent.raceNum.id);
parentDiv.appendChild(this.track);
this.track.appendChild(this.sprite);
document.getElementById(this.track.id).classList.add("trackClass");
this.trackWidth = this.track.getBoundingClientRect().width;
}
createSprite() {
this.sprite.id = this.track.id + "_Runner";
document.getElementById(this.sprite.id).classList.add("spriteClass");
this.element = document.getElementById(this.sprite.id);
}
animate() {
// declare time variables
var timeNow = Date.now();
var timespent = timeNow - this.parent.startTime;
var diff = Math.floor(this.timeTaken * 100);
// step is position of sprite.
var step = timespent * this.speed;
// Print table for all tracks with 10 laps.
if ((Math.round(timespent / 50) * 50) == (Math.round(((diff - 25) * this.printCount) / 50) * 50)) {
this.addRow(this.printCount + ": " + timespent, (Math.floor(step)));
this.printCount++;
}
// check condition to stop
if (step > this.trackWidth - 23) {
document.getElementById(this.parent.raceNum.id).innerHTML += 'Winner: Runner' + (this.count + 1);
this.parent.stop();
}
this.element.style.left = step + 'px';
// ------------sprite animation----------------
// start position for the image slicer
var position = (3 - (Math.floor(step / 6.5) % 4)) * 25;
// we use the ES6 template literal to insert the variable "position"
this.element.style.backgroundPosition = `${position}px 0px`;
}
animateReverse() {
// declare time variables
var timeNow = Date.now();
var timespent = timeNow - this.parent.revStartTime;
var diff = Math.floor(this.timeTaken * 100);
console.log(this.count + " position of step " + this.element.style.left);
while (this.stepCount < 2) {
this.lastStep = parseFloat(this.element.style.left);
this.stepCount++;
}
console.log(this.count + " this is lastStep " + this.lastStep);
// step is position of sprite.
var step = this.lastStep - (this.speed * timespent);
// Print table for all tracks with 10 laps.
if ((Math.round(timespent / 50) * 50) == (Math.round(((diff - 25) * this.printCount) / 50) * 50)) {
this.addRow(this.printCount + ": " + timespent, (Math.floor(step)));
this.printCount++;
}
// check condition to stop
if (step < 25) {
document.getElementById(this.parent.raceNum.id).innerHTML += 'Winner: Runner' + (this.count + 1);
this.parent.stopRev();
}
this.element.style.left = step + 'px';
// ------------sprite animation----------------
// start position for the image slicer
//var position = (3 - (Math.floor(step / 6.5) % 4)) * 25;
//this.element.style.backgroundPosition = position + 'px 0px';
}
}
manager = new raceManager();
#tableContainer {
float: left;
}
#addRaces {
text-align: center;
}
.raceDivClass {
margin: 1% auto;
width: 60%;
text-align: center;
border: 1px solid;
}
.tableClass {
text-align: center;
border: 1px solid;
margin: 5px;
float: left;
}
.trackClass {
background-color: black;
height: 30px;
width: 98%;
margin: 1%;
position: relative;
}
.spriteClass {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGgAAAAeCAYAAADAZ1t9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAASwSURBVGhD7Zq/axRBFMfv9u4MxATUSgsVm3QWigYbexuxUkiaKIqNoIUiwRSJoJLCxpSCaJoEYimo/4AgQVRIZxdBEIREYwzc5X74vndvlrm5mdnZ3dm9oPnAsDubu52Z93373pvNFQsJOXO9NUKHsU4vZPH90+IXPt/FA2kEmqbDTKcX8pza7K5I/vAtEJghge7zeSrwlDYbtYlmfWuILxWC8uBmUNoz/784wY4WaPRq9SGJcY+7Mt7GEOzUkB0pkGHi4Ci1K53TEK8h7tTE+pPywL6b3JXJQqBcQ7arQwR87AE34ElPUsPE1ZapODsErFHnnD7AfVWb9oylFYjVFcKoQuQC5kD55hB3Qxrbf17RYbHT+/fpCXGSOEmEaYcevofwhkRxXM0/VCi8azXr3+q1Xw8+LRxZ4cte4PneoHaQ2iVck0gVThVbyOhSRM9YOoFMyR9eW6KmLkAGYW6Vmjx47AViUfSkPC5V9p7nS23q1Z9zH+b33+KuF9iAOocUa0lcKFjubQJ2h51D5zbmIAVM9gc1mzgAE0kdFlFaq+JkQYQBV+FYOYoDGy9Tw3dgQ7QxnUBQUHxAtJfUhqllDhbWam4f525mJDCgMynufZFa13d6BILHsOeEjS6PUjMNtsRHFXgExI2V0PN6egiEkTzFMdlJgM/3zMd1H2Tzhjlqa53TLhLFbsvep9Cob70uFsuffbxJoHWZcq1A5CCZyDUZ7gtxotKDCsafdRHIZSFe9j9wBl1xoIJSuxhUVpIK5eB0JiILHo29EouDtVmLBF4IKjIbWOQkfzYVruENn+ESXFe+upBJeDMQVfWiyXQ5fFQV57oQLyLJL0VlsAfi06yJyhMuIOci7Efdqy0ENzxxonVFI22IY0NDHN1mykaX+nHAmKbw1qhtLLVaze8U1o6Jv9OmdaEYlI1lsLQGGVGwmMKbKZ8KXHIQxnUJn062CgVSFmQTRjySpr8n2nlb3lxTztl8W6+u3x0YOlylrpij1Vi0Hl3uxNx/U9MWIYSPtwZxclukSG2B4qreOTV+3skzBBgbuafVrJ0sVYbO8eUe4r5FMAgEbEnbSSC2l/p0grgRB1jHDGKqjt019kkwvoid4okS4D7O+Qji4MmxiQMonI2cGP/qYwMbt6LSAXFEzpCbyYaJcxuKBAwWJQ5EwATCTScLBeUhVGKRTIWBCgQsVYavcdcF8UZEnVveYPwXfIwNBMJCdF/GNeEZCFnahMzX1A0dgEi6MJALigP1SyiMCdu9wZH7sZBzkGpM5zcBljAZGdNPX964UAhKt0vlwbN8SQs2p/Xq2lTSfzU4hvK0OUily4b0PV1etI4Z+SbBFYMBrIPjO1QuT1N+GedLbVC1FYM9Hyk31fgScHYYE5JhD1Dz/r+fKPoqEJAMILAa1VRaU+HwaPnZwBR3vWJwJCDCUSonsKERKHJMrwLFAYbSbUwRyujanawMZfBikPXTEzvCgKhXPZmhe+/W2ZCuTWXpxQbgyWGFmhGILLb8p6V/AmnKa+Qd3783cCDz0JaGvgmEX4jyaRu8W6N8NM/dPGlvvvk8T5ye2r7mIIQ5PEl5/pyXc4FzIeOLZOMWCn8Bh1eBvOSZzIIAAAAASUVORK5CYII=');
position: absolute;
height: 30px;
width: 25px;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="mainContainer">
<div id="addRaces">
<input type="Button" value="Add Race" onclick="manager.addRace()">
</div>
<div id="races">
</div>
<br>
</div>
<div id="tableContainer">
<div id="tables"></div>
</div>
</body>
</html>
I expect it to move from y to x after clicking the reverse button, but it is not moving.
When you run the reverse function the elements are no longer referencing the dom elements.
I am actually not sure why that is, maybe someone else can chime in.
Anyway, this will fix your problem:
Replace this.element.style.left = step + 'px';
With: document.getElementById(this.element.id).style.left = step + 'px';

.forEach method applying update to all items in array instead of individual item

I'm making a small exercise for some students of mine where I am automating a kind of 10 pin bowling game I have put it into a JsBin here https://jsbin.com/qilizo/edit?html,js,output. I don't know whether I am tired, stupid or it's just because I am working on a national holiday but something has me puzzled. When i start the game I prompt the user to set up a number of desired players. This automatically produces an object array of Players like so:
[{score: Array[10], spareCount: 0, strikeCount: 0, username: "Player 1"}, ...]
Now later I allow the user to play frames where each Player in our array has two throws... I collect the score and add it to the certain player's score array. However when I try to perform this action using a .forEach method the score I generate is applied to all items in my Players array (play the game and see). I have put my code in a jsBin and the problem is on line 109 : a.score[currentFrame - 1] = playFrame();
I have tried to amend my code but I can't work out why the current (or last) frame score is being applied to all Player objects! If you can understand my syntax error and explain why I would be most appreciative. Play the game (just click the button after setting the player numbers) and you will see what I mean...
Snippet:
var players,
currentFrame = 0,
currentThrow = 0;
// helper functions
// Accurate isNumber function... Thank you Crockford (see JavaScript: The Good Parts)
function isNumber(value) {
return typeof(value === 'number') && isFinite(value);
}
function frameStyle(k) {
var returnCssClass,
k = k + 1;
if (k < currentFrame) {
returnCssClass = 'played-frame';
} else if (k === currentFrame) {
returnCssClass = 'current-frame';
} else {
returnCssClass = null;
}
return returnCssClass;
}
function setUpPlayers(num) {
var tempArray = [],
tempName = 'Player ',
emptyScores = Array(10).fill([-1, -1]); // set default to -1 as a rubbish player may hit no pins!
for (var i = 0; i < num; i++) {
tempArray.push({
username: tempName + (i + 1),
score: emptyScores,
strikeCount: 0,
spareCount: 0
}); // the way I have named the tempName is technically an antipattern!
}
return tempArray;
}
function getTotals(scores) {
var totalScore = scores.reduce(function(a, b) {
return a + b.reduce(function(c, d) {
return (c + (c + ((d > 0) ? d : 0)));
}, 0);
}, 0);
return totalScore;
}
function displayScore(score) {
// toDo reformat!
var formatScore = score.map(function(a, b) {
if (a === -1) {
a = '-';
} else if (a === 10) {
a = 'X';
}
return a;
});
return formatScore;
}
function createGrid() {
// If only I was using ES6 I could have multi line support!
var playerLen = players.length,
scoresLen = players[0].score.length;
boards = '<div class="score-board">' +
'<!-- one row for each player -->';
// need to loop this through the players...
for (var i = 0; i < playerLen; i++) {
boards += '<div class="row">' +
'<!-- first cell is the name -->' +
'<div class="name">' + players[i].username + '</div>';
// need to loop this with the users scores
for (var k = 0; k < scoresLen; k++) {
boards += '<div class="game ' + frameStyle(k) + ' ">' + displayScore(players[i].score[k]) + '</div>';
}
// don't forget the total
boards += '<div class="player-total">' + getTotals(players[i].score) + '</div>';
boards += '</div>';
}
boards += '</div>';
boards += '<div>Current Frame: ' + currentFrame + '</div>';
boards += '<button type="button" onclick="startGame()">Start Game</button>';
// fill the holder....
document.getElementById('boardHolder').innerHTML = boards;
}
function startGame() {
if (currentFrame >= 10) {
announceWinner();
} else {
currentFrame++;
// do the throws for Each Player!
players.forEach(function(a, b) {
a.score[currentFrame - 1] = playFrame();
});
// update the grid
createGrid();
// recurrrrrrsion....
//startGame();
}
}
function throwBall(pinsStanding) {
// i know it isn't a ball
return Math.floor(Math.random() * (pinsStanding + 1));
}
function playFrame() {
// here we just create the array and determine if we have a strike or a spare!
var pinsStanding = 10,
frameScore = [],
frameThrows = 2,
pinsDown;
for(var i = 0; i < frameThrows; i++) {
pinsDown = throwBall(pinsStanding);
pinsStanding = pinsStanding - pinsDown;
// if it is the pinsStanding = 0 and it is the first throw - a strike!
if(pinsStanding === 0 && i === 1) {
pinsStanding = 10;
frameThrows = 3;
}
// what if it is a spare?
frameScore.push(pinsDown);
}
return frameScore;
}
function announceWinner() {
}
// kick it all off!!!
window.onload = function() {
// lets get some users....
players = prompt('Please enter the NUMBER of players?', 2);
// check we have a number...
if (isNumber(players)) {
players = setUpPlayers(players);
createGrid();
}
};
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
/* classes */
.score-board {
border: 1px solid #000;
}
.row {
display: block;
border-bottom: 1px solid #000;
}
.row:last-child {
border-bottom: none;
}
.row > div {
display: inline-block;
padding: 5px;
}
.game {
border-right: 1px solid #000;
}
.name {
background-color: #f5f5f5;
border-right: 1px solid #000;
}
.player-total {
text-align: right;
background-color: #d5eabb;
}
.played-frame {
background-color: #aee1e8;
}
.current-frame {
background-color: #ffc0cb;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<h1>Let's go bowling!</h1>
<div id="boardHolder">
</div>
</body>
</html>
Here is the bin!
https://jsbin.com/qilizo/edit?html,js,output
You need to call Array(10).fill([-1, -1]) inside for loop, because otherwise all objects will share the same score array:
function setUpPlayers(num) {
var tempArray = [],
tempName = 'Player ';
for (var i = 0; i < num; i++) {
tempArray.push({
username: tempName + (i + 1),
score: Array(10).fill([-1, -1]),// set default to -1 as a rubbish player may hit no pins!
strikeCount: 0,
spareCount: 0
}); // the way I have named the tempName is technically an antipattern!
}
return tempArray;
}
https://jsbin.com/yeyupiteyu/1/edit?html,js,output
In JavaScript objects are passed by reference, and since array is an object, if you declare emptyScores outside the loop and then assign it to every element of the array, all elements will share the same score array.
You have make new emptyScores array for each element, so you have to declare it inside the loop:
var tempArray = [],
tempName = 'Player ';
for (var i = 0; i < num; i++) {
var emptyScores = Array(10).fill([-1, -1]);
tempArray.push({
username: tempName + (i + 1),
score: emptyScores,
strikeCount: 0,
spareCount: 0
});
}

Categories

Resources