Preface:
What I have been doing for a year is back-end stuff. I haven't written the front-end code. I forgot about it. I used jQuery before, but I can still do something good. Think of picking up a little, or waste the cultivation of the master.
I've been reading blogs, but I don't have anything of my own. this has to change.
why not start now? As the saying goes, as long as the code knocks fast enough, sadness will not catch up with me.
This blog begins with a simple game. The goal is to make something that can see the effect quickly and to pick up a little bit of programmer confidence.
Look first at the final results:
1. 2048 Game Function Analysis:
The core is the processing of movement in four directions.
Move in one direction and see if there is a merger of numbers. One move, one row is allowed to merge only once, and merge from the end point to the starting point.
After the merge is completed, the merged numbers and other numbers are moved and edged.
A number 2 is generated randomly in the blank position and the movement ends.
Algorithmic implementation:
Consider using a two-dimensional array to store values in 4*4 lattices. If you move, you only need to update the array, and then update the dom element with the value of the array.
(The idea is not very object-oriented. If we understand each lattice as an object, we don't know whether it's good or not. We'll study it later--TODO.
2. Things to be used
2.1 html page layout, 4*4 squares to be integrated
2.2 Simple css: Different numbers set different colors
2.3 Simple dom operation: take element, change display number, change class
2.4 Random Number Selection Algorithms
2.5 Keyboard Event Monitoring
2.6 A little bit of interaction considerations, such as deciding the end of the game failure, successful end, go back to the previous step.
3. Code structure:
Rougher, js is almost all referenced directly in html, no other way. First realize the function;
Several pictures are: Return to the previous step button, up and down the left and right buttons, restart the button.
js distinction:
ArayHelper is an array of operations;
domOperation, Gu Wenyi, operates dom;
EvetListener, handle key events
common: page initialization, random number generation, etc.
4. Core Code
4.1 Logic of Moving in Direction [Left]
Comment: Write more dead, step by step, according to the rules.
// Move in one direction,Update arrays (left), the same in other directions function moveLeft(arrayCopy){ var gameSuccess = false; // If there is merge or move, if there is no merge or move, if there is no operation, then do not generate new numbers var anyChange = false; // Each line, from left to right, compares whether there is the same number (excluding 0)--It doesn't need to be next to each other! Air in the middle can also be combined. for (var i=0;i<4;i++){ var firstIndex = 0; var secondIndex = 1; while (secondIndex<4){ if (arrayCopy[i][firstIndex] == 0){ // The first is 0.,There can't be mergers, moving backwards. firstIndex++; secondIndex++; continue; } if (arrayCopy[i][secondIndex] == 0){ // The second one is 0, the second one continues to look back, and the first one remains unchanged. secondIndex++; // 1. You can't find the number at the back. Keep looking back. End the loop. continue; } // Once there was the same number: calculate the sum, put it in the first place, and that's the end of the line. else if (arrayCopy[i][firstIndex] == arrayCopy[i][secondIndex]){ arrayCopy[i][firstIndex] = arrayCopy[i][firstIndex] * 2; arrayCopy[i][secondIndex] = 0; anyChange = true; if (arrayCopy[i][firstIndex] >= 2048){ // Get 2048, the game is over gameSuccess = true; } // 2. Find the number later, and can merge, merge, end the cycle break; } else{ // 3. Find the number later, but can not merge, update the first number to the current number, the second number to the next number. firstIndex = secondIndex; secondIndex += 1; continue; } } } // Move each line of numbers to the left for (var i=0;i<4;i++){ var newLine = [];//Temporary storage of non-zero numbers from left to right var index = 0; for (var j=0;j<4;j++){ if (arrayCopy[i][j] != 0){ newLine[index] = arrayCopy[i][j]; index++; } } // Update arrays with temporarily stored numbers for (var m=0;m<index;m++){ if (arrayCopy[i][m] != newLine[m]){ anyChange = true; } arrayCopy[i][m] = newLine[m]; } // The remaining position is given to 0. for (var n=index;n<4;n++){ if (arrayCopy[i][n] != 0){ anyChange = true; } arrayCopy[i][n] = 0; } } if (!anyChange){ console.log("no change after this move!"); if (!isEmptyCell(arrayCopy)){ // This step can not move, and there is no remaining grid, and any adjacent grid does not have the same, the end of the game. if (!canMerge(arrayCopy)){ console.log("Game Over! Try again."); return 'fail'; } } if (gameSuccess){ return 'success'; } // No move return 'unmoved'; } // Set Number 2 for Free Location if (isEmptyCell(arrayCopy)) { initOnePosition(arrayCopy); } if (gameSuccess){ return 'success'; } return 'moved'; }
4.2. General mobile processing.
Because moving in one direction is the same as moving in other directions, it is impossible to copy the above code four times.
In another direction: move left and right to manipulate arrays, but the row processing is the opposite, the column processing is the same;
Moving in other directions is similar and not worth copy ing the entire method.
// General method // All the movements are translated into a movement in one direction: for example, they are all imagined to move to the left, only need to reverse the array, complete the movement and then reverse back! function move(direction){ if (flagSuccess){ if (confirm("You've got your 2048! Start Another One?\n It's cleared! Start a new game?")){ gameRestart(); } return; } // Before moving, record the contents of the previous step, and recover after the failure of the move var lastStepUnchange = createNewArray(); updateFrontArray(lastStepUnchange,lastStepArray); // Set the previous step status to the current one updateFrontArray(lastStepArray,arrayInit); // Update the current,Update failure rolls back the status of the previous step // 1. Array inversion replication var arrayCopy = new Array(); if (direction == 'left'){ arrayCopy = copyArrayLeft(); }else if (direction == 'right'){ arrayCopy = copyArrayRight(); }else if (direction == 'up'){ arrayCopy = copyArrayUp(); }else if (direction == 'down'){ arrayCopy = copyArrayDown(); } // 2. They all move in one direction. var moveResult = moveLeft(arrayCopy); if ('fail' == moveResult){ updateFrontArray(lastStepArray,lastStepUnchange); // Mobile failure, no change if (confirm('Game Over! Try again?\n Game over, one more time?')){ gameRestart(); return; }else{ // The last step, let's go back. clickedLastStep = false; return; } return; } if ('unmoved' == moveResult){ return; } // 3. Update the original array from the inverted array if (direction == 'left'){ restoreArrayLeft(arrayCopy); }else if (direction == 'right'){ restoreArrayRight(arrayCopy); }else if (direction == 'up'){ restoreArrayUp(arrayCopy); }else if (direction == 'down'){ restoreArrayDown(arrayCopy); } // 4. Update page elements based on numbers updatePageByArray(); updateColor(); if ('success' == moveResult){ // Because operation DOM Not real-time, so wait for an event to complete before popping up the confirmation box setTimeout(function(){ // Game clearance, whether to restart if (confirm('Congragulations! Start Another Game?\n Congratulations on clearance! Would you like another one??')){ gameRestart(); }else{ flagSuccess = true; } },200); return; } // Mobile completion clickedLastStep = false; }
4.3 Generation of random numbers:
What we started with was to generate a random number, any one of the 16 locations. If the location was already occupied, we would abandon it and regenerate it until we found a vacancy.
But when there are fewer vacancies, it is inefficient.
Optimize: Search for random positions only in vacancies.
// Generate a random number and convert it to 0-15 Integer; function getRamdom(count) { // 0-1 var r0 = Math.random(); // 0-16 var r1 = r0 * count; // Number of integer digits only return Math.floor(r1); } // Improvement: Random search only in current available locations, not in unavailable locations function getOneEmptyCoordinate(array) { // 1. Get the current array var countEmptyCells = 0; var mapIndex2Coordinate = {}; var coordinates = null; for (var i=0;i<4;i++){ for (var j=0;j<4;j++){ if (array[i][j] == 0){ countEmptyCells++; coordinates = new Array(); coordinates.push(i); coordinates.push(j); mapIndex2Coordinate[countEmptyCells] = coordinates; } } } // Random Location of Available Location var random = getRamdom(countEmptyCells); return mapIndex2Coordinate[random]; }
5. deficiency:
5.1 Layout, style adjustment is relatively troublesome, misleading.
5.2 js code relationship - it doesn't matter, forget how the front end is organized;
5.3 Refresh page many times, may appear from the initialization exception, may be the file loading order problem, initialization dom operation is slow and so on.
5.4 See what other people think about.
http://www.cnblogs.com/-lizi/p/8431030.html
6. summary:
Development time: 5 working days, actual investment: about 15 hours.
Code size: js400 lines;
7. Full code pasting
index.html
<head> <meta http-equiv="content-type" content="text/html;charset=utf-8"> </head> <link href="../css/common.css" rel="stylesheet"> <body> <script type="text/javascript" src="../js/common.js"></script> <script type="text/javascript" src="../js/eventListener.js"></script> <script type="text/javascript" src="../js/domOperation.js"></script> <div id="main"> <div id="refreshDiv" onclick="gameRestart()"> <span id="refreshButton"> <img src="../resource/refreshButton.png" alt="refresh" /> <a>Restart</a> </span> </div> <div id="mainTable"> </div> <div id="explation"> <span> 2048 Game Description:<br> Press the left and right direction keys to move the numeric blocks.<br> Moving adjacent blocks of the same number in one direction will merge into larger numbers.<br> When the maximum number is 2048, the game wins!<br> Warm Tip: You can use the space bar to step back. </span> </div> <div id="rights"> <span> All rights reserved to S.C. Contact me at 857025773@qq.com. </span> </div> </div> <!-- operation --> <div id="keys"> <div> <span id="moveUpButton"onclick="move('up')"> <img src="../resource/direction.png" alt="direction" /> </span> </div> <div> <span id="moveLeftButton"onclick="move('left')"> <img src="../resource/direction.png" alt="direction" /> </span> <span id="moveBackButton" onclick="eventSpaceKey()"> <img src="../resource/moveBack.png" alt="moveBack" /> </span> <span id="moveRightButton"onclick="move('right')"> <img src="../resource/direction.png" alt="direction" /> </span> </div> <div> <span id="moveDownButton"onclick="move('down')"> <img src="../resource/direction.png" alt="direction" /> </span> </div> </div> <script type="text/javascript"> window.onload = function(){ pageInit(); } </script> </body>
common.css
#main
{
margin-left:500px;
margin-top:100px;
width:404px;
heignt:400px;
border: 0px solid gray;
border-radius: 1px;
}
#keys
{
margin-left:1150px;
margin-top:-430px;
width:303px;
heignt:300px;
border: 3px solid green;
border-radius: 20px;
}
#keys div
{
display:flex;
height:75px;
}
#keys div span
{
height:75px;
width:100px;
border: 1px solid gray;
background:blue;
}
#moveLeftButton img
{
height:75px;
width:100px;
-ms-transform:rotate(180deg); /* IE 9 */
-moz-transform:rotate(180deg); /* Firefox */
-webkit-transform:rotate(180deg); /* Safari and Chrome */
-o-transform:rotate(180deg); /* Opera */
}
#moveRightButton img
{
height:75px;
width:100px;
}
#moveUpButton
{
margin-left:100px;
}
#moveUpButton img
{
margin-top: -13px;
margin-left: 12px;
height:100px;
width:75px;
-ms-transform:rotate(270deg); /* IE 9 */
-moz-transform:rotate(270deg); /* Firefox */
-webkit-transform:rotate(270deg); /* Safari and Chrome */
-o-transform:rotate(270deg); /* Opera */
}
#moveDownButton
{
margin-left:100px;
}
#moveDownButton img
{
margin-left: 12px;
margin-top: -13px;
height:100px;
width:75px;
-ms-transform:rotate(90deg); /* IE 9 */
-moz-transform:rotate(90deg); /* Firefox */
-webkit-transform:rotate(90deg); /* Safari and Chrome */
-o-transform:rotate(90deg); /* Opera */
}
#moveBackButton
{
height:100px;
width:75px;
background:yellow !important;
}
#refreshDiv
{
height:40px;
width:133px;
margin-left:140px;
cursor: pointer;
background:#ba3537;
border-radius: 2px;
}
#refreshDiv span
{
display: contents;
font-family: 'Microsoft YaHei';
margin-left:159px;
font-size:20;
}
#refreshDiv span a
{
margin-bottom: 10px;
}
#explation
{
margin-top:30px;
}
#rights
{
margin-top:100px;
}
#rights span
{
font-size:10;
}
#explation span
{
font-size:14;
}
#mainTable
{
margin-top:20px;
background:#f5f5f5;
border: 2px solid #478dcd;
border-radius: 3px;
}
#mainTable div
{
display:flex;
width:400px;
heignt:100px;
}
#mainTable span
{
height:100px;
width:100px;
border: 1px solid gray;
font-size: 50;
text-align: center;
font-weight:bold;
}
.color0
{
background:#f5f5f5;
}
.color2
{
background:#f5c7ad;
}
.color4
{
background:#ec9362;
}
.color8
{
background:#e3631e;
}
.color16
{
background:#c2fcb1;
font-size: 45 !important;
}
.color32
{
background:#76f850;
font-size: 45 !important;
}
.color64
{
background:#2dad07;
font-size: 45 !important;
}
.color128
{
background:#a8a6f9;
font-size: 40 !important;
}
.color256
{
background:#4b47f1;
font-size: 40 !important;
}
.color512
{
background:#110da4;
font-size: 40 !important;
}
.color1024
{
background:#f799ef;
font-size: 35 !important;
}
.color2048
{
background:#a30e98;
font-size: 35 !important;
}
common.js
// Put together 2048, freeze operation, no movement allowed var flagSuccess = false; // Just clicked Back, no repeat clicks allowed, to move and then click var clickedLastStep = false; // Record the previous step for regression var lastStepArray = [ [0,0,0,0], [0,0,0,0], [0,0,0,0], [0,0,0,0] ]; // Array initialization--Normal initialization var arrayInit = [ [0,0,0,0], [0,0,0,0], [0,0,0,0], [0,0,0,0] ]; //[//Debugging -- will succeed // [0,0,0,0], // [0,128,0,0], // [0,0,512,1024], // [0,0,0,1024] //]; //[//Debugging -- will fail // [1,2,3,4], // [5,128,6,7], // [8,9,512,1024], // [13,22,11,11] //]; // Page loading initialization function pageInit() { addHelper(); // initArray(); // Page element initialization (cells) initElements(); // Initial data initTwoPositions(); // Fill cells with values based on initial data updatePageByArray(); // Style cells according to their values updateColor(); } // Restart function gameRestart(){ initArray(); pageInit(); } function initArray(){ flagSuccess = false; arrayInit = createNewArray(); clickedLastStep = false; lastStepArray = createNewArray(); } // Set the number 2 for two locations function initTwoPositions() { initOnePosition(arrayInit); initOnePosition(arrayInit); } // Set the number 2 for a location function initOnePosition(array){ // Choose Random Number Mode 1 // var num = getRamdom(16); // var line = Math.floor(num/4); // var col = num % 4; // var curNum = array[line][col]; // if (curNum == 0) // { // // Successfully find a free place // array[line][col] = 2; // return true; // } // else{ // // Recursive calls have to find an available location to complete // return initOnePosition(array); // } // Choose Random Number Mode 2 var coordinate = getOneEmptyCoordinate(array); array[coordinate[0]][coordinate[1]] = 2; } function isEmptyCell(arrayCopy) { for (var i=0;i<4;i++) { for (var j=0;j<4;j++) { if (arrayCopy[i][j] == 0) { return true; } } } return false; } // Generate a random number and convert it to 0-15 Integer; function getRamdom(count) { // 0-1 var r0 = Math.random(); // 0-16 var r1 = r0 * count; // Number of integer digits only return Math.floor(r1); } // Improvement: Random search only in current available locations, not in unavailable locations function getOneEmptyCoordinate(array) { // 1. Get the current array var countEmptyCells = 0; var mapIndex2Coordinate = {}; var coordinates = null; for (var i=0;i<4;i++){ for (var j=0;j<4;j++){ if (array[i][j] == 0){ countEmptyCells++; coordinates = new Array(); coordinates.push(i); coordinates.push(j); mapIndex2Coordinate[countEmptyCells] = coordinates; } } } // Random Location of Available Location var random = getRamdom(countEmptyCells); return mapIndex2Coordinate[random]; }
eventListener,js
/** * Reference Tool Class */ function addHelper(){ var newscript = document.createElement('script'); newscript.setAttribute('type','text/javascript'); newscript.setAttribute('src','../js/arrayHelper.js'); document.body.appendChild(newscript); } //Capture keystroke events document.onkeyup = function(event) { event = event || window.event; if (event.keyCode == 37){//left move('left'); }else if (event.keyCode == 39){//right move('right'); }else if (event.keyCode == 38){//up move('up'); }else if (event.keyCode == 40){//down move('down'); }else if (event.keyCode == 32){//space eventSpaceKey(); } } function eventSpaceKey(){ // Take a step back if (clickedLastStep){ console.log('can not move back again'); return; } moveBack(); flagSuccess = false; clickedLastStep = true; } // Take a step back function moveBack(){ // Judge that the last step is all 0 (just initialized) var justStarted = true; for (var i=0;i<4;i++){ for (var j=0;j<4;j++){ if (lastStepArray[i][j] != 0){ justStarted = false; } } } if(justStarted){ return; } // 1. Set values for the current array with backup arrays updateFrontArray(arrayInit,lastStepArray); // 3. Update page updatePageByArray(); updateColor(); } // General method // All the movements are translated into a movement in one direction: for example, they are all imagined to move to the left, only need to reverse the array, complete the movement and then reverse back! function move(direction){ if (flagSuccess){ if (confirm("You've got your 2048! Start Another One?\n It's cleared! Start a new game?")){ gameRestart(); } return; } // Before moving, record the contents of the previous step, and recover after the failure of the move var lastStepUnchange = createNewArray(); updateFrontArray(lastStepUnchange,lastStepArray); // Set the previous step status to the current one updateFrontArray(lastStepArray,arrayInit); // Update the current,Update failure rolls back the status of the previous step // 1. Array inversion replication var arrayCopy = new Array(); if (direction == 'left'){ arrayCopy = copyArrayLeft(); }else if (direction == 'right'){ arrayCopy = copyArrayRight(); }else if (direction == 'up'){ arrayCopy = copyArrayUp(); }else if (direction == 'down'){ arrayCopy = copyArrayDown(); } // 2. They all move in one direction. var moveResult = moveLeft(arrayCopy); if ('fail' == moveResult){ updateFrontArray(lastStepArray,lastStepUnchange); // Mobile failure, no change if (confirm('Game Over! Try again?\n Game over, one more time?')){ gameRestart(); return; }else{ // The last step, let's go back. clickedLastStep = false; return; } return; } if ('unmoved' == moveResult){ return; } // 3. Update the original array from the inverted array if (direction == 'left'){ restoreArrayLeft(arrayCopy); }else if (direction == 'right'){ restoreArrayRight(arrayCopy); }else if (direction == 'up'){ restoreArrayUp(arrayCopy); }else if (direction == 'down'){ restoreArrayDown(arrayCopy); } // 4. Update page elements based on numbers updatePageByArray(); updateColor(); if ('success' == moveResult){ // Because operation DOM Not real-time, so wait for an event to complete before popping up the confirmation box setTimeout(function(){ // Game clearance, whether to restart if (confirm('Congragulations! Start Another Game?\n Congratulations on clearance! Would you like another one??')){ gameRestart(); }else{ flagSuccess = true; } },200); return; } // Mobile completion clickedLastStep = false; } // Move in one direction,Update arrays (left), the same in other directions function moveLeft(arrayCopy){ var gameSuccess = false; // If there is merge or move, if there is no merge or move, if there is no operation, then do not generate new numbers var anyChange = false; // Each line, from left to right, compares whether there is the same number (excluding 0)--It doesn't need to be next to each other! Air in the middle can also be combined. for (var i=0;i<4;i++){ var firstIndex = 0; var secondIndex = 1; while (secondIndex<4){ if (arrayCopy[i][firstIndex] == 0){ // The first is 0.,There can't be mergers, moving backwards. firstIndex++; secondIndex++; continue; } if (arrayCopy[i][secondIndex] == 0){ // The second one is 0, the second one continues to look back, and the first one remains unchanged. secondIndex++; // 1. You can't find the number at the back. Keep looking back. End the loop. continue; } // Once there was the same number: calculate the sum, put it in the first place, and that's the end of the line. else if (arrayCopy[i][firstIndex] == arrayCopy[i][secondIndex]){ arrayCopy[i][firstIndex] = arrayCopy[i][firstIndex] * 2; arrayCopy[i][secondIndex] = 0; anyChange = true; if (arrayCopy[i][firstIndex] >= 2048){ // Get 2048, the game is over gameSuccess = true; } // 2. Find the number later, and can merge, merge, end the cycle break; } else{ // 3. Find the number later, but can not merge, update the first number to the current number, the second number to the next number. firstIndex = secondIndex; secondIndex += 1; continue; } } } // Move each line of numbers to the left for (var i=0;i<4;i++){ var newLine = [];//Temporary storage of non-zero numbers from left to right var index = 0; for (var j=0;j<4;j++){ if (arrayCopy[i][j] != 0){ newLine[index] = arrayCopy[i][j]; index++; } } // Update arrays with temporarily stored numbers for (var m=0;m<index;m++){ if (arrayCopy[i][m] != newLine[m]){ anyChange = true; } arrayCopy[i][m] = newLine[m]; } // The remaining position is given to 0. for (var n=index;n<4;n++){ if (arrayCopy[i][n] != 0){ anyChange = true; } arrayCopy[i][n] = 0; } } if (!anyChange){ console.log("no change after this move!"); if (!isEmptyCell(arrayCopy)){ // This step can not move, and there is no remaining grid, and any adjacent grid does not have the same, the end of the game. if (!canMerge(arrayCopy)){ console.log("Game Over! Try again."); return 'fail'; } } if (gameSuccess){ return 'success'; } // No move return 'unmoved'; } // Set Number 2 for Free Location if (isEmptyCell(arrayCopy)) { initOnePosition(arrayCopy); } if (gameSuccess){ return 'success'; } return 'moved'; } // Are there any adjacent lattices that can be merged? function canMerge(arrayCopy){ for (var i=0;i<4;i++){ for (var j=0;j<4;j++){ if (j+1 < 4&& arrayCopy[i][j] == arrayCopy[i][j+1]){ return true; } if (i+1 < 4 && arrayCopy[i][j] == arrayCopy[i+1][j]){ return true; } } } return false; }
arrayHelper.js
function createNewArray(){ var newArray = [ [0,0,0,0], [0,0,0,0], [0,0,0,0], [0,0,0,0] ]; return newArray; } // Copy the back to the front function updateFrontArray(arr1,arr2) { for (var i=0;i<4;i++){ for (var j=0;j<4;j++){ arr1[i][j] = arr2[i][j]; } } } function copyArray(arr){ var newArray = createNewArray(); updateFrontArray(newArray,arr); return newArray; } //Left, original direction function copyArrayLeft(){ var arrayCopy = copyArray(arrayInit); return arrayCopy; } function restoreArrayLeft(arrayCopy){ updateFrontArray(arrayInit,arrayCopy); } //Right, top and bottom unchanged, left and right reversed function copyArrayRight(){ var arrayCopy = new Array(); for (var i=0;i<4;i++){ var copyOneLine = new Array(); for (var j=0;j<4;j++){ copyOneLine[3-j] = arrayInit[i][j]; } arrayCopy[i] = copyOneLine; } return arrayCopy; } function restoreArrayRight(arrayCopy){ for (var i=0;i<4;i++){ for (var j=0;j<4;j++){ arrayInit[i][j] = arrayCopy[i][3-j]; } } } //upper //From top to bottom to left to right //From right to left to top to bottom //(i,j) Corresponding:(3-j,i) function copyArrayUp(){ var arrayCopy = [ [0,0,0,0], [0,0,0,0], [0,0,0,0], [0,0,0,0] ]; for (var i=0;i<4;i++){ for (var j=0;j<4;j++){ arrayCopy[3-j][i] = arrayInit[i][j]; } } return arrayCopy; } function restoreArrayUp(arrayCopy){ for (var i=0;i<4;i++){ for (var j=0;j<4;j++){ arrayInit[i][j] = arrayCopy[3-j][i]; } } } //lower //From top to bottom to top //From left to right to left to right //(i,j) Corresponding:(j,3-i) function copyArrayDown(){ var arrayCopy = [ [0,0,0,0], [0,0,0,0], [0,0,0,0], [0,0,0,0] ]; for (var i=0;i<4;i++){ for (var j=0;j<4;j++){ arrayCopy[j][3-i] = arrayInit[i][j]; } } return arrayCopy; } function restoreArrayDown(arrayCopy){ for (var i=0;i<4;i++){ for (var j=0;j<4;j++){ arrayInit[i][j] = arrayCopy[j][3-i]; } } }
domOperation.js
// Assignment of elements with arrays function updatePageByArray() { var lines = document.getElementById("mainTable").children; var lineIndex = 0; while (lineIndex < lines.length) { var spanIndex = 0; while (spanIndex < lines[lineIndex].children.length) { var oneSpan = lines[lineIndex].children[spanIndex]; oneSpan.innerHTML = arrayInit[lineIndex][spanIndex]; spanIndex++; } lineIndex++; } } // Initialize cells and colors function initElements() { var mainTable = document.getElementById("mainTable"); var str = ''; // Create row for (var i=0;i<4;i++) { str += "<div id='" +"line"+i+"'>"; for (var j=0;j<4;j++) { var num = arrayInit[i][j]; str += "<span id='" +"span"+i+j+"'>" + num+ "</span>"; } str += "</div>"; mainTable.innerHTML = str; } } // according to ID Update color function updateColor(){ for (var i=0;i<4;i++){ for (var j=0;j<4;j++){ var span = document.getElementById("span"+i+j); var value = span.innerHTML; if (value == '0'){ span.innerHTML = ''; } span.className = (" color" + value); } } }