var score = 0; var bestScore = 0; var gridSize = 4; var cellValues; var tileItems = []; var availableCells; //var labels = "PRC"; var labels = "2048"; var labelFunc; var targetLevel = 11; var checkTargetFlag = true; switch (labels) { case "2048": labelFunc = function(n) { return Math.pow(2, n).toString(); }; break; case "PRC": labelFunc = function(n) { var dynasties = ["商", "周", "秦", "汉", "唐", "宋", "元", "明", "清", "ROC", "PRC"]; return dynasties[n-1]; }; break; } function startupFunction() { // Initialize variables score = 0; checkTargetFlag = true; var i; var j; cellValues = new Array(gridSize); for (i = 0; i < gridSize; i++) { cellValues[i] = new Array(gridSize); for (j = 0; j < gridSize; j++) cellValues[i][j] = 0; } for (i = 0; i < Math.pow(gridSize, 2); i++) { try { tileItems[i].destroy(); } catch(e) { } tileItems[i] = null; } updateAvailableCells(); createNewTileItems(true); updateScore(0); addScoreText.parent = scoreBoard.itemAt(0); console.log("Started a new game"); } function moveKey(event) { var isMoved = false; var i, j; var v, v2, mrg, indices; var oldScore = score; switch (event.key) { case Qt.Key_Left: for (i = 0; i < gridSize; i++) { v = cellValues[i]; mrg = mergeVector(v); v2 = mrg[0]; indices = mrg[1]; if (! arraysIdentical(v,v2)) { isMoved = true; moveMergeTilesLeftRight(i, v, v2, indices, true); cellValues[i] = v2; } } break; case Qt.Key_Right: for (i = 0; i < gridSize; i++) { v = cellValues[i].slice(); v.reverse(); mrg = mergeVector(v); v2 = mrg[0]; indices = mrg[1]; if (! arraysIdentical(v,v2)) { isMoved = true; v.reverse(); v2.reverse(); indices.reverse(); for (j = 0; j < indices.length; j++) indices[j] = gridSize - 1 - indices[j]; moveMergeTilesLeftRight(i, v, v2, indices, false); cellValues[i] = v2; } } break; case Qt.Key_Up: for (i = 0; i < gridSize; i++) { v = cellValues.map(function(row) {return row[i];}); mrg = mergeVector(v); v2 = mrg[0]; indices = mrg[1]; if (! arraysIdentical(v,v2)) { isMoved = true; moveMergeTilesUpDown(i, v, v2, indices, true); for (j = 0; j < gridSize; j++) { cellValues[j][i] = v2[j]; } } } break; case Qt.Key_Down: for (i = 0; i < gridSize; i++) { v = cellValues.map(function(row) {return row[i];}); v.reverse(); mrg = mergeVector(v); v2 = mrg[0]; indices = mrg[1]; if (! arraysIdentical(v,v2)) { isMoved = true; v.reverse(); v2.reverse(); indices.reverse(); for (j = 0; j < gridSize; j++) { indices[j] = gridSize - 1 - indices[j]; cellValues[j][i] = v2[j]; } moveMergeTilesUpDown(i, v, v2, indices, false); } } break; } if (isMoved) { updateAvailableCells(); createNewTileItems(false); if (oldScore !== score) { if (bestScore < score) { bestScore = score; } updateScore(oldScore); if (checkTargetFlag && maxTileValue() >= targetLevel) { winMessage.open(); } } } else { if (isDead()) { deadMessage.open(); } } } function ind2sub(ind) { var sub = [0, 0]; sub[0] = Math.floor(ind / gridSize); sub[1] = ind % gridSize; return sub; } function mergeVector(v0) { var i, j; var vlen = v0.length; var indices = []; // Pass 1: remove zero elements var v = []; for (i = 0; i < vlen; i++) { indices[i] = v.length; if (v0[i] > 0) { v.push(v0[i]); } } // Pass 2: merge same elements var v2 = []; for (i = 0; i < v.length; i++) { if (i === v.length - 1) { // The last element v2.push(v[i]); } else { if (v[i] === v[i+1]) { // move all right-side elements to left by 1 for (j = 0; j < vlen; j++) { if (indices[j] > v2.length) indices[j] -= 1; } // Merge i-1 and i v2.push(v[i] + 1); score += Math.pow(2, v[i] + 1); i++; } else { v2.push(v[i]); } } } // Fill the gaps with zeros for (i = v2.length; i < vlen; i++) v2[i] = 0; return [v2, indices]; } function removeElementsWithValue(arr, val) { var i = arr.length; while (i--) { if (arr[i] === val) { arr.splice(i, 1); } } return arr; } function arraysIdentical(a, b) { var i = a.length; if (i !== b.length) return false; while (i--) { if (a[i] !== b[i]) return false; } return true; }; function updateAvailableCells() { availableCells = []; for (var i = 0; i < gridSize; i++) { for (var j = 0; j < gridSize; j++) { if (cellValues[i][j] === 0) { availableCells.push(i * gridSize + j); } } } } function createNewTileItems(isStartup) { var i, sub, nTiles; if (isStartup) { nTiles = 2; } else { nTiles = 1; } // Popup a new number for (i = 0; i < nTiles; i++) { var oneOrTwo = Math.random() < 0.9 ? 1: 2; var randomCellId = availableCells[Math.floor(Math.random() * availableCells.length)]; sub = ind2sub(randomCellId); cellValues[sub[0]][sub[1]] = oneOrTwo; tileItems[randomCellId] = createTileObject(randomCellId, oneOrTwo, isStartup); // Mark this cell as unavailable var idx = availableCells.indexOf(randomCellId); availableCells.splice(idx, 1); } } function updateScore(oldScore) { if (score > oldScore) { addScoreText.text = "+" + (score-oldScore).toString(); addScoreAnim.running = true; } scoreBoard.itemAt(0).scoreText = MyScript.score.toString(); scoreBoard.itemAt(1).scoreText = MyScript.bestScore.toString(); } function isDead() { var dead = true; for (var i = 0; i < gridSize; i++) { for (var j = 0; j < gridSize; j++) { if (cellValues[i][j] === 0) { dead = false; } if (i > 0) { if (cellValues[i-1][j] === cellValues[i][j]) { dead = false; } } if (j > 0) { if (cellValues[i][j-1] === cellValues[i][j]) { dead = false; } } } } return dead; } function computeTileStyle(n) { var fgColors = ["#776E62", "#F9F6F2"]; var bgColors = ["#EEE4DA", "#EDE0C8", "#F2B179", "#F59563", "#F67C5F", "#F65E3B", "#EDCF72", "#EDCC61", "#EDC850", "#EDC53F", "#EDC22E", "#3C3A32"]; var sty = {bgColor: helper.myColors.bggray, fgColor: fgColors[0], fontSize: 55 }; if (n > 0) { if (n > 2) sty.fgColor = fgColors[1]; if (n <= bgColors.length) sty.bgColor = bgColors[n-1]; else sty.bgColor = bgColors[bgColors.length-1]; } if (labels === "2048") { /* Adjust font size according to size of the number [2, 100): 55 [100, 1000): 45 [1000, 2048]: 35 > 2048: 30 */ var pv = Math.pow(2, n); if (pv >= 100 && pv < 1000) sty.fontSize = 45; else if (pv >= 1000 && pv <= 2048) sty.fontSize = 35; else if (pv > 2048) sty.fontSize = 30; } return sty; } function maxTileValue() { var mv = 0; for (var i = 0; i < gridSize; i++) { for (var j = 0; j < gridSize; j++) { var cv = cellValues[i][j]; if ( mv < cv) { mv = cv; } } } return mv; } function createTileObject(ind, n, isStartup) { var component; var tile; var sty = computeTileStyle(n); var tileText = labelFunc(n); component = Qt.createComponent("Tile.qml"); tile = component.createObject(tileGrid, {"x": cells.itemAt(ind).x, "y": cells.itemAt(ind).y, "color": sty.bgColor, "tileColor": sty.fgColor, "tileFontSize": sty.fontSize, "tileText": tileText}); if (! isStartup) { tile.runNewTileAnim = true; } if (tile === null) { // Error Handling console.log("Error creating a new tile"); } return tile; } function moveMergeTilesLeftRight(i, v, v2, indices, left) { var j0, j; for (j0 = 0; j0 < v.length; j0++) { if (left) { j = j0; } else { j = v.length - 1 - j0; } if (v[j] > 0 && indices[j] !== j) { if (v2[indices[j]] > v[j] && tileItems[gridSize*i+indices[j]] !== null) { // Move and merge tileItems[gridSize*i+j].destroyFlag = true; tileItems[gridSize*i+j].z = -1; tileItems[gridSize*i+j].opacity = 0; tileItems[gridSize*i+j].x = cells.itemAt(gridSize*i+indices[j]).x; // tileItems[gridSize*i+j].destroy(); var sty = computeTileStyle(v2[indices[j]]); tileItems[gridSize*i+indices[j]].tileText = labelFunc(v2[indices[j]]); tileItems[gridSize*i+indices[j]].color = sty.bgColor; tileItems[gridSize*i+indices[j]].tileColor = sty.fgColor; tileItems[gridSize*i+indices[j]].tileFontSize = sty.fontSize; } else { // Move only tileItems[gridSize*i+j].x = cells.itemAt(gridSize*i+indices[j]).x; tileItems[gridSize*i+indices[j]] = tileItems[gridSize*i+j]; } tileItems[gridSize*i+j] = null; } } } function moveMergeTilesUpDown(i, v, v2, indices, up) { var j0, j; for (j0 = 0; j0 < v.length; j0++) { if (up) { j = j0; } else { j = v.length - 1 - j0; } if (v[j] > 0 && indices[j] !== j) { if (v2[indices[j]] > v[j] && tileItems[gridSize*indices[j]+i] !== null) { // Move and merge tileItems[gridSize*j+i].destroyFlag = true; tileItems[gridSize*j+i].z = -1; tileItems[gridSize*j+i].opacity = 0; tileItems[gridSize*j+i].y = cells.itemAt(gridSize*indices[j]+i).y; // tileItems[gridSize*j+i].destroy(); var sty = computeTileStyle(v2[indices[j]]); tileItems[gridSize*indices[j]+i].tileText = labelFunc(v2[indices[j]]); tileItems[gridSize*indices[j]+i].color = sty.bgColor; tileItems[gridSize*indices[j]+i].tileColor = sty.fgColor; tileItems[gridSize*indices[j]+i].tileFontSize = sty.fontSize; } else { // Move only tileItems[gridSize*j+i].y = cells.itemAt(gridSize*indices[j]+i).y; tileItems[gridSize*indices[j]+i] = tileItems[gridSize*j+i]; } tileItems[gridSize*j+i] = null; } } }