用JS實現2048小游戲

来源:https://www.cnblogs.com/hhhblog/archive/2018/04/20/8894069.html
-Advertisement-
Play Games

前言: 一年來一直做得是後端的東西,沒有寫前端代碼,忘乾凈了,之前也只用jQuery,好歹還能做點效果。想著撿起來一點,要不然枉費了師傅的栽培。 一直在看博客,但沒有屬於自己的東西。this has to change. why not start now?俗話說只要代碼敲得夠快,悲傷就追不上我。 ...


前言:

一年來一直做得是後端的東西,沒有寫前端代碼,忘乾凈了,之前也只用jQuery,好歹還能做點效果。想著撿起來一點,要不然枉費了師傅的栽培。

一直在看博客,但沒有屬於自己的東西。this has to change.

why not start now?俗話說只要代碼敲得夠快,悲傷就追不上我。

此篇開博,從簡單小游戲開始。目的是做出一些可以快點看到效果的東西,撿回一點程式員的信心。

 

先看最終效果:

 

 

1. 2048游戲功能分析:

核心是4個方向的移動的處理。

往一個方向移動,先看是否有數字的合併。一次移動,一行只允許合併一次,且從終點往起點合併。

合併完成之後,將合併後的數字和其他數字移動,貼邊。

在空白位置隨機生成一個數字2,移動結束。

 

演算法實現:

考慮採用二維數組存儲4*4個格子中的值,如果移動,只需要更新數組,然後用數組的值來更新dom元素即可。

(這種想法不太面向對象。要是將每個格子都理解為一個對象,不知道好不好做,等以後研究--TODO)

 

2. 要用到的東西

2.1 html頁面佈局,4*4個方塊得整齣來

2.2 簡單css:不同的數字設置不同顏色

2.3 簡單dom操作:取元素,變換顯示的數字,改變class

2.4 取隨機數演算法

2.5 按鍵事件監聽

2.6 一點點交互操作考慮,比如判定游戲失敗結束,成功結束,返回上一步。

 

3. 代碼結構:

 

較為粗糙,js幾乎全部是直接用html引用了,不會其他方式。先實現功能;

幾個圖片是:返回上一步按鈕,上下左右按鈕,重新開始按鈕。

js區分:

arrayHelper是操作數組的;

domOperation顧文思意,操作dom;

eventListener,處理按鍵事件

common:頁面初始化,隨機數生成等

 

4. 核心代碼

4.1 向方向【左】移動的邏輯

評論:寫的比較死,一步一步,按照規則來即可

// 向一個方向移動,更新數組(左),其他方向也是一樣的
function moveLeft(arrayCopy){
    var gameSuccess = false;
    
    // 是否有合併或者移動,如果沒有合併也沒有移動,就是沒有操作那就不要生成新的數字
    var anyChange = false;
    // 每一行,從【左】往【右】對比是否有一樣的數字(排除0)--並不需要挨著!中間隔了空氣也可以合併
    for (var i=0;i<4;i++){
        var firstIndex = 0;
        var secondIndex = 1;
        while (secondIndex<4){
            if (arrayCopy[i][firstIndex] == 0){
                // 第一個是0,不可能有合併,往後移動
                firstIndex++;
                secondIndex++;
                continue;
            }
            if (arrayCopy[i][secondIndex] == 0){
                // 第二個是0,第二個繼續往後找,第一個不變
                secondIndex++;
                // 1. 後面找不到數字,一直往後找,結束迴圈
                continue;
            }            
            // 有一次一樣的數字:計算得到和,放到第一個位置,這一行完了
            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){
                    // 得到了2048,游戲結束
                    gameSuccess = true;
                }
                // 2. 後面找到數字,且可以合併,就合併,結束迴圈
                break;
            }
            else{
                // 3. 後面找到數字,但是不能合併,更新第一個數字為當前數字,第二個數字為下一個數字
                firstIndex = secondIndex;
                secondIndex += 1;
                continue;
            }
        }
    }
    
    // 將每一行數字向【左】挪動
    for (var i=0;i<4;i++){
        var newLine = [];//臨時存儲從【左】到【右】的非0數字
        var index = 0;
        for (var j=0;j<4;j++){
            if (arrayCopy[i][j] != 0){
                newLine[index] = arrayCopy[i][j];
                index++;
            }
        }
        
        // 用臨時存儲的數字給數組更新
        for (var m=0;m<index;m++){
            if (arrayCopy[i][m] != newLine[m]){
                anyChange = true;
            }
            arrayCopy[i][m] = newLine[m];
        }
        // 剩餘的位置給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)){
            // 本步不能移動,且沒有剩餘格子,且任意相鄰格子沒有相同的,就結束游戲
            if (!canMerge(arrayCopy)){
                console.log("Game Over! Try again.");
                return 'fail';
            }
        }
        if (gameSuccess){
            return 'success';
        }
        // 沒有移動
        return 'unmoved';
    }
    
    // 給空閑位置設置數字2
    if (isEmptyCell(arrayCopy))
    {
        initOnePosition(arrayCopy);
    }
    
    if (gameSuccess){
        return 'success';
    }
    return 'moved';
}

