小游戏制作-其他系列-数独


本文章是小游戏制作系列,其他系列-数独篇章

游戏思路

数独游戏的规律是,同一行,同一列,每3*3的9宫格中只能存在1-9的数字,不能重复。
步骤1:知道游戏规则之后,我们可以开始着手创建一个符合游戏规则的数独棋盘(它的本质是一个二维数组)。
步骤2:根据选择的难度随机挖空对应数目的格子,留给用户填写。简单模式挖空4格子,中等模式挖空6格子等。
步骤3:用户点击提交时判断做一个简单的输入验证(是否输入为空,是否正填写1-9范围的数字)。
步骤4:通过步骤3的初步验证之后,验证用户填写完的数独数组是否是有效的。(有两种方案,方案一是保步骤1的数独数组与现在的数独数组做对比;方案二:将现在新的组成的数独数组通过一个检验是否有效数独的方法校验),此处选择的是方案二。
步骤5:根据步骤4的校验结果,判断是否通过游戏,并进行对应的提示。通过之后得分改变。
最终游戏界面如下:
在这里插入图片描述

游戏代码

html代码
在这里插入图片描述
js代码重点方法

// 画布初始化
function init(contentId){
    // 创建一个二维数据 9*9来进行画布渲染
    for(let i=0;i<9;i++){
        sdArr[i] = new Array(9).fill(0)
    }
    // 创建数独二维数组
    // 数独规则,每一行,每一列数字不能重复(1-9)。每一个3*3的正方形格子中,数字不能重复(1-9)
    for(let row=0;row<9;row++){
        let column = 0;
        let numArr = [...numArray];
        let newObj = new Map();
        while(column<9){
            if(column == 0){
                newObj = new Map();
            }
            let cellItem = Math.floor(Math.random()*numArr.length);
            newObj[column]?'':newObj[column] = new Set();
            newObj[column].add(numArr[cellItem])
            if(!rule(numArr[cellItem],row,column)){ 
                if(numArr.length == newObj[column].size){
                    // 表示陷入死循环中,需要重新开始计算这一对数据
                    numArr =  [...numArray];
                    column=0;
                    sdArr[row] = new Array(9).fill(0)
                }
            }else{
                sdArr[row][column] = numArr[cellItem];
                numArr.splice(cellItem,1)
                column++;
            }
        }
    }
    hollowing(contentId,sdArr);
}
/**
 * @description 生成数独数组时需要判断数独的合理性,一行不能出现重复数字,一列不能出现重复数字,一个3*3方格不能出现重复的数字
*/
function rule(number,row,column){
    // 一列
    for(let i=0;i<9;i++){
       if( sdArr[i][column] == number || sdArr[row][i] == number){
        return false;
       }
    }
    // 一个3*3
    let rowStart = Math.floor(row/3)*3;
    let cloumStart = Math.floor(column/3)*3;
    let rowS = row%3;
    if(rowS != 0){
        for(let i=0;i<3;i++){
            for(let j=0;j<3;j++){
                if(sdArr[rowStart+i][cloumStart+j] == number){
                    return false
                }
            }
        }
    }
    return true;
}
/**
 * @description 用于检验是否是一个合法的数独数组
 * */ 
function submitRule(Arr){
    let blockSet = {};
    let blockFlag =true;
    for(let i=0;i<9;i++){
        let columSet = new Set();
        let rowIndex = Math.floor(i/3)*3;
        for(let j=0;j<9;j++){
            let columnIndex = Math.floor(j/3)*3;
            columSet.add(Arr[i][j]);
            if(i%3 == 0 && j%3 == 0){
                blockSet[rowIndex+''+columnIndex] = new Set();
            }
            blockSet[rowIndex+''+columnIndex].add(Arr[i][j]);
        }
        let rowSet = new Set(Arr[i]);
        if(rowSet.size<9 || columSet.size<9){
            return false;
        }
    }
    for(item in blockSet){
        if(item.size<9){
            blockFlag = false;
        }
    }
    return blockFlag
}
/**
 * @description 用于渲染游戏区域
 * @param{contentId} 需要渲染的游戏区域的元素id
 * @param{Arr} 用于渲染游戏区域的数组对象
 * */ 
