首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JavaScript中的数独游戏

JavaScript中的数独游戏
EN

Code Review用户
提问于 2020-03-21 20:47:48
回答 2查看 8.1K关注 0票数 6

这里的PHP编码器。本周学习JavaScript。我做了一场sudoku游戏供练习。功能:

  • 通过粘贴文本字符串导入谜题。
  • 进口方块是灰色的。你的方块是白色的。
  • 程序不允许你做出明显的非法举动。它将空白您的号码和颜色方红色2秒。
  • sudoku拼图/游戏是一门课。以后很容易向它添加方法和特性。
  • 增长的空间。我可能会添加一个“解决”按钮和“给予提示”复选框后。我可以在你赢的时候加上一个“你赢了”的信息。

我希望从这篇代码评论中得到一些好处。

  • 让我们关注JavaScript。对JavaScript代码的组织、样式、函数的选择、变量和函数名称等的改进。
  • 如果你想要的话,可以完全重构。
  • 寻找专业的编码器视角,这样我就可以建立良好的习惯。
  • 请随意建议下一步/下一步的功能。

小提琴- https://jsfiddle.net/AdmiralAkbar2/z6rv70h4/37/

截图

JavaScript

代码语言:javascript
复制
// TODO: solve button
// TODO: show hints
    // if 8 squares in a 3x3 are known, highlight 9th square
    // if 8 squares in a row are known, highlight 9th square
    // if 8 squares in a column are known, highlight 9th square

"use strict";

class Sudoku {
  constructor() {
        this.board = this.blank_board_array();
    }
    
    blank_board_array() {
        return [
            [0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0]
        ];
    }

  // I can't figure out how to get this working with the "set" keyword, so making a method for now
    set_board(board_string) {
        if ( ! board_string.match(/^\d{81}$/m) ) {
            this.board = this.blank_board_array();
            return;
        }
        
        for ( let row = 0; row <= 8; row++ ) {
            for ( let column = 0; column <= 8; column++ ) {
                this.board[row][column] = board_string.charAt(row*9+column);
            }
        }
        
        /*
        if ( ! this.puzzle_is_valid() ) {
            this.board = this.blank_board_array();
            return;
        }
        */
    }
    
    get_board_array() {
        return this.board;
    }
    
    make_move(row, col, value) {
        this.board[row][col] = value;
    }
    
    is_legal_move(row, col, value) {
        // check for non numbers
      // weird that JS match function doesn't put quotes around regex
        if ( ! value.match(/^[1-9]$/m) ) {
            return false;
        }
        
        // check row
        for ( let i = 0; i <= 8; i++ ) {
            if ( value == this.board[row][i] ) {
                return false;
            }
        }
        
        // check column
        for ( let i = 0; i <= 8; i++ ) {
            if ( value == this.board[i][col] ) {
                return false;
            }
        }
        
        // check 3x3 grid
        let row_offset = Math.floor(row/3)*3;
        let col_offset = Math.floor(col/3)*3;
        for ( let i = 0 + row_offset; i <= 2 + row_offset; i++ ) {
            for ( let j = 0 + col_offset; j <= 2 + col_offset; j++ ) {
                if ( value == this.board[i][j] ) {
                    return false;
                }
            }
        }
        
        return true;
    }
};

let game1 = new Sudoku();
let import_string;
let import_button = document.getElementById('import');
let sudoku_squares = createArray(9,9);

for ( let row = 0; row <= 8; row++ ) {
    for ( let col = 0; col <= 8; col++ ) {
        sudoku_squares[row][col] =  document.getElementsByClassName('sudoku')[0].getElementsByTagName('tbody')[0].getElementsByTagName('tr')[row].getElementsByTagName('td')[col].getElementsByTagName('input')[0];
    }
}

import_button.addEventListener("mouseup", function() {
    import_string = document.getElementsByName("import_string")[0].value;
  game1.set_board(import_string);
    print_sudoku_to_webpage(game1);
});

for ( let row = 0; row <= 8; row++ ) {
    for ( let col = 0; col <= 8; col++ ) {
        sudoku_squares[row][col].addEventListener('input', function(e) {
            e.target.classList.remove("invalid");
            
            if ( ! game1.is_legal_move(row, col, e.target.value) && e.target.value != "" ) {
              e.target.value = "";
                highlight_temporarily(e.target, 2000);
            } else {
                game1.make_move(row, col, e.target.value);
            }
        });
    }
}

function print_sudoku_to_webpage(sudoku_object) {
    let board = sudoku_object.get_board_array();
    clear_webpage_board();
    for ( let row = 0; row <= 8; row++ ) {
        for ( let col = 0; col <= 8; col++ ) {
            if ( board[row][col] != 0 ) {
                let input = sudoku_squares[row][col];
                input.value = board[row][col];
                input.classList.add('imported_square');
            }
        }
    }
}