4.2.  通用的移動處理。

因為往一個方向移動,和往其他方向移動處理是一樣的,不可能複製以上代碼4次吧。

換個方向看:往左移動和往右移動對數組的操作,只是行處理相反,列處理一樣;

其他方向移動類似,不值得copy整個方法。

// 通用方法
// 所有移動都轉換成一個方向上的移動:例如,都想象成向左移動,只需要倒轉數組即可,完成移動再倒轉回來!
function move(direction){
    if (flagSuccess){
        if (confirm("You've got your 2048! Start Another One?\n已經通關!開始新游戲?")){
            gameRestart();
        }
        return;
    }
    
    // 移動之前,記錄上一步的內容,移動失敗之後可以恢復
    var lastStepUnchange = createNewArray();
    updateFrontArray(lastStepUnchange,lastStepArray);
    // 將上一步狀態設置為當前的
    updateFrontArray(lastStepArray,arrayInit);
    
    // 將當前的去更新,更新失敗則回滾上一步的狀態
    // 1. 數組倒轉複製
    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. 都向一個方向移動
    var moveResult = moveLeft(arrayCopy);
    if ('fail' == moveResult){
        
        updateFrontArray(lastStepArray,lastStepUnchange);
        // 移動失敗,沒有任何改變
        if (confirm('Game Over! Try again?\n游戲結束,再來一次?')){
            gameRestart();
            return;
        }else{
            // 最後一步了,允許回退
            clickedLastStep = false;
            return;
        }
        return;
    }
    if ('unmoved' == moveResult){
        return;
    }
    
    // 3. 從倒轉的數組更新原數組
    if (direction == 'left'){
        restoreArrayLeft(arrayCopy);
    }else if (direction == 'right'){
        restoreArrayRight(arrayCopy);
    }else if (direction == 'up'){
        restoreArrayUp(arrayCopy);
    }else if (direction == 'down'){
        restoreArrayDown(arrayCopy);
    }
    
    // 4. 根據數字更新頁面元素
    updatePageByArray();
    updateColor();
    
    if ('success' == moveResult){
        // 因為操作DOM不是實時的,所以要等一段事件操作完成之後再彈出確認框
        setTimeout(function(){
            // 游戲通關,是否重新開始
            if (confirm('Congragulations! Start Another Game?\n恭喜通關!是否再來一把?')){
                gameRestart();
            }else{
                flagSuccess = true;
            }
        },200);
        return;
    }
    
    // 移動完成
    clickedLastStep = false;
}

 

4.3 隨機數的生成:

開始做的是生成一個隨機數,16個位置的任意一個,如果這個位置已經有人了,就放棄,重新生成一個,直到找到空位為止。

但是到空位變少的時候,這樣效率低下。

優化:只在空位中找隨機位置。

// 生成隨機數,轉化成0-15的整數;
function getRamdom(count)
{
    // 0-1
    var r0 = Math.random();
    // 0-16
    var r1 = r0 * count;
    // 只取整數位數的數
    return Math.floor(r1);
}

