0

I'm trying to code "the 15 game" using jquery in html, See this page. The game is about to get a table of "boxes" in order from 1-15.

My code:

// Insert numbers from 1 to arraysize
function insertElements(myArr, arraysize){
 for (var i = 1; i < arraysize; i++ ) {
     myArr.push(i);
 }
}

// Check if the two cells is in range
function canMove(col, row, empty_row, empty_col){
 if((row == empty_row+1) && (col == empty_col) ||
  (row == empty_row-1) && (col == empty_col) ||
  (row == empty_row) && (col == empty_col+1) ||
  (row == empty_row) && (col == empty_col-1)){
  return true;
 } 
 else
  return false;
}

// Swap elements in array
function swapElements(myArr, indexA, indexB){
 // Check bounds
 if((indexA > myArr.length) || (indexA < 0) || (indexB > myArr.length) || (indexB < 0)) {
  alert("Out of bounds");
 } 
 else{

  var temp = myArr[indexA];
  myArr[indexA] = myArr[indexB];
  myArr[indexB] = temp;

 }
}  

// Wait for the page to finish loading
$(document).ready(function(){ 

// Create array
var myArr = [];
var arraysize = 17;
var lastelement = arraysize-1;
var empty_row;
var empty_col;
var empty_cell;

var col;
var row;
var nonempty_cell;

// Insert the elements
insertElements(myArr, arraysize);

// Number of shuffles
var shuffleNum = 10000;

// Shuffle the array
for (var i = 0; i < shuffleNum; i++ ) {
 var f = Math.floor((Math.random()*16)+0);
 var s = Math.floor((Math.random()*16)+0);
 swapElements(myArr, f, s);
}

//printarray(myArr, myArr.length);

i = 0;
// For each td in the table
$(".maincontainer td").each(function() {
 // Get the radnom value from the array
 val = myArr[i];

 // If the value is the last element
 // assign this cell to emptycell and add the class empty
 if(val == lastelement)
 { 
  empty_cell = $(this);
  empty_cell.addClass("empty");
  empty_row = this.parentNode.rowIndex;
  empty_col = this.cellIndex;
 }
 // Else, assign the value val to its text and add the class nonempty to it
 else
 {
  $(this).text(val);
  $(this).addClass("nonempty");

    }

    ++i;
    
});

// If one of the nonempty boxes is clicked
$(".nonempty").click(function(){

 // assign the cell that has been clicked to nonempty cell
 nonempty_cell = $(this);
 row = this.parentNode.rowIndex; 
 col = this.cellIndex;

 // If the cell is in range of the empty cell
 if(canMove(col, row, empty_row, empty_col)){

  // Swap empty cell and the non emptycell clicked
  var temp = empty_cell;
  empty_cell = nonempty_cell;
  nonempty_cell = temp;

  // Swap coordinates
  var temprow = row;
  row = empty_row;
  empty_row = temprow;
  var tempcol = col;
  col = empty_col;
  empty_col = tempcol;

  // Get text from the old empty cell
  var new_value = $(empty_cell).text();

  // Assign the value to the nonempty cell text and change class to nonempty
  $(nonempty_cell).text(new_value);
  $(nonempty_cell).removeClass("empty").addClass("nonempty");
  
  // "Erase" the textstring and change class to empty
  $(empty_cell).removeClass("nonempty").addClass("empty");
  $(empty_cell).text(""); 
 }
 else
 {
  alert("Cant move!");
 } 
});  


$(".empty").click(function(){
 alert("Clicked empty cell!");

});
});
<!DOCTYPE html>
<html lang='sv'>
<head>
 <meta charset="UTF-8" >
 <title>The 15 game</title>

<style>

.maincontainer
{
 width: 35%;
 border: 10px solid black;
}

.maincontainer td
{
 width: 100px;
 height: 100px;
 text-align: center;
 font-size: 100px;
 border: 3px solid black;
}

.nonempty
{
 background-color: red;
}

.empty
{
 background-color: #C0C0C0;
}

.nonempty:hover
{
 border: 3px solid white;
}
</style>


<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

<!-- External javascript with the game -->
<script type="text/javascript" src="javascript/15game.js"></script>

</head>
<body>

<!-- Table which is the maincontainer of the 16 boxes -->
<table class="maincontainer" >
  <tr>
    <td></td>
    <td></td> 
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td></td> 
    <td></td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td></td>
    <td></td> 
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td></td>
    <td></td> 
    <td></td>
    <td></td>
  </tr>
</table>

</body>
</html>

The code is kind of working correctly. When I click on a cell that is in range of the empty cell, the two cells are being swapped. The only problem is that the cell that first is assigned the class "empty" seems to keep the class "empty" when I try to replace its class to the class "nonempty".

I'm sorry for any typos, english is not my first language. Thanks for any help!

  • Remove both classes before adding a new one- removeClass("empty nonempty") to simplify logic and ensure clears. – user2864740 Sep 25 '15 at 23:11
  • Then use *delegated events* so the event handlers will transfer dynamically. The current events are bound in immediate mode, and stick to the original set of matched elements. – user2864740 Sep 25 '15 at 23:12

2 Answers2