function clear_webpage_board() {
    for ( let row = 0; row <= 8; row++ ) {
        for ( let col = 0; col <= 8; col++ ) {
            sudoku_squares[row][col].value = "";
            sudoku_squares[row][col].classList.remove('imported_square');
        }
    }
}

// This code is borrowed from another website. Thanks google.
function createArray(length) {
    var arr = new Array(length || 0),
        i = length;

    if (arguments.length > 1) {
        var args = Array.prototype.slice.call(arguments, 1);
        while(i--) arr[length-1 - i] = createArray.apply(this, args);
    }

    return arr;
}

function highlight_temporarily(obj, timeout_in_ms){
   obj.classList.add('invalid');
   setTimeout(function(){
        obj.classList.remove('invalid');
   }, timeout_in_ms);
}

代码语言:javascript
复制
    Sudoku




    
    

    Import

CSS

代码语言:javascript
复制
body {font-family:sans-serif;}

.import {padding-bottom:0.2em;}
.import input[type=text] {width:630px;}

.valid {background-color:limegreen;}
.invalid {background-color:red;}
.imported_square {background-color:lightgray;}

.sudoku {border:4px solid black; border-collapse: collapse;}
.sudoku tr {padding:0;}
.sudoku td {padding:0; border:1px solid black; width:1em;}
.sudoku input {width:1em; border:0; font-size:25pt; text-align:center;}
.sudoku .thick_right {border-right:4px solid black !important;}
.sudoku .thick_bottom {border-bottom:4px solid black;}
EN

回答 2

Code Review用户

发布于 2020-03-24 23:06:00

在现有审查的基础上,我注意到以下几点:

  • 您混淆了under_score (clear_webpage_board)和camelCase命名(createArray)。javascript中的函数通常使用camelCase (您可以在使用的所有内置方法中看到这一点,包括借用的createArray)。
  • 另一方面,Css通常使用命名,其中使用破折号,所以是thick-right,而不是thick_right。是的,每种技术都有不同的约定命名,这有点烦人。
  • 我不太喜欢你的名字。print_sudoku_to_webpage。该方法将数据与表示它的html元素同步。我会称它为displayBoard或其他什么东西(因为你在另一个函数中称它为“板”)。print感到不舒服,你什么都不印。webpage也是(嗯,我们知道你在网页上)。clear_webpage_board再次放弃webpage,没有意义。
  • 如果我希望在一页上有更多的sudoku板,如何使用您的代码?这是行不通的,因为你总是在寻找具有"sudoku“类的第一个元素。感觉上应该有一个类表示Sudoku,独立于HTML (您有),然后应该有另一个类,它可以在UI中显示它,处理事件并将这些事件传递给游戏本身。该类可以使用类"sudoku“了解这个”根元素“,并使用querySelector作为我们在其他答案中的同事来查找其中的其他部分。这也将清理您的所有循环和代码,它在任何地方都没有功能。
  • 考虑将重复字符串提取到常量--这将有助于避免bug。如果您在一个地方出错,而不是在另一个地方出错,有时很难调试。数字也是如此--这也会使生成不同尺寸的sudoku变得更容易。
票数 5
EN

Code Review用户

发布于 2020-03-24 23:11:09

让我们从一些常规的事情开始,在JS中,我们(每个人)都将函数和变量名写为camel。

我看到您有一个评论,您试图使用一个setter,问题是,您会想要以两种方式使用它。您可能希望编写this.board = import_string来调用setter,但是在构造函数中可以这样做。

this.board = this.blank_board_array();

你可以用一个策划人写一些重写,但我认为这是好的。

JS ==中的double等于强制类型,因此,例如,0==[]是真的,虽然这可能是有用的,但在我的经验中,它正好适合于过于聪明或巧合地工作的事物。我建议您始终使用不强制类型的=== (但对我的同事来说,有争议的是,我写了一些像if (x === false)这样的行,有人说这太过分了)。

我建议使用创建html Sudoku板的函数会更好,也就是说,与碰巧存在的目标元素相比,您可以使用JS生成元素,然后在末尾添加一个元素(有许多子元素),如果这样做,也可以整理设置事件侦听器的逻辑。

总的来说,有一种趋势(至少在我的工作经验中)是用JS编写相当实用的代码。你的东西离那很远,不是什么问题,只是一些需要注意的东西。

在不重写所有内容的情况下给出一个示例有点困难,但例如(虽然我将给出的示例仍然不是非常实用),您可以多次在2D数组上循环,您可以编写一个函数loopOverMatrix(矩阵,f),它接受2D数组和函数f (i,j) => {.},并遍历所有元素并调用f(i)(j) (J)。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/239248

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档