You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

474 lines
13 KiB

var score = 0;
var bestScore = settings.value("bestScore", 0);
var gridSize = 4;
var cellValues;
var tileItems = [];
var availableCells;
var targetLevel = 11;
var checkTargetFlag = true;
var tileComponent = Qt.createComponent("Tile.qml");
var label = settings.value("label", "2048");
var labelOptions = ["2048", "Degree", "Military Rank", "PRC"];
var labelFunc = {
"2048":
function(n) {
return Math.pow(2, n).toString();
},
"PRC":
function(n) {
var arr = ["商", "周", "秦", "汉", "唐", "宋", "元", "明", "清", "民国", "天朝", "天庭"];
if (n > 0 && n < arr.length)
return arr[n-1];
else
return "";
},
"Military Rank":
function(n) {
var arr = ["少尉", "中尉", "上尉", "少校", "中校", "上校", "大校", "少将", "中将", "上将", "元帅", "大元帅"];
if (n > 0 && n < arr.length)
return arr[n-1];
else
return "";
},
"Degree":
function(n) {
var arr = ["幼儿园", "小学", "初中", "高中", "学士", "硕士", "博士", "博士后", "勇士", "壮士", "烈士", "圣斗士"];
if (n > 0 && n < arr.length)
return arr[n-1];
else
return "";
}
}
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);
// Save the currently achieved best score
if (bestScore > settings.value("bestScore", 0)) {
console.log("Updating new high score...");
settings.setValue("bestScore", bestScore);
}
if (label !== settings.value("label", "2048"))
settings.setValue("label", label);
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;
}
}
event.accepted = true;
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;
}
}
event.accepted = true;
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];
}
}
}
event.accepted = true;
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);
}
}
event.accepted = true;
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, tileText) {
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];
}
/* Adjust font size according to the length of the text
<= 2: 55
{3, 4}: 45
{5, 6}: 35
> 6: 30
*/
var tlen = getLengthInBytes(tileText);
if (tlen <= 2)
sty.fontSize = 50;
else if (tlen <= 4)
sty.fontSize = 40;
else if (tlen <= 6)
sty.fontSize = 30;
else
sty.fontSize = 20;
return sty;
}
function getLengthInBytes(str) {
// getLengthInBytes("一二三") = 6
// getLengthInBytes("123") = 3
var b = str.match(/[^\x00-\xff]/g); // Multi-byte characters (Chinese) occupy twice more space
return (str.length + (!b ? 0: b.length));
}
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 tile;
var tileText = labelFunc[label](n);
var sty = computeTileStyle(n, tileText);
tile = tileComponent.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 tileText = labelFunc[label](v2[indices[j]]);
var sty = computeTileStyle(v2[indices[j]], tileText);
tileItems[gridSize*i+indices[j]].tileText = tileText;
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 tileText = labelFunc[label](v2[indices[j]]);
var sty = computeTileStyle(v2[indices[j]], tileText);
tileItems[gridSize*indices[j]+i].tileText = tileText;
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;
}
}
}
function cleanUpAndQuit() {
if (bestScore > settings.value("bestScore", 0)) {
console.log("Updating new high score...");
settings.setValue("bestScore", bestScore);
}
if (label !== settings.value("label", "2048"))
settings.setValue("label", label);
Qt.quit();
}