function renderGame(contentId,Arr){
    const content = document.getElementById(contentId);
    let str = '';
    for(let i=0;i<9;i++){
        str +=`<div class='canvas-row'>`
        for(let j=0;j<9;j++){
            if(Arr[i][j]){
                str += `<span class='cell'>${Arr[i][j]}</span>`
            }else{
                str += `<span class='cell cell${i}${j} cell-color' contenteditable="true">${Arr[i][j]}</span>`
            }
        }
        str +=`</div>`
    }
    content.innerHTML = str;
}
/**
 * @description 进行游戏挖空,根据选定难度来
 * */ 
 let hollowingArr = [];
function hollowing(contentId,Arr){
   let num = difficulty[difficultyType].nums;//提取难度对应的空缺位数
    while(num>0){
        // 取随机数
        let row =  Math.floor(Math.random()*9)
        let colum = Math.floor(Math.random()*9)
        if(hollowingArr.length == 0){
            hollowingArr.push({row,colum});
            Arr[row][colum] = ''
            num--;
        }else{
            let hasRow = hollowingArr.some((item)=>{
                return item.row == row && item.colum == colum
            });
            if(!hasRow){
                hollowingArr.push({row,colum});
                Arr[row][colum] = ''
                num--;
            }
        }
    }
    renderGame(contentId,Arr);
}
/**
 * @description 游戏可编辑块输入内容捕捉
 * */ 
   function editable(className){
        // 获取所有填写的cell元素,组合数组元素
        let num = difficulty[difficultyType].nums;//提取难度对应的空缺位数
        let flag = true;
        for(i=0;i<num;i++){
            const editE = document.getElementsByClassName(className+hollowingArr[i].row+hollowingArr[i].colum)[0];
            if(editE.innerText){
                if(numArray.includes(editE.innerText)){
                    sdArr[hollowingArr[i].row][hollowingArr[i].colum] = editE.innerText;
                }else{
                    alert("请正确填写第"+(parseInt(hollowingArr[i].row)+1)+'行,第'+(parseInt(hollowingArr[i].colum)+1)+'列内容');
                    flag = false;
                    return false;
                }
            }else{
                alert("第"+(parseInt(hollowingArr[i].row)+1)+'行,第'+(parseInt(hollowingArr[i].colum)+1)+'列未填写');
                flag = false;
                return false;
            }
        }
        return flag;
    }

游戏优化

不过现在多次重新开始游戏,可能是init方法里面的算法问题,可能会存在卡顿现象。后续还需要进行算法优化
界面优化(2023-1-6):在选中用户点击可输入块进行输入时,界面上提示该列,该行,该3*3九宫格范围,让用户比较明显的知道要对比的数据。我们需要css中准备一个class类名‘cell-item’,然后在事件判断过程中,动态的添加到元素上,展示效果如图。
在这里插入图片描述
重点代码如下:

/**
 * @description 输入过程中,样式动态修改
*/
function editCell(){
    document.getElementById("canvasContent").addEventListener("click", function(e) {
        // 检查事件源e.targe是否为目标
        if(e.target && e.target.className.includes('cell-color')) {
            let elementData = e.target.getAttribute('data');
            // 获取到当前点击的行列坐标
            let row = elementData[0];
            let colum = elementData[2];
            // 现在需要做样式渲染
            let cellList = document.getElementsByClassName("cell");
            for(let i=0;i<cellList.length;i++){
                cellList[i].classList.remove("cell-item")
                // 同行同列开始渲染颜色
                if((i>=row*9 && i<(row*9+9)) || i%9 == colum){
                    cellList[i].classList.add("cell-item")
                }
                // 3*3格子开始渲染颜色
                if(Math.floor(i/27) == Math.floor(row/3)){
                    if(Math.floor((i%9)/3)>=Math.floor(colum/3) && Math.floor((i%9)/3)<Math.floor(colum/3)+1){
                        cellList[i].classList.add("cell-item")
                    }
                }
            }
        }
      });
}

github地址

试玩路径

试玩路径

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值