Learn Javascript by hand-PopStar

Links to the original text: http://www.cnblogs.com/riasky/p/3471579.html

PopStar is a popular mobile game. Its basic rule is to click on a box. If there are squares of the same color around the box, they are all selected. Then click on one of the selected squares again, and all the selected squares will disappear.

As shown in the figure below, seven green squares are selected (the selected squares are surrounded by white boxes):


Click the selected box again and the green ones will disappear. If the top of these squares is the other one, the top one will fall off. If a column disappears, the column on the right moves left automatically. The effect of seven selected green squares disappearing is as follows:


The HTML code is as follows:

 

<!DOCTYPE html>
<html>
    <head>
        <meta charset=utf-8 />
        <title>PopStar</title>
        <link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
        <script src="http://code.jquery.com/jquery-1.9.1.js"></script>
        <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
        <script src="PopStar.js" type="text/javascript">
        </script>
        <link rel="stylesheet" type="text/css" href="PopStar.css" />
    </head>
    <body>
        <h1>Welcome to PopStar</h1>
        <div id="totalScore">Total Score: 0</div>
        <div id="currentScore">Click to Select.</div>
        <div id="mainCanvas">
        </div>
        <div id="notification">
            <div id="message"></div>
        </div>
    </body>
</html>

As you can see from the above code, we will use the related functions of JQuery and jQuery UI.

 

The code for CSS is as follows:

 

#mainCanvas {
    background-color: black;
    width: 300px;
    height: 300px;
}

.block {
    position: fixed;
    height: 28px;
    width: 28px;
    border-radius: 4px;
}

.selected {
    height: 26px;
    width: 26px;
    border-color: white;
    border-style: solid;
    border-width: 1px;
}

CSS defines the background of the game and the appearance of the box (checked or unchecked).

 

The main functions of the game are implemented in Javascript, as follows:

 