// 改進:只在當前可用位置中隨機找,不用找不可用的位置 
function getOneEmptyCoordinate(array)
{
    // 1. 得到當前數組
    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;
            }
        }
    }
    // 取可用位置的隨機位置
    var random = getRamdom(countEmptyCells);
    return mapIndex2Coordinate[random];
}

 

 

5. 欠缺:

5.1 佈局,樣式的調整比較嫌麻煩,瞎調的。

5.2 js代碼關係--沒什麼關係,忘了前端是怎麼組織的了;

5.3 刷新頁面多次,可能出現從初始化異常,可能是文件載入順序問題,初始化時dom操作比較慢等原因

5.4 看看別人實現思路如何 

-- http://www.cnblogs.com/-lizi/p/8431030.html 這個寫的很漂亮

 

6. 總結:

 開發時間:5天下班時間,實際投入:15個小時左右。

 代碼規模:js400行;

 

7. 完整代碼粘貼

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>重新開始</a>
            </span>
        </div>
        <div id="mainTable">
        </div>
        <div id="explation">
            <span>
             2048游戲說明:<br>
             按上下左右方向鍵可以移動有數字的方塊,<br>
             相鄰的相同數字的方塊往一個方向移動會合併成更大的數字。<br>
             當最大數字出現2048時,游戲勝利!<br>
             溫馨提示:你可以使用空格鍵回退上一步。
            </span>
        </div>
        <div id="rights">
            <span>
                All rights reserved to S.C. Contact me at [email protected]. 
            </span>
        </div>
    </div>
    
    <!-- 操作 -->
    <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: '微軟雅黑';
    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

// 拼成了2048,凍結操作,不允許移動了
var flagSuccess = false;
// 剛纔點擊了回退,不允許重覆點擊,要移動之後再點擊
var clickedLastStep = false;

// 記錄上一步,用於回退
var lastStepArray = [
                       [0,0,0,0],
                       [0,0,0,0],
                       [0,0,0,0],
                       [0,0,0,0]
                     ];

// 數組初始化--正常初始化
var arrayInit = 
    [
     [0,0,0,0],
     [0,0,0,0],
     [0,0,0,0],
     [0,0,0,0]
   ];
//[//調試--將要success
// [0,0,0,0],
// [0,128,0,0],
// [0,0,512,1024],
// [0,0,0,1024]
//];
//[//調試--將要fail
// [1,2,3,4],
// [5,128,6,7],
// [8,9,512,1024],
// [13,22,11,11]
//];



// 頁面載入初始化
function pageInit()
{
    addHelper();
    
//    initArray();
    // 頁面元素初始化(單元格)
    initElements();
    
    // 初始數據
    initTwoPositions();
    
    // 根據初始數據給單元格填充值
    updatePageByArray();
    
    // 根據單元格的值給單元格設置樣式
    updateColor();
}

// 重新開始
function gameRestart(){
    initArray();
    pageInit();
}

function initArray(){
    flagSuccess = false;
    arrayInit = createNewArray();
    clickedLastStep = false;
    lastStepArray = createNewArray();
}


// 給兩個位置設置數字2
function initTwoPositions()
{
    initOnePosition(arrayInit);
    initOnePosition(arrayInit);
}
// 給一個位置設置數字2
function initOnePosition(array){
    // 取隨機數方式1
//    var num = getRamdom(16);
//    var line = Math.floor(num/4);
//    var col = num % 4;
//    var curNum = array[line][col];
//    if (curNum == 0)
//    {
//        // 成功找到空閑位置
//        array[line][col] = 2;
//        return true;
//    }
//    else{
//        // 遞歸調用,必須找到一個可用位置才算完
//        return initOnePosition(array);
//    }
    
    // 取隨機數方式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;
}

// 生成隨機數,轉化成0-15的整數;
function getRamdom(count)
{
    // 0-1
    var r0 = Math.random();
    // 0-16
    var r1 = r0 * count;
    // 只取整數位數的數
    return Math.floor(r1);
}

