资讯专栏INFORMATION COLUMN

用vue开发一个所谓的数独

shixinzhang / 1623人阅读

摘要:前言最近的后台管理系统页面,功能暂时没有新的需求,就在想首页放什么东西,最近我想到的就是放个所谓的数独,为什么是所谓的数独,因为规则不同于标准的数独,只要求每一行每一列数字不一样就可以了这个实例也是基于的,代码分享给大家。

1.前言

最近的后台管理系统页面,功能暂时没有新的需求,就在想首页放什么东西,最近我想到的就是放个所谓的数独,为什么是所谓的数独,因为规则不同于标准的数独,只要求每一行每一列数字不一样就可以了!这个实例也是基于vue的,代码分享给大家。给大家代码,并不是要让大家直接拷贝代码,而是希望能让大家当做是一个练手的项目,或者学习到知识。如果大家觉得我哪里写得不好,写错了,欢迎指出,让大家交流意见,一起进步。代码上传到github了:有需要的可以star一下!vue-demos

2.运行效果

3.实现步骤
实现步骤,感觉说得有点绕,建议大家边写边看文章,这样不会懵。或者直接去看源码(sudoku),把源码看懂!这个项目也不复杂!
3-1.准备数据和排版

排版的html+css代码我不多说了,排版很简单,这个相信都难不倒大家的。复杂一点的就是数据的交互!
下面开始第一步,把数独的数据先准备好,数据是什么,大家都知道,就是像下面这样的数据!

排版出来的效果就是下面这样。

html代码如下

{{allNumText[index][indexSub]}}

代码也很简单,如下

mounted(){
    let arr1 = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    let row = [], rowCol = 0;
    for (let i = 0, len = arr1.length; i < len; i++) {
        row = Object.assign([], arr1);
        this.allNum.push(row);
        //删除第一个数字并记录下来
        rowCol = arr1.splice(0, 1)[0];
        //在最后面插入数字
        arr1.push(rowCol)
    }
}

大家也可以发现,这个数据,的每一行和每一列的数字都是不同样的!

3-2.打乱行

之后就是随机打乱顺序了,打乱顺序这个得保证一个前提,就是保证每一行每一列的数字都不一样。这样的话,我用了一个简单粗暴的方法-以行或者列为单位,进行打乱。比如,第一行和第三行进行位置交互,第一列和第五列进行位置的交换。下面说下以行为单位的打乱顺序!
行的打乱,很简单,就是随机打乱数组而已!一行代码搞定!

this.allNum.sort((n1, n2) => Math.random() - 0.5);

3-3.打乱列

行打乱了,下面进行以列为单位的打乱,这个稍微复杂一点。
大家想下,比如第二列是第五列的值进行交换,那就是每一行的第二个格子的值和第五个格子的值进行交换,那么就需要遍历每一行!来进行交换,至于前面说的第二列和第五列的这个列数,可以用一个函数实现!
下面看代码!

//随机获取两列的索引
function randomText() {
    let rondomIndex = 0, rondomIndexAfter = 0;
    //获取第一列的索引
    rondomIndex = Math.floor(Math.random() * 9);
    function randomDo() {
        rondomIndexAfter = Math.floor(Math.random() * 9);
        //如果第一列和第二列索引一样,第二列的索引再次重新随机获取
        if (rondomIndexAfter === rondomIndex) {
            randomDo();
        }
    }

    randomDo();
    //返回两列的索引
    return [rondomIndex, rondomIndexAfter]
}

//打乱列
let randomArr = [], nowValue = 0;
//同样遍历9次
for (let i = 0; i < 9; i++) {
    randomArr = Object.assign([], randomText());
    //遍历每一行,给每一行的随机两列交换值
    for (let j = 0, len = this.allNum.length; j < len; j++) {
        //随机两列交换值
        nowValue = this.allNum[j][randomArr[0]];
        this.allNum[j][randomArr[0]] = this.allNum[j][randomArr[1]];
        this.allNum[j][randomArr[1]] = nowValue;
    }
}

3-3.随机掏空单元格

掏空单元格就是把一些格子随机设空,然后让玩数独的人。把这些单元格给填上!
需求,我现在实现的就是,每一行有把两个格子设空,这里我的做法是,把每一个格子的坐标先记录下来,然后再从记录的坐标里面随机获取坐标,用获取到的坐标,进行设空!
首先,获取所有点的坐标

//记录所有坐标
let rowText = "", arrText = []
for (let i = 0; i < 9; i++) {
    rowText = ""
    for (let j = 0; j < 9; j++) {
        rowText += i + "-" + j + ",";
    }
    arrText.push(rowText.substr(0, rowText.length - 1))
}
console.log(arrText);

看到这个坐标,大家很容易的知道,数组的一个元素,就是第一行,‘0-0’就是第一行第一个格子。数组最后一个元素,就是最后一行,‘8-8’就是最后一行,最后一个格子,其他如此类推!
下面进行随机掏空,代码也很简单!