$(document).ready(function () {
    var sharedData;
    initGame();
    startGame();

    function initGame() {
        sharedData = {};
        sharedData.size = 10;

        var canvas = $('#mainCanvas');
        var width = parseInt(canvas.css('width'));
        var height = parseInt(canvas.css('height'));
        if (width != height) {
            alert('the canvas should be a square.');
        }
        sharedData.canvas = canvas;
        sharedData.blockLength = width / sharedData.size;
        sharedData.matrix = initMatrix();

        $('#notification').dialog({
            width: 400,
            resizable: false,
            modal: true,
            buttons: [{ text: "Ok", click: function () { $(this).dialog("close"); location.reload(); } }]
        });
    }

    function startGame() {
        sharedData.size = 10;
        sharedData.status = 0; // possible values: 0, 1
        sharedData.totalScore = 0;

        clearMatrix();

        initBlocks(sharedData);
        moveBlocks();

        clearCurrentScore();
        clearTotalScore();
        hideNotification();

        if (isGameOver()) {
            showNotification();
        }
    }

    function initBlocks(data) {
        var size = data.size;
        var row, col, value;
        var singleColor = size * size / 4;
        var divString;
        var newRow, newCol, index;

        $('.block').each(function () {
            $(this).remove();
        });

        var randomArray = getRandomArray(data.size);

        for (row = 0; row < size; ++row) {
            for (col = 0; col < size; ++col) {
                if (row * size + col < singleColor) {
                    value = 1;
                }
                else if (row * size + col < singleColor * 2) {
                    value = 2;
                }
                else if (row * size + col < singleColor * 3) {
                    value = 3;
                }
                else {
                    value = 4;
                }
                
                index = randomArray[row * size + col];
                newRow = Math.floor(index / size);
                newCol = index % size;

                divString = '<div class="block" currow="0" curcol="0" nextrow="' + newRow.toString()
                    + '" nextcol="' + newCol.toString() + '" value="' + value.toString() + '"></div>';
                $('#mainCanvas').append(divString);
            }
        }
    }

    function getRandomArray(size) {
        var total = size * size;
        var array = new Array(total);
        var i, index, temp;
        
        for (i = 0; i < array.length; ++i) {
            array[i] = i;
        }
        
        for (i = array.length - 1; i > 0; --i) {
            index = Math.floor(Math.random() * total);

            temp = array[i];
            array[i] = array[index];
            array[index] = temp;
        }
        
        return array;
    }

    function moveBlocks() {
        $('.block').each(function () {
            var nextRow = $(this).attr('nextrow');
            var nextCol = $(this).attr('nextcol');
            var value = $(this).attr('value');
            var parentPos = $(this).parent().offset();
            var top = parseInt(nextRow) * sharedData.blockLength + parentPos.top + 1;
            var left = parseInt(nextCol) * sharedData.blockLength + parentPos.left + 1;
            var cssTop = top.toString() + 'px';
            var cssLeft = left.toString() + 'px';
            var colors = ['#aaaaaa', '#3333cc', '#33cc33', '#cc3333', '#cccc33'];

            $(this).animate({
                top: cssTop,
                left: cssLeft
            },
            500);

            $(this).css({
                'background-color': colors[parseInt(value)]
            });

            $(this).attr('currow', nextRow);
            $(this).attr('curcol', nextCol);
        });
    }

    $('.block').click(function () {
        var clickedBlock = getClickedBlockPos($(this));
        var sameColorBlocks;

        clearMatrix();
        sameColorBlocks = getBlocksWithSameColor(clickedBlock.row, clickedBlock.col);
        updateStatus(clickedBlock.row, clickedBlock.col, sameColorBlocks);
    });

    function updateStatus(row, col, sameColorBlocks) {
        if (sameColorBlocks.length > 1) {
            if (sharedData.status == 0) {
                sharedData.status = 1;
                setSelectedBlocks(sameColorBlocks);
            }
            else {
                if (isClickAgain(row, col, sameColorBlocks)) {
                    moveMatrix(sharedData.matrix, sameColorBlocks);
                    sharedData.status = 0;
                    updateTotalScore(sharedData, sameColorBlocks.length);
                    clearSelectedBlocks();
                    moveBlocks();

                    clearMatrix();
                    if (isGameOver()) {
                        showNotification();
                    }
                }
                else {
                    setSelectedBlocks(sameColorBlocks);
                }
            }
        }
        else if (sharedData.status == 1) {
            sharedData.status = 0;
            clearSelectedBlocks();
        }
    }

    function moveMatrix(matrix, sameColorBlocks) {
        moveMatrixDown(matrix, sameColorBlocks);
        moveMatrixLeft(matrix);
        deleteBlocks();
        updateBlockPosition();
    }

    function updateBlockPosition() {
        $('.block').each(function () {
            var curRow = parseInt($(this).attr('currow'));
            var curCol = parseInt($(this).attr('curcol'));

            var moveDown = sharedData.matrix[curRow][curCol].moveDown;
            var moveLeft = sharedData.matrix[curRow][curCol].moveLeft;

            var nextRow = curRow + moveDown;
            var nextCol = curCol - moveLeft;

            $(this).attr('nextrow', nextRow.toString());
            $(this).attr('nextcol', nextCol.toString());
        });
    }

    function deleteBlocks() {
        $('.block').each(function () {
            var curRow = parseInt($(this).attr('currow'));
            var curCol = parseInt($(this).attr('curcol'));
    
            if (sharedData.matrix[curRow][curCol].value == 0) {
                $(this).remove();
            }
        });
    }

    function moveMatrixDown(matrix, toBeDeleted) {
        var i, j;

        toBeDeleted.sort(sortPosition);

        for (i = 0; i < toBeDeleted.length; ++i) {
            matrix[toBeDeleted[i].row][toBeDeleted[i].col].value = 0;

            for (j = toBeDeleted[i].row ; j >= 0; --j) {
                matrix[j][toBeDeleted[i].col].moveDown += 1;
            }
        }
    }

    function moveMatrixLeft(matrix) {
        for (i = 0; i < matrix.length; ++i) {
            if (isColumnBlank(matrix, i)) {
                moveColumnsLeft(matrix, i);
            }
        }
    }

    function moveColumnsLeft(matrix, col) {
        var i, j;
        for(i = 0; i < matrix.length; ++i) {
            for (j = col + 1; j < matrix.length; ++j)
                matrix[i][j].moveLeft += 1;
            }
    }

    function isColumnBlank(matrix, col) {
        var row;
        for (row = 0; row < matrix.length; ++row) {
            if (matrix[row][col].value != 0)
                return false;
        }

        return true;
    }

    function sortPosition(pos1, pos2) {
        if ((pos1.col < pos2.col) || (pos1.col == pos2.col && pos1.row > pos2.row))
            return -1;
        if (pos1.col == pos2.col && pos1.row == pos2.row)
            return 0;
        return 1;
    }

    function setSelectedBlocks(sameColorBlocks) {
        $('.block').each(function () {
            if ($(this).hasClass('selected')) {
                $(this).removeClass('selected');
            }
        });

        $('.block').each(function () {
            var curRow = parseInt($(this).attr('currow'));
            var curCol = parseInt($(this).attr('curcol'));

            if(isSelected(sameColorBlocks, curRow, curCol) && !$(this).hasClass('selected')) {
                $(this).addClass('selected');
            }
        });

        setCurrentScore(sameColorBlocks.length);
    }

    function isSelected(sameColorBlocks, row, col) {
        for (var i = 0; i < sameColorBlocks.length; ++i) {
            if (sameColorBlocks[i].row == row && sameColorBlocks[i].col == col) {
                return true;
            }
        }

        return false;
    }

    function clearSelectedBlocks() {
        $('.block').each(function () {
            if ($(this).hasClass('selected')) {
                $(this).removeClass('selected');
            }
        });

        clearCurrentScore();
    }

    function getClickedBlockPos(block) {
        var curRow = parseInt(block.attr('currow'));
        var curCol = parseInt(block.attr('curcol'));

        return {
            row: curRow,
            col: curCol
        };
    }

    function initMatrix() {
        var i, j;
        var size = sharedData.size;
        var rows = new Array(size);

        for (i = 0; i < size; ++i) {
            rows[i] = new Array(size);
            for (j = 0; j < size; ++j) {
                rows[i][j] = {
                    value: 0,
                    moveDown: 0,
                    moveLeft: 0
                };
            }
        }

        return rows;
    }

    function clearMatrix() {
        var i, j;
        var size = sharedData.size;
        var matrix = sharedData.matrix;

        for (i = 0; i < size; ++i) {
            for (j = 0; j < size; ++j) {
                matrix[i][j] = {
                    value: 0,
                    moveDown: 0,
                    moveLeft: 0
                };
            }
        }

        $('.block').each(function () {
            var value = parseInt($(this).attr('value'));
            var curRow = parseInt($(this).attr('currow'));
            var curCol = parseInt($(this).attr('curcol'));
            sharedData.matrix[curRow][curCol].value = value;
        });
    }

    function getBlocksWithSameColor(row, col) {
        var matrix = sharedData.matrix;
        var value = matrix[row][col].value, curValue;
        var matrixSize = matrix[0].length;
        var visited = new Array();
        var top, curRow, curCol, preRow, preCol;
        var sameColor = new Array();
        var i;

        var flag = new Array(matrixSize * matrixSize);
        for (i = 0; i < flag.length; ++i) {
            flag[i] = false;
        }

        addBlockWithSameColor(matrix, visited, sameColor, flag, row, col);

        while (visited.length > 0) {
            top = visited.pop();

            // left
            curRow = top.row;
            curCol = top.col - 1;
            addBlockWhenWithSameColor(matrix, value, visited, sameColor, flag, curRow, curCol);

            // right
            curRow = top.row;
            curCol = top.col + 1;
            addBlockWhenWithSameColor(matrix, value, visited, sameColor, flag, curRow, curCol);

            // up
            curRow = top.row - 1;
            curCol = top.col;
            addBlockWhenWithSameColor(matrix, value, visited, sameColor, flag, curRow, curCol);

            // down
            curRow = top.row + 1;
            curCol = top.col;
            addBlockWhenWithSameColor(matrix, value, visited, sameColor, flag, curRow, curCol);
        }

        return sameColor;
    }

    function addBlockWithSameColor(matrix, visited, sameColor, flag, row, col) {
        var cell = {
            row: row,
            col: col
        };

        visited.push(cell);
        sameColor.push(cell);
        flag[row * matrix[0].length + col] = true;
    }

    function addBlockWhenWithSameColor(matrix, value, visited, sameColor, flag, curRow, curCol) {
        var matrixSize = matrix.length;
        var isOnBoundaryOrDiffColor = curRow >= 0 && curRow < matrixSize &&
            curCol >= 0 && curCol < matrixSize &&
            matrix[curRow][curCol].value == value;
        if (isOnBoundaryOrDiffColor && !flag[curRow * matrixSize + curCol]) {
            addBlockWithSameColor(matrix, visited, sameColor, flag, curRow, curCol);
        }
    }

    function isClickAgain(row, col, sameColor) {
        var result = false;

        $('.block').each(function () {
            var curRow = parseInt($(this).attr('currow'));
            var curCol = parseInt($(this).attr('curcol'));

            if(isSelected(sameColor, curRow, curCol) && $(this).hasClass('selected')) {
                result = true;
            }
        });

        return result;
    }

    function setCurrentScore(num) {
        var score = getScore(num);
        $('#currentScore').html('Selection Score: ' + score.toString());
    }

    function clearCurrentScore() {
        $('#currentScore').html('Click to Slect.');
    }

    function clearTotalScore() {
        $('#totalScore').html('Total Score: 0');
    }

    function getScore(num) {
        return 5 * num * num;
    }

    function updateTotalScore(data, num) {
        var score = getScore(num);
        data.totalScore += score;
        $('#totalScore').html('Total Score: ' + data.totalScore.toString());
    }

    function hideNotification() {
        $('#notification').dialog('close');
    }

    function showNotification() {
        $('#message').html('Game over. Click Ok to restart.');
        $('#notification').dialog('open');
    }

    function isGameOver() {
        var over = true;
        var curRow, curCol;
        var sameColor;

        $('.block').each(function () {
            if (over) {
                curRow = parseInt($(this).attr('currow'));
                curCol = parseInt($(this).attr('curcol'));

                sameColor = getBlocksWithSameColor(curRow, curCol);
                if (sameColor.length > 1) {
                    over = false;
                }
            }
        });

        return over;
    }
});

If you are interested in the above code, you can also go to http://download.csdn.net/detail/haitaohe/6702475 Download here.

 

 

Reprinted at: https://www.cnblogs.com/riasky/p/3471579.html

Keywords: JQuery Javascript Mobile

Added by kef on Wed, 31 Jul 2019 19:39:25 +0300