乐趣区

关于javascript:数独游戏的前端实现

之前学习目标写的一个数独游戏,用 jquery 模块模式、mvc 模式实现的。

1. controller.sudoku.js

// Controller Sudoku.js
(function ($) {$(function () {
        'use strict';

        // Get filled numbers from html tables
        var getTableNums = function () {var inputArr = [[], [], [], [], [], [], [], [], []];
            var allowNums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
            $('.sudoku_cell').each(function () {var data = $(this).data('val').split('-');
                var val = $(this).val();
                val = (val === '') ? null : parseInt(val);
                if (val !== null && allowNums.indexOf(val) === -1) {alert('Number allowed only between 0-9');
                    return null;
                }
                var r = parseInt(data[0]);
                var c = parseInt(data[1]);

                inputArr[r] = val;
            });

            return inputArr;
        };

        // Fill numbers to html tables
        var assignTableNums = function (solution) {$('.sudoku_cell').each(function () {var data = $(this).data('val').split('-');
                var r = parseInt(data[0]);
                var c = parseInt(data[1]);

                $(this).val(solution[r]);
            });
        };

        // Reset
        $('#sudoku-reset-btn').click(function () {$('.sudoku_cell').val(null);
        });

        // Start
        $('#sudoku-start-btn').click(function () {
            // Get numbers from HTML
            var inputArr = getTableNums();
            if(inputArr === null) return;

            // Call module Sudoku
            var sudoku = new SOLEIL.Sudoku(inputArr);
            var solution = sudoku.Go();
            if(solution === null) return;

            // Assign data to HTML
            assignTableNums(solution);
        });

        // Examples data
        $('#sudoku-exp-btn').click(function () {
            // random number
            var min = Math.ceil(0);
            var max = Math.floor(1);
            var num = Math.floor(Math.random() * (max - min + 1)) + min;
            var inputArr = [
                [[null, 7, 6, null, 1, null, null, 4, 3],
                    [null, null, null, 7, null, 2, 9, null, null],
                    [null, 9, null, null, null, 6, null, null, null],
                    [null, null, null, null, 6, 3, 2, null, 4],
                    [4, 6, null, null, null, null, null, 1, 9],
                    [1, null, 5, 4, 2, null, null, null, null],
                    [null, null, null, 2, null, null, null, 9, null],
                    [null, null, 4, 8, null, 7, null, null, 1],
                    [9, 1, null, null, 5, null, 7, 2, null]
                ],
                [[1, null, null, null, 3, null, 5, 9, null],
                    [3, null, null, 5, null, null, null, 2, null],
                    [null, 5, null, 9, null, 2, 6, 3, 8],
                    [4, 3, null, null, null, null, null, null, null],
                    [null, null, null, 6, null, 1, null, null, null],
                    [null, null, null, null, null, null, null, 8, 7],
                    [6, 4, 7, 3, null, 8, null, 5, null],
                    [null, 1, null, null, null, 5, null, null, 9],
                    [null, 9, 2, null, 7, null, null, null, 3]
                ]
            ];

            // Assign data to HTML
            assignTableNums(inputArr[num]);
        });

    })
})(jQuery);

2. module.sudoku.js

// Module Sudoku .js
SOLEIL.Sudoku = function (inputArr) {
    "use strict";
    // private
    var possiArr = [];

    /**
     * Remove an element form array
     * @param {Array} arr
     * @param elem
     * @returns {*}
     */
    var removeElem = function (arr, elem) {var index = arr.indexOf(elem);
        if (index > -1) {arr.splice(index, 1);
        }
        return arr;
    };

    /**
     * Return sum of filled numbers
     * @returns {number}
     */
    var totalResult = function () {
        var total = 0;
        for (var i = 0; i < inputArr.length; i++) {for (var j = 0; j < inputArr[i].length; j++) {if (inputArr[i][j] !== null) {total++;}
            }
        }
        return total;
    };

    /**
     * Create a shadow array to assist calculating
     */
    var fillPossi = function () {for (var r = 0; r < inputArr.length; r++) {possiArr[r] = [];
            for (var c = 0; c < inputArr[r].length; c++) {possiArr[r] = (inputArr[r] === null) ? [1, 2, 3, 4, 5, 6, 7, 8, 9] : null;
            }
        }
    };

    /**
     * Search possibilities of sudoku
     */
    var searchPossi = function () {
        var rr, cc, r, c, blocR, blocC;
        for (r = 0; r < possiArr.length; r++) {for (c = 0; c < possiArr[r].length; c++) {if (possiArr[r] === null) {

                    // row 1x9
                    for (cc = 0; cc < possiArr[r].length; cc++) {if (possiArr[r][cc] !== null) { // cell to resolve
                            possiArr[r][cc] = removeElem(possiArr[r][cc], inputArr[r]);
                        }
                    }

                    // column 9x1
                    for (rr = 0; rr < possiArr.length; rr++) {if (possiArr[rr] !== null) { // cell to resolve
                            possiArr[rr] = removeElem(possiArr[rr], inputArr[r]);
                        }
                    }

                    // block 3x3
                    blocR = Math.floor(r / 3);
                    blocC = Math.floor(c / 3);
                    for (rr = 3 * blocR; rr < 3 * (blocR + 1); rr++) {for (cc = 3 * blocC; cc < 3 * (blocC + 1); cc++) {if (rr !== r && cc !== c && possiArr[rr][cc] !== null) { // cell to resolve
                                possiArr[rr][cc] = removeElem(possiArr[rr][cc], inputArr[r]);
                            }
                        }
                    }
                }
            }
        }
    };

    /**
     * Find the unique answer for one cell
     * @returns {boolean}
     */
    var fillResult = function () {
        var r, c, found = false;
        for (r = 0; r < possiArr.length; r++) {for (c = 0; c < possiArr[r].length; c++) {if (possiArr[r] !== null && possiArr[r].length === 1) {
                    // unique answer
                    found = true;
                    inputArr[r] = possiArr[r][0];
                    possiArr[r] = null;
                }
            }
        }
        return found;
    };

    // public
    return {Go: function () {
            // Init an show array to calculate possibilities
            fillPossi();

            // Recursive to find unique number
            while (totalResult() < 81) {searchPossi();
                if (fillResult() === false) {alert('No found result');
                    inputArr = null;
                    break;
                }
            }
            return inputArr;
        }
    };
};

3. tpl.sudoku.html

<div class="sudoku table-responsive">
    <table class="table table-bordered">
        <?php
        for ($row = 0; $row < 9; $row++) {
            echo '<tr>';
            for ($col = 0; $col < 9; $col++) {
                // Border style
                $styleTD = '';
                if ($row === 0) {$styleTD .= 'border-top: 1px solid #000;';}
                if ($row % 3 === 2) {$styleTD .= 'border-bottom: 1px solid #000;';}
                if ($col === 0) {$styleTD .= 'border-left: 1px solid #000;';}
                if ($col % 3 === 2) {$styleTD .= 'border-right: 1px solid #000;';}

                echo '<td style="' . $styleTD . '"">';
                echo '<input type="text"maxlength="1"data-val="' . $row . '-' . $col . '"class="sudoku_cell"autocomplete="false"/>';
                echo '</td>';
            }
            echo '</tr>';
        }
        ?>
    </table>

    <button id="sudoku-reset-btn" class="btn btn-danger">Reset</button>
    <button id="sudoku-start-btn" class="btn btn-success">Search solution</button>
    <button id="sudoku-exp-btn" class="btn btn-info">Generate sudoku</button>
</div>
退出移动版