0

Your problem here is that jQuery line here:

$(".empty").click(function(){
    alert("Clicked empty cell!");
});

See, the line matches all elements against '.empty' and adds the click event handler to them. When you change classes on the one element, the event handler isn't reset.

What you need is an event handler on a larger scope, say the table, or the document. Then check to see if the event target has the class.

user2676208
  • 123
  • 7
0

You are binding the events to the initial classes of the elements. Changing the classes later won't change the event bindings.

You can use delegated events instead, that way they detect the class at the time of the event:

$(".maincontainer").on("click", ".nonempty", function(){

and

$(".maincontainer").on("click", ".empty", function(){

Demo:

// Insert numbers from 1 to arraysize
function insertElements(myArr, arraysize){
 for (var i = 1; i < arraysize; i++ ) {
     myArr.push(i);
 }
}

// Check if the two cells is in range
function canMove(col, row, empty_row, empty_col){
 if((row == empty_row+1) && (col == empty_col) ||
  (row == empty_row-1) && (col == empty_col) ||
  (row == empty_row) && (col == empty_col+1) ||
  (row == empty_row) && (col == empty_col-1)){
  return true;
 } 
 else
  return false;
}

// Swap elements in array
function swapElements(myArr, indexA, indexB){
 // Check bounds
 if((indexA > myArr.length) || (indexA < 0) || (indexB > myArr.length) || (indexB < 0)) {
  alert("Out of bounds");
 } 
 else{

  var temp = myArr[indexA];
  myArr[indexA] = myArr[indexB];
  myArr[indexB] = temp;

 }
}  

// Wait for the page to finish loading
$(document).ready(function(){ 

// Create array
var myArr = [];
var arraysize = 17;
var lastelement = arraysize-1;
var empty_row;
var empty_col;
var empty_cell;

var col;
var row;
var nonempty_cell;

// Insert the elements
insertElements(myArr, arraysize);

// Number of shuffles
var shuffleNum = 10000;

// Shuffle the array
for (var i = 0; i < shuffleNum; i++ ) {
 var f = Math.floor((Math.random()*16)+0);
 var s = Math.floor((Math.random()*16)+0);
 swapElements(myArr, f, s);
}

//printarray(myArr, myArr.length);

i = 0;
// For each td in the table
$(".maincontainer td").each(function() {
 // Get the radnom value from the array
 val = myArr[i];

 // If the value is the last element
 // assign this cell to emptycell and add the class empty
 if(val == lastelement)
 { 
  empty_cell = $(this);
  empty_cell.addClass("empty");
  empty_row = this.parentNode.rowIndex;
  empty_col = this.cellIndex;
 }
 // Else, assign the value val to its text and add the class nonempty to it
 else
 {
  $(this).text(val);
  $(this).addClass("nonempty");

    }

    ++i;
    
});

// If one of the nonempty boxes is clicked
$(".maincontainer").on("click", ".nonempty", function(){

 // assign the cell that has been clicked to nonempty cell
 nonempty_cell = $(this);
 row = this.parentNode.rowIndex; 
 col = this.cellIndex;

 // If the cell is in range of the empty cell
 if(canMove(col, row, empty_row, empty_col)){

  // Swap empty cell and the non emptycell clicked
  var temp = empty_cell;
  empty_cell = nonempty_cell;
  nonempty_cell = temp;

  // Swap coordinates
  var temprow = row;
  row = empty_row;
  empty_row = temprow;
  var tempcol = col;
  col = empty_col;
  empty_col = tempcol;

  // Get text from the old empty cell
  var new_value = $(empty_cell).text();

  // Assign the value to the nonempty cell text and change class to nonempty
  $(nonempty_cell).text(new_value);
  $(nonempty_cell).removeClass("empty").addClass("nonempty");
  
  // "Erase" the textstring and change class to empty
  $(empty_cell).removeClass("nonempty").addClass("empty");
  $(empty_cell).text(""); 
 }
 else
 {
  alert("Cant move!");
 } 
});  


$(".maincontainer").on("click", ".empty", function(){
 alert("Clicked empty cell!");

});
});
<!DOCTYPE html>
<html lang='sv'>
<head>
 <meta charset="UTF-8" >
 <title>The 15 game</title>

<style>

.maincontainer
{
 width: 35%;
 border: 10px solid black;
}

.maincontainer td
{
 width: 100px;
 height: 100px;
 text-align: center;
 font-size: 100px;
 border: 3px solid black;
}

.nonempty
{
 background-color: red;
}

.empty
{
 background-color: #C0C0C0;
}

.nonempty:hover
{
 border: 3px solid white;
}
</style>


<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

<!-- External javascript with the game -->
<script type="text/javascript" src="javascript/15game.js"></script>

</head>
<body>

<!-- Table which is the maincontainer of the 16 boxes -->
<table class="maincontainer" >
  <tr>
    <td></td>
    <td></td> 
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td></td> 
    <td></td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td></td>
    <td></td> 
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td></td>
    <td></td> 
    <td></td>
    <td></td>
  </tr>
</table>

</body>
</html>
Guffa
  • 687,336
  • 108
  • 737
  • 1,005