//随机掏空
let nowItme = [], _option, nowOption = [];
for (let i = 0; i < 9; i++) {
    //抽取当前行的所有坐标
    nowItme = arrText[i].split(",");
    nowOption = [];
    //当前行的随机两个坐标掏空
    for (let j = 0; j < 2; j++) {
        //抽取当前行的随机一个坐标
        _option = Math.floor(Math.random() * nowItme.length);
        //分割坐标的x,y
        nowOption = nowItme.splice(_option,1)[0].split("-");
        this.allNum[nowOption[0]][nowOption[1]] = "";
    }

}

这样相信大家都觉得奇怪,下面进行下样式的该写,就是把设空了的格子的样式改一下!.no这个class对应的样式我在css那里写好了,大家注意下。


{{allNumText[index][indexSub]}}

3-4.显示数字键盘

首先,我简单的用一个流程图说下逻辑,如下

然后关于数字键盘的位置,看下图(数字键盘的样式我不多说了,就是一个是相对定位,一个绝对定位的设置而已)

如上图,我点击的是第一行第三个格子,首先,我期待被点击的格子的样式有所改变,方便我区分,这个不难,用一个class改变样式就可以了,这个可以看下面的代码,我用一个.curclass控制样式。还有一个就是期待数字键盘在第二行,第四个格子那里出现。这样的话,大家就知道,数字键盘的位置是怎么定位的了!数字键盘的top就是,被点击格子所在的行的索引+160(60是格子的宽高),left就是,被点击格子所在的列的索引+160(60是格子的宽高)。比如上图,第一行第三个格子,top=(0+1)*60+"px",left=(2+1)*60+"px"

代码如下


    
{{allNumText[index][indexSub]}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

js代码

/**
 * @description 显示数字键盘
 * @param i1
 * @param i2
 */
showCheck(i1, i2){
    //点击的格子是否是被掏空的格子
    if (this.allNum[i1][i2] !== "") {
        return
    }
    //点击的格子如果是上一次点击的格子(当前格子)
    if (i1 === this.curRow && i2 === this.curCol) {
        //隐藏数字键盘,curRow和curCol设空
        this.checkShow = false;
        this.curRow = "";
        this.curCol = "";
    }
    else {
        //隐藏数字键盘,curRow和curCol分别设置成当前的点
        this.checkShow = true;
        this.curRow = i1;
        this.curCol = i2;
    }
},

运行效果

3-5.高亮显示同行同列

这一步很简单,首先,高亮显示行,大家都知道怎么做了,就是行对应的div,设置一个:hover,然后对应设置单元格的样式而已!这个不多说!

然后,高亮显示列,复杂一点,但是也很简单,原理我想大家也知道,就是当鼠标进如格子的时候,在data里面,用一个变量储存进入的格子的列的索引,然后加上判断,如果格子的列的索引等于进入的格子的列的索引。就加上一个class,这里我用.cur-col。代码如下


{{allNumText[index][indexSub]}}

运行效果

3-6.填写操作和错误提示

这一步的操作函数,我直接发代码吧,看代码比我说的会清晰些,毕竟说的有点绕


{{allNumText[index][indexSub]}}

js代码

inputText(_text){
    //*****************************检查前的初始化
    let _row = this.curRow, _col = this.curCol;
    this.curRow = "";
    this.curCol = "";
    this.isErr = false;
    this.optionNow = {
        x: "",
        y: "",
    }
    this.optionNowInRow = {
        x: "",
        y: "",
    }
    this.optionNowInCol = {
        x: "",
        y: "",
    }
    //*****************************检查行
    //根据当前格子进行赋值
    this.allNumText[_row][_col] = _text;
    let rowCheck = Object.assign(this.allNumText[_row], []);
    this.checkShow = false;
    for (let i = 0, len = rowCheck.length; i < len; i++) {
        //如果值一样,但是坐标不一样,就是填写错误
        if (_text === rowCheck[i] && _col !== i) {
            this.isErr = true;
            this.isShake = true;
            //记录当前格子的信息
            this.optionNow = {
                x: _row,
                y: _col,
            }
            //记录和当前格子同一行,以及同一个值的格子的坐标
            this.optionNowInRow = {
                x: _row,
                y: i,
            }
        }
    }
    //*****************************检查列
    let colCheck = [];
    //首先把每一行的那一列的数值保存起来
    for (let i = 0, len = this.allNumText.length; i < len; i++) {
        colCheck.push(this.allNumText[i][_col]);
    }
    //遍历检查
    for (let i = 0, len = colCheck.length; i < len; i++) {
        //如果值一样,但是坐标不一样,就是填写错误
        if (_text === colCheck[i] && _row !== i) {
            this.isErr = true;
            this.isShake = true;
            //记录和当前格子同一列,以及同一个值的格子的坐标
            this.optionNowInCol = {
                x: i,
                y: _col,
            }
        }
    }
    //如果发现的同样的
    if (this.isErr) {
        setTimeout(() => {
            this.isShake = false;
        }, 1000)
        return;
    }
    //如果数组去重后,长度小于9,就是行没完成
    rowCheck = rowCheck.filter(item => item !== "");
    if (rowCheck.length !== 9) {
        //console.log("行没完成")
        return;
    }

    let coloCheck = [];
    //如果数组去重后,长度小于9,就是列没完成
    for (let i = 0, len = this.allNumText.length; i < len; i++) {
        coloCheck = [...new Set(this.allNumText[i])];
        coloCheck = coloCheck.filter(item => item !== "");
        if (coloCheck.length !== 9) {
            //console.log("没完成")
            return;
        }
    }
    alert("挑战成功,但是没奖品");
    this.numShow = false;
} 

上面的代码逻辑,简单说下

1..err 这个class是设置红色字体所使用的,至于判断,就是在inputText这个函数里面,有optionNowoptionNowInRowoptionNowInCol。只要格子的坐标等于三者其中之一,就会添加这个class,就会变红。
2..isShake这个class是控制,抖动的动画,添加上了之后,在一秒后,要去掉这个class,不然下次添加没有动画效果。
3.在inputText这个函数里面,我操作的数独列表,并不是之前,提到的allNum,而是利用allNum,深度拷贝生成出的allNumTextthis.allNumText = JSON.parse(JSON.stringify(this.allNum));)。主要就是为了避免下图的情况!

这样是为了往掏空的格子输入数字的时候,然后那个格子就不能再改了,即使是填错了,都不能改。样式控制也不正确!正确的格式应该是下面这样,即使填入了,格子的样式还是灰色的,这样可以方便的知道哪个格子是当时被掏空的,填写错了,也是可以改的。

4.完整代码



    
    vue-所谓的数独
    
    


所谓的数独:规则

1.每一行数字不重复

2.每一列数字不重复

{{allNumText[index][indexSub]}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

reset.cssvue.min.js大家自行到github下载!

5.小结

好了,用vue做的所谓的数独,就写到这里了,主要就是逻辑有点绕,其它的问题相信都难不倒大家。这个实例比之前快速入门的三个小实例要麻烦一点,但是也很好理解!大家只要稍微看下估计都不难理解!最后,如果大家觉得文章写得不好,哪里写错了,欢迎给建议或者指点下迷津。期待和大家交流意见,共同进步!

-------------------------华丽的分割线--------------------
想了解更多,关注关注我的微信公众号:守候书阁

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/51611.html

相关文章

  • vue开发一个所谓数独

    摘要:前言最近的后台管理系统页面,功能暂时没有新的需求,就在想首页放什么东西,最近我想到的就是放个所谓的数独,为什么是所谓的数独,因为规则不同于标准的数独,只要求每一行每一列数字不一样就可以了这个实例也是基于的,代码分享给大家。 1.前言 最近的后台管理系统页面,功能暂时没有新的需求,就在想首页放什么东西,最近我想到的就是放个所谓的数独,为什么是所谓的数独,因为规则不同于标准的数独,只要求每...

    Pluser 评论0 收藏0
  • 【LeetCode】数组初级算法-有效数独

    摘要:题目描述有效的数独判断一个的数独是否有效。上图是一个部分填充的有效的数独。数独部分空格内已填入了数字,空白格用表示。说明一个有效的数独部分已被填充不一定是可解的。只需要根据以上规则,验证已经填入的数字是否有效即可。 题目描述 有效的数独判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出...

    wyk1184 评论0 收藏0
  • 数独X--Android openCV识别数独并自动求解填充APP开发过程

    摘要:可以针对笔者常用的数独本文的实现都基于该,实现数独的识别求解并把答案自动填入。专家级别的平均秒完成求解包括图像数字提取,识别过程,完成全部操作。步骤四数独求解,生成答案,并生成需要填充的数字序列。 1 序   数独是源自18世纪瑞士的一种数学游戏。是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3*3...

    kelvinlee 评论0 收藏0
  • 数独X--Android openCV识别数独并自动求解填充APP开发过程

    摘要:可以针对笔者常用的数独本文的实现都基于该,实现数独的识别求解并把答案自动填入。专家级别的平均秒完成求解包括图像数字提取,识别过程,完成全部操作。步骤四数独求解,生成答案,并生成需要填充的数字序列。 1 序   数独是源自18世纪瑞士的一种数学游戏。是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3*3...

    yvonne 评论0 收藏0
  • LeetCode36.有效数独 JavaScript

    摘要:上图是一个部分填充的有效的数独。数独部分空格内已填入了数字,空白格用表示。但由于位于左上角的宫内有两个存在因此这个数独是无效的。说明一个有效的数独部分已被填充不一定是可解的。只需要根据以上规则,验证已经填入的数字是否有效即可。 判断一个 9x9的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次...

    elva 评论0 收藏0

发表评论

0条评论

shixinzhang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<