Making a little game in Javascript and I seem to not have “explained” the rules to the code properly. The playfield is a 10×9 grid and you are to move two colored pieces back to their original place after being scattered. The rule is you can only move a piece across one other piece of the opposite color, kinda like taking a piece in Checkers. To make things fair I decided that instead of giving the pieces random coordinates I would make the pieces move in accordance to the rules to ensure that the player could backtrack and the game was solvable.
As they were moving I noticed that they started ignoring the rules. Jumping over more than one, jumping over the same color, and/or jumping over empty spaces. I broke up the code to only move when I pressed a key and print the board array. The output ended up like this:

As you’ll notice on the last capture, a piece “clones” itself and jumps over an empty space. Visually the piece is no longer in the place it was, but in the array it is now in two places.
var MARBLES = {
stage: 0,
drawrect: 0,
ball: [],
curball: -1,
slideDest: {x: 0, y: 0},
// array board flipped on its side so that [x] can come before [y]
board: [
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0]
]
};
function MARBLES_init()
{
MARBLES.stage = 0;
MARBLES.drawrect = 0;
MARBLES.ball = [];
}
function MARBLES_update(timing)
{
if(MARBLES.stage == 0)
{
ctx.drawImage(images[scenes["MARBLES"]][2].img, 240-MARBLES.drawrect,240-MARBLES.drawrect,160+MARBLES.drawrect*2,MARBLES.drawrect*2,
240-MARBLES.drawrect,240-MARBLES.drawrect,160+MARBLES.drawrect*2,MARBLES.drawrect*2);
MARBLES.drawrect += timing;
if(MARBLES.drawrect > 240 + timing)
{
MARBLES.stage = 1;
ctx.drawImage(images[scenes["MARBLES"]][3].img, 32, 112);
ctx.drawImage(images[scenes["MARBLES"]][4].img, 32, 320);
MARBLES.ball.push(new class_Marble(2,4,2));
for(var y = 3; y < 6; y++)
MARBLES.ball.push(new class_Marble(3,y,2));
for(var y = 2; y < 7; y++)
MARBLES.ball.push(new class_Marble(4,y,2));
for(var y = 2; y < 7; y++)
MARBLES.ball.push(new class_Marble(5,y,1));
for(var y = 3; y < 6; y++)
MARBLES.ball.push(new class_Marble(6,y,1));
MARBLES.ball.push(new class_Marble(7,4,1));
MARBLES.stage = 1;
setTimeout(function () { MARBLES.stage = 2; },1000);
}
}
else if(MARBLES.stage == 2)
{
if(MARBLES.curball == -1)
{
var dir = -1;
if(inkey > 1) // is set at onkeyup
{
MARBLES.curball = Math.floor(Math.random() * MARBLES.ball.length);
var curlx = MARBLES.ball[MARBLES.curball].locx;
var curly = MARBLES.ball[MARBLES.curball].locy;
dir = Math.floor(Math.random()*8);
if(MARBLES.ball[MARBLES.curball].c == 1) var opos = 2;
if(MARBLES.ball[MARBLES.curball].c == 2) var opos = 1;
}
if(dir == 0 && curlx > 1 && curly > 1 && MARBLES.board[curlx-1][curly-1] == opos && MARBLES.board[curlx-2][curly-2] == 0)
{
MARBLES.slideDest.x = 168+((curlx-2)*42.20);
MARBLES.slideDest.y = 49+((curly-2)*42.20);
MARBLES.board[curlx][curly] = 0;
MARBLES.board[curlx-2][curly-2] = MARBLES.ball[MARBLES.curball].c;
}
else if(dir == 1 && curlx < 9 && curly > 1 && MARBLES.board[curlx+1][curly-1] == opos && MARBLES.board[curlx+2][curly-2] == 0)
{
MARBLES.slideDest.x = 168+((curlx+2)*42.20);
MARBLES.slideDest.y = 49+((curly-2)*42.20);
MARBLES.board[curlx][curly] = 0;
MARBLES.board[curlx+2][curly-2] = MARBLES.ball[MARBLES.curball].c;
}
else if(dir == 2 && curlx > 1 && curly < 8 && MARBLES.board[curlx-1][curly+1] == opos && MARBLES.board[curlx-2][curly+2] == 0)
{
MARBLES.slideDest.x = 168+((curlx-2)*42.20);
MARBLES.slideDest.y = 49+((curly+2)*42.20);
MARBLES.board[curlx][curly] = 0;
MARBLES.board[curlx-2][curly+2] = MARBLES.ball[MARBLES.curball].c;
}
else if(dir == 3 && curlx < 9 && curly < 8 && MARBLES.board[curlx+1][curly+1] == opos && MARBLES.board[curlx+2][curly+2] == 0)
{
MARBLES.slideDest.x = 168+((curlx+2)*42.20);
MARBLES.slideDest.y = 49+((curly+2)*42.20);
MARBLES.board[curlx][curly] = 0;
MARBLES.board[curlx+2][curly+2] = MARBLES.ball[MARBLES.curball].c;
}
else if(dir == 4 && curlx > 1 && MARBLES.board[curlx-1][curly] == opos && MARBLES.board[curlx-2][curly] == 0)
{
MARBLES.slideDest.x = 168+((curlx-2)*42.20);
MARBLES.slideDest.y = 49+(curly*42.20);
MARBLES.board[curlx][curly] = 0;
MARBLES.board[curlx-2][curly] = MARBLES.ball[MARBLES.curball].c;
}
else if(dir == 5 && curlx < 9 && MARBLES.board[curlx+1][curly] == opos && MARBLES.board[curlx+2][curly] == 0)
{
MARBLES.slideDest.x = 168+((curlx+2)*42.20);
MARBLES.slideDest.y = 49+(curly*42.20);
MARBLES.board[curlx][curly] = 0;
MARBLES.board[curlx+2][curly] = MARBLES.ball[MARBLES.curball].c;
}
else if(dir == 6 && curly > 1 && MARBLES.board[curlx][curly-1] == opos && MARBLES.board[curlx][curly-2] == 0)
{
MARBLES.slideDest.x = 168+(curlx*42.20);
MARBLES.slideDest.y = 49+((curly-2)*42.20);
MARBLES.board[curlx][curly] = 0;
MARBLES.board[curlx][curly-2] = MARBLES.ball[MARBLES.curball].c;
}
else if(dir == 7 && curly < 8 && MARBLES.board[curlx][curly+1] == opos && MARBLES.board[curlx][curly+2] == 0)
{
MARBLES.slideDest.x = 168+(curlx*42.20);
MARBLES.slideDest.y = 49+((curly+2)*42.20);
MARBLES.board[curlx][curly] = 0;
MARBLES.board[curlx][curly+2] = MARBLES.ball[MARBLES.curball].c;
}
else
{
MARBLES.curball = -1;
}
}
else
{
if(MARBLES.ball[MARBLES.curball].px < MARBLES.slideDest.x)
MARBLES.ball[MARBLES.curball].moveX(1);
if(MARBLES.ball[MARBLES.curball].px > MARBLES.slideDest.x)
MARBLES.ball[MARBLES.curball].moveX(-1);
if(MARBLES.ball[MARBLES.curball].py < MARBLES.slideDest.y)
MARBLES.ball[MARBLES.curball].moveY(1);
if(MARBLES.ball[MARBLES.curball].py > MARBLES.slideDest.y)
MARBLES.ball[MARBLES.curball].moveY(-1);
if(MARBLES.ball[MARBLES.curball].px > MARBLES.slideDest.x-1 && MARBLES.ball[MARBLES.curball].px < MARBLES.slideDest.x+1 && MARBLES.ball[MARBLES.curball].py > MARBLES.slideDest.y-1 && MARBLES.ball[MARBLES.curball].py < MARBLES.slideDest.y+1)
{
PlaySound(scenes["MARBLES"],2,OPTIONS.volsfx,1);
console.log("----------");
for(var y = 0; y < 9; y++) // printing the array as shown above
{
var t = "";
for(var x = 0; x < 10; x++)
{
t += MARBLES.board[x][y] + " ";
}
console.log(t);
}
MARBLES.curball = -1;
}
}
}
}
function class_Marble(x,y,c)
{
this.locx = x;
this.locy = y;
this.c = c;
this.px = 168+(x*42.20);
this.py = 49+(y*42.20);
this.bkdata = ctx.getImageData(this.px,this.py,42,42);
MARBLES.board[x][y] = c;
ctx.drawImage(images[scenes["MARBLES"]][this.c-1].img, this.px,this.py);
this.update = function(timing)
{
}
this.setPos = function(px,py)
{
ctx.putImageData(this.bkdata,this.px,this.py);
this.px = px;
this.py = py;
this.bkdata = ctx.getImageData(this.px,this.py,42,42);
ctx.drawImage(images[scenes["MARBLES"]][this.c-1].img, this.px,this.py);
}
this.moveX = function(inc)
{
ctx.putImageData(this.bkdata,this.px,this.py);
this.px += inc;
this.bkdata = ctx.getImageData(this.px,this.py,42,42);
ctx.drawImage(images[scenes["MARBLES"]][this.c-1].img, this.px,this.py);
}
this.moveY = function(inc)
{
ctx.putImageData(this.bkdata,this.px,this.py);
this.py += inc;
this.bkdata = ctx.getImageData(this.px,this.py,42,42);
ctx.drawImage(images[scenes["MARBLES"]][this.c-1].img, this.px,this.py);
}
}