// 改進:只在當前可用位置中隨機找,不用找不可用的位置 
function getOneEmptyCoordinate(array)
{
    // 1. 得到當前數組
    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;
            }
        }
    }
    // 取可用位置的隨機位置
    var random = getRamdom(countEmptyCells);
    return mapIndex2Coordinate[random];
}

 

eventListener,js

/**
 *  引用工具類
 */
function addHelper(){
    var newscript = document.createElement('script');  
    newscript.setAttribute('type','text/javascript');  
    newscript.setAttribute('src','../js/arrayHelper.js');  
    document.body.appendChild(newscript);  
}

//捕捉按鍵事件
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(){
    // 回退上一步
    if (clickedLastStep){
        console.log('can not move back again');
        return;
    }
    moveBack();
    flagSuccess = false;
    clickedLastStep = true;
}

// 回退上一步
function moveBack(){
    // 判斷上一步全是0(剛剛初始化)
    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. 用備份的數組給當前數組設置值
    updateFrontArray(arrayInit,lastStepArray);
    
    // 3. 更新頁面
    updatePageByArray();
    updateColor();
}

// 通用方法
// 所有移動都轉換成一個方向上的移動:例如,都想象成向左移動,只需要倒轉數組即可,完成移動再倒轉回來!
function move(direction){
    if (flagSuccess){
        if (confirm("You've got your 2048! Start Another One?\n已經通關!開始新游戲?")){
            gameRestart();
        }
        return;
    }
    
    // 移動之前,記錄上一步的內容,移動失敗之後可以恢復
    var lastStepUnchange = createNewArray();
    updateFrontArray(lastStepUnchange,lastStepArray);
    // 將上一步狀態設置為當前的
    updateFrontArray(lastStepArray,arrayInit);
    
    // 將當前的去更新,更新失敗則回滾上一步的狀態
    // 1. 數組倒轉複製
    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. 都向一個方向移動
    var moveResult = moveLeft(arrayCopy);
    if ('fail' == moveResult){
        
        updateFrontArray(lastStepArray,lastStepUnchange);
        // 移動失敗,沒有任何改變
        if (confirm('Game Over! Try again?\n游戲結束,再來一次?')){
            gameRestart();
            return;
        }else{
            // 最後一步了,允許回退
            clickedLastStep = false;
            return;
        }
        return;
    }
    if ('unmoved' == moveResult){
        return;
    }
    
    // 3. 從倒轉的數組更新原數組
    if (direction == 'left'){
        restoreArrayLeft(arrayCopy);
    }else if (direction == 'right'){
        restoreArrayRight(arrayCopy);
    }else if (direction == 'up'){
        restoreArrayUp(arrayCopy);
    }else if (direction == 'down'){
        restoreArrayDown(arrayCopy);
    }
    
    // 4. 根據數字更新頁面元素
    updatePageByArray();
    updateColor();
    
    if ('success' == moveResult){
        // 因為操作DOM不是實時的,所以要等一段事件操作完成之後再彈出確認框
        setTimeout(function(){
            // 游戲通關,是否重新開始
            if (confirm('Congragulations! Start Another Game?\n恭喜通關!是否再來一把?')){
                gameRestart();
            }else{
                flagSuccess = true;
            }
        },200);
        return;
    }
    
    // 移動完成
    clickedLastStep = false;
}

// 向一個方向移動,更新數組(左),其他方向也是一樣的
function moveLeft(arrayCopy){
    var gameSuccess = false;
    
    // 是否有合併或者移動,如果沒有合併也沒有移動,就是沒有操作那就不要生成新的數字
    var anyChange = false;
    // 每一行,從【左】往【右】對比是否有一樣的數字(排除0)--並不需要挨著!中間隔了空氣也可以合併
    for (var i=0;i<4;i++){
        var firstIndex = 0;
        var secondIndex = 1;
        while (secondIndex<4){
            if (arrayCopy[i][firstIndex] == 0){
                // 第一個是0,不可能有合併,往後移動
                firstIndex++;
                secondIndex++;
                continue;
            }
            if (arrayCopy[i][secondIndex] == 0){
                // 第二個是0,第二個繼續往後找,第一個不變
                secondIndex++;
                // 1. 後面找不到數字,一直往後找,結束迴圈
                continue;
            }            
            // 有一次一樣的數字:計算得到和,放到第一個位置,這一行完了
            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){
                    // 得到了2048,游戲結束
                    gameSuccess = true;
                }
                // 2. 後面找到數字,且可以合併,就合併,結束迴圈
                break;
            }
            else{
                // 3. 後面找到數字,但是不能合併,更新第一個數字為當前數字,第二個數字為下一個數字
                firstIndex = secondIndex;
                secondIndex += 1;
                continue;
            }
        }
    }
    
    // 將每一行數字向【左】挪動
    for (var i=0;i<4;i++){
        var newLine = [];//臨時存儲從【左】到【右】的非0數字
        var index = 0;
        for (var j=0;j<4;j++){
            if (arrayCopy[i][j] != 0){
                newLine[index] = arrayCopy[i][j];
                index++;
            }
        }
        
        // 用臨時存儲的數字給數組更新
        for (var m=0;m<index;m++){
            if (arrayCopy[i][m] != newLine[m]){
                anyChange = true;
            }
            arrayCopy[i][m] = newLine[m];
        }
        // 剩餘的位置給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)){
            // 本步不能移動,且沒有剩餘格子,且任意相鄰格子沒有相同的,就結束游戲
            if (!canMerge(arrayCopy)){
                console.log("Game Over! Try again.");
                return 'fail';
            }
        }
        if (gameSuccess){
            return 'success';
        }
        // 沒有移動
        return 'unmoved';
    }
    
    // 給空

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文為mariadb官方手冊:HIGH_PRIORITY and LOW_PRIORITY的譯文。 原文:https://mariadb.com/kb/en/high_priority-and-low_priority/ 我提交到MariaDB官方手冊的譯文:https://mariadb.com/ ...
  • 本文為mariadb官方手冊:LOAD DATA INFILE的譯文。 原文:https://mariadb.com/kb/en/load-data-infile/ 我提交到MariaDB官方手冊的譯文:https://mariadb.com/kb/zh-cn/load-data-infile/ 回 ...
  • 結論:getMeasuredWidth()獲取的是view原始的大小,也就是這個view在XML文件中配置或者是代碼中設置的大小。getWidth()獲取的是這個view最終顯示的大小,這個大小有可能等於原始的大小也有可能不等於原始大小。 1.getMeasuredWidth 從源碼上來看,getM ...
  • ImageView是用於界面上顯示圖片的控制項。 屬性 1、為ImageView設置圖片 ①android:src="@drawable/img1"; src設置圖片,預設圖片等比例放縮,以最適應的大小顯示。 ②android:background="@drawable/img1" backgroun ...
  • 【說明】 TextView是用來顯示文本的組件。以下介紹的是XML代碼中的屬性,在java代碼中同樣可通過 ”組件名.setXXX()方法設置。如,tv.setTextColor(); 【屬性一】 【屬性二】 【屬性三】 【屬性四】 【屬性五】為TextView中的文字設置鏈接 【效果】 【提示】 ...
  • 我的主博客在CSDN,這裡只有部分文章,這是地址https://blog.csdn.net/z979451341 ...
  • n CSS浮動和清除 Float:讓元素浮動,取值:left(左浮動)、right(右浮動)。 Clear:清除浮動,取值:left(清除左浮動)、right(清除右浮動)、both(同時清除上面的左浮動和右浮動)。 1、CSS浮動 l 浮動的元素將向左或向右浮動,浮動到包圍元素的邊上,或上一個浮動 ...
  • 依賴註入是一種使程式的一部分能夠訪問另一部分的系統,並且可以通過配置控制其行為。 “註入”可以理解為是“new”操作符的一種替代,不再需要使用編程語言所提供的"new"操作符,依賴註入系統管理對象的生成。 依賴註入的最大好處是組件不再需要知道如何建立依賴項。它們只需要知道如何與依賴項交互。 在Ang ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...