用vue開發一個所謂的數獨

守候i發表於2017-12-21

1.前言

最近的後臺管理系統頁面,功能暫時沒有新的需求,就在想首頁放什麼東西,最近我想到的就是放個所謂的數獨,為什麼是所謂的數獨,因為規則不同於標準的數獨,只要求每一行每一列數字不一樣就可以了!這個例項也是基於vue的,程式碼分享給大家。給大家程式碼,並不是要讓大家直接拷貝程式碼,而是希望能讓大家當做是一個練手的專案,或者學習到知識。如果大家覺得我哪裡寫得不好,寫錯了,歡迎指出,讓大家交流意見,一起進步。程式碼上傳到github了:有需要的可以star一下!vue-demos

2.執行效果

用vue開發一個所謂的數獨

3.實現步驟

實現步驟,感覺說得有點繞,建議大家邊寫邊看文章,這樣不會懵。或者直接去看原始碼(sudoku),把原始碼看懂!這個專案也不復雜!

3-1.準備資料和排版

排版的html+css程式碼我不多說了,排版很簡單,這個相信都難不倒大家的。複雜一點的就是資料的互動!
下面開始第一步,把數獨的資料先準備好,資料是什麼,大家都知道,就是像下面這樣的資料!

用vue開發一個所謂的數獨

排版出來的效果就是下面這樣。

用vue開發一個所謂的數獨

html程式碼如下

<div class="num-table" @mouseleave="hoverCol=''" :class="{'shake':isShake}">
    <!--遍歷每一行-->
    <div v-for="row,index in allNum" class="num-row chearfix">
        <!--遍歷行裡面的每一列-->
        <div v-for="num1,indexSub in row" class="num-col">
            {{allNumText[index][indexSub]}}
        </div>
    </div>
</div>複製程式碼

程式碼也很簡單,如下

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);
複製程式碼

用vue開發一個所謂的數獨

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;
    }
}
複製程式碼

用vue開發一個所謂的數獨

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);
複製程式碼

用vue開發一個所謂的數獨

看到這個座標,大家很容易的知道,陣列的一個元素,就是第一行,‘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]] = '';
    }

}

複製程式碼

用vue開發一個所謂的數獨

這樣相信大家都覺得奇怪,下面進行下樣式的該寫,就是把設空了的格子的樣式改一下!.no這個class對應的樣式我在css那裡寫好了,大家注意下。

<!--遍歷每一行-->
<div v-for="row,index in allNum" class="num-row chearfix">
    <!--遍歷行裡面的每一列-->
    <!--
        no:被掏空陣列的樣式
    -->
    <div v-for="num1,indexSub in row" :class="{'no':num1===''}" class="num-col">
        {{allNumText[index][indexSub]}}
    </div>
</div>
複製程式碼

用vue開發一個所謂的數獨

3-4.顯示數字鍵盤

首先,我簡單的用一個流程圖說下邏輯,如下

用vue開發一個所謂的數獨

然後關於數字鍵盤的位置,看下圖(數字鍵盤的樣式我不多說了,就是一個是相對定位,一個絕對定位的設定而已)

用vue開發一個所謂的數獨

如上圖,我點選的是第一行第三個格子,首先,我期待被點選的格子的樣式有所改變,方便我區分,這個不難,用一個class改變樣式就可以了,這個可以看下面的程式碼,我用一個.curclass控制樣式。還有一個就是期待數字鍵盤在第二行,第四個格子那裡出現。這樣的話,大家就知道,數字鍵盤的位置是怎麼定位的了!數字鍵盤的top就是,被點選格子所在的行的索引+1

60(60是格子的寬高),left就是,被點選格子所在的列的索引+1
60(60是格子的寬高)。比如上圖,第一行第三個格子,top=(0+1)*60+'px',left=(2+1)*60+'px'

程式碼如下

<!--遍歷每一行-->
    <div v-for="row,index in allNum" class="num-row chearfix">
        <!--遍歷行裡面的每一列-->
        <!--
            no:被掏空陣列的樣式
            cur:格子被點選時觸發,被點選的格子樣式
        -->
        <div v-for="num1,indexSub in row"
             :class="{'no':num1==='',
             'cur':curRow===index&&indexSub===curCol}"
             @click="showCheck(index,indexSub)" class="num-col">
            {{allNumText[index][indexSub]}}

        </div>
    </div>
<!--數字鍵盤-->
<div class="num-check chearfix" :style="{'top':(curRow+1)*60+'px','left':(curCol+1)*60+'px'}"
     v-show="checkShow">
    <ul>
        <li @click="inputText(1)">1</li>
        <li @click="inputText(2)">2</li>
        <li @click="inputText(3)">3</li>
        <li @click="inputText(4)">4</li>
        <li @click="inputText(5)">5</li>
        <li @click="inputText(6)">6</li>
        <li @click="inputText(7)">7</li>
        <li @click="inputText(8)">8</li>
        <li @click="inputText(9)">9</li>
    </ul>
</div>複製程式碼

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;
    }
},
複製程式碼

執行效果

用vue開發一個所謂的數獨

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

這一步很簡單,首先,高亮顯示行,大家都知道怎麼做了,就是行對應的div,設定一個:hover,然後對應設定單元格的樣式而已!這個不多說!

用vue開發一個所謂的數獨

然後,高亮顯示列,複雜一點,但是也很簡單,原理我想大家也知道,就是當滑鼠進如格子的時候,在data裡面,用一個變數儲存進入的格子的列的索引,然後加上判斷,如果格子的列的索引等於進入的格子的列的索引。就加上一個class,這裡我用.cur-col。程式碼如下

<!--遍歷每一行-->
<div v-for="row,index in allNum" class="num-row clear">
    <!--遍歷行裡面的每一列-->
    <!--
        no:被掏空陣列的樣式
        cur:格子被點選時觸發,被點選的格子樣式
        cur-col:滑鼠進入的時候觸發,和被點選格子同一列的格子的樣式
    -->
    <div v-for="num1,indexSub in row"
         :class="{'no':num1==='',
         'cur':curRow===index&&indexSub===curCol,
         'cur-col':hoverCol===indexSub}"
         @click="showCheck(index,indexSub)" @mouseenter="hoverCol=indexSub;" class="num-col">
        {{allNumText[index][indexSub]}}
    </div>
</div>
複製程式碼

執行效果

用vue開發一個所謂的數獨

3-6.填寫操作和錯誤提示

這一步的操作函式,我直接發程式碼吧,看程式碼比我說的會清晰些,畢竟說的有點繞

<!--遍歷每一行-->
<div v-for="row,index in allNum" class="num-row clear">
    <!--遍歷行裡面的每一列-->
    <!--
        no:被掏空陣列的樣式
        cur:格子被點選時觸發,被點選的格子樣式
        cur-col:滑鼠進入的時候觸發,和被點選格子同一列的格子的樣式
        err:填寫錯誤的時候觸發的樣式
    -->
    <div v-for="num1,indexSub in row"
         :class="{'no':num1==='',
         'cur':curRow===index&&indexSub===curCol,
         'cur-col':hoverCol===indexSub,
         'err':(optionNow.x===index&&optionNow.y===indexSub)||(optionNowInRow.x===index&&optionNowInRow.y===indexSub)||(optionNowInCol.x===index&&optionNowInCol.y===indexSub)}"
         @click="showCheck(index,indexSub)" @mouseenter="hoverCol=indexSub;" class="num-col">
        {{allNumText[index][indexSub]}}

    </div>
</div>複製程式碼

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;
} 

複製程式碼

用vue開發一個所謂的數獨

上面的程式碼邏輯,簡單說下

1..err 這個class是設定紅色字型所使用的,至於判斷,就是在inputText這個函式裡面,有optionNowoptionNowInRowoptionNowInCol。只要格子的座標等於三者其中之一,就會新增這個class,就會變紅。
2..isShake這個class是控制,抖動的動畫,新增上了之後,在一秒後,要去掉這個class,不然下次新增沒有動畫效果。
3.在inputText這個函式裡面,我操作的數獨列表,並不是之前,提到的allNum,而是利用allNum,深度拷貝生成出的allNumTextthis.allNumText = JSON.parse(JSON.stringify(this.allNum));)。主要就是為了避免下圖的情況!

用vue開發一個所謂的數獨

這樣是為了往掏空的格子輸入數字的時候,然後那個格子就不能再改了,即使是填錯了,都不能改。樣式控制也不正確!正確的格式應該是下面這樣,即使填入了,格子的樣式還是灰色的,這樣可以方便的知道哪個格子是當時被掏空的,填寫錯了,也是可以改的。

4.完整程式碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue-所謂的數獨</title>
    <link rel="stylesheet" href="../../reset.css">
    <style>
        li{
            list-style-type: none;
        }
        .shake {
            animation: shake-opacity 500ms 1 ease-in-out;
        }
        @keyframes shake-opacity {
            0% {
                transform: translate(0px, 0px) rotate(0deg);
                opacity: 0.6;
            }
            10% {
                transform: translate(-2px, -1px) rotate(-0.5deg);
                opacity: 0.5;
            }
            20% {
                transform: translate(-4px, 4px) rotate(1.5deg);
                opacity: 0.4;
            }
            30% {
                transform: translate(-4px, -1px) rotate(-1.5deg);
                opacity: 0.8;
            }
            40% {
                transform: translate(-2px, -1px) rotate(-2.5deg);
                opacity: 0.3;
            }
            50% {
                transform: translate(-4px, 1px) rotate(-2.5deg);
                opacity: 0.5;
            }
            60% {
                transform: translate(-2px, 4px) rotate(0.5deg);
                opacity: 0.1;
            }
            70% {
                transform: translate(-3px, 1px) rotate(-0.5deg);
                opacity: 0.4;
            }
            80% {
                transform: translate(0px, 0px) rotate(-0.5deg);
                opacity: 0.5;
            }
            90% {
                transform: translate(2px, -1px) rotate(-2.5deg);
                opacity: 0.8;
            }
        }
        .num-box {
            margin: 0 auto;
            width: 540px;
            position: relative;
        }
        .num-box .num-check {
            position: absolute;
            width: 180px;
            box-shadow: 0 0 10px 0 #000;
            left: 0;
            top: 0;
        }
        .num-box .num-check li {
            box-sizing: border-box;
            float: left;
            background: #fff;
            color: #58B7FF;
            width: 60px;
            height: 60px;
            text-align: center;
            line-height: 60px;
            font-size: 24px;
            border: 1px solid #58B7FF;
            cursor: pointer;
            transition: all .5s;
        }
        .num-box .num-check li:hover {
            color: #fff;
            background: #58B7FF;
            border: 1px solid #fff;
        }
        .num-tips{
            color: #333;
            line-height: 32px;
            font-size: 16px;
        }
        .num-table{
            position: relative;
        }
        .num-row {
            font-size: 0;
        }
        .num-row:hover .num-col, .num-row:hover .num-col.no, .num-row:hover .num-col.cur-col {
            background: #0068b7;
        }
        .num-row .num-col {
            width: 60px;
            height: 60px;
            line-height: 60px;
            float: left;
            box-sizing: border-box;
            text-align: center;
            background: #58B7FF;
            color: #fff;
            font-size: 24px;
            font-weight: bold;
            border: 1px solid #ccc;
        }
        .num-row .num-col.no {
            background: #ccc;
            border: 1px solid #fff;
        }
        .num-row .num-col.err {
            color: #ff4949;
        }
        .num-row .num-col.cur-col {
            background: #0068b7;
        }
        .num-row .num-col.cur {
            background: #fff !important;
        }
    </style>
</head>
<body>
<div class="num-box" v-show="numShow" id="num">
    <div class="num-tips">
        <p>所謂的數獨:規則</p>
        <p>1.每一行數字不重複</p>
        <p>2.每一列數字不重複</p>
    </div>
    <div class="num-table" @mouseleave="hoverCol=''" :class="{'shake':isShake}">
        <!--遍歷每一行-->
        <div v-for="row,index in allNum" class="num-row clear">
            <!--遍歷行裡面的每一列-->
            <!--
                no:被掏空陣列的樣式
                cur:格子被點選時觸發,被點選的格子樣式
                cur-col:滑鼠進入的時候觸發,和被點選格子同一列的格子的樣式
                err:填寫錯誤的時候觸發的樣式
            -->
            <div v-for="num1,indexSub in row"
                 :class="{'no':num1==='',
                 'cur':curRow===index&&indexSub===curCol,
                 'cur-col':hoverCol===indexSub,
                 'err':(optionNow.x===index&&optionNow.y===indexSub)||(optionNowInRow.x===index&&optionNowInRow.y===indexSub)||(optionNowInCol.x===index&&optionNowInCol.y===indexSub)}"
                 @click="showCheck(index,indexSub)" @mouseenter="hoverCol=indexSub;" class="num-col">
                {{allNumText[index][indexSub]}}

            </div>
        </div>
        <!--數字鍵盤-->
        <div class="num-check clear" :style="{'top':(curRow+1)*60+'px','left':(curCol+1)*60+'px'}"
             v-show="checkShow">
            <ul>
                <li @click="inputText(1)">1</li>
                <li @click="inputText(2)">2</li>
                <li @click="inputText(3)">3</li>
                <li @click="inputText(4)">4</li>
                <li @click="inputText(5)">5</li>
                <li @click="inputText(6)">6</li>
                <li @click="inputText(7)">7</li>
                <li @click="inputText(8)">8</li>
                <li @click="inputText(9)">9</li>
            </ul>
        </div>
    </div>
</div>
</body>
<script src="../vue.min.js"></script>
<script>
    new Vue({
        el:'#num',
        data:{
                name: 'welcome',
                testText: '歡迎來到',
                nowIndex: 0,
                allNum: [],//數字排列
                answer: [],//所有答案的座標點
                allNumText: [],//數字,包括輸入後的數字
                curRow: '',//當前格子所在的行的索引
                curCol: '',//當前格子所在的列的索引
                checkShow: false,//數字鍵盤的顯示
                hoverCol: '',//滑鼠進去的當前列
                hoverRow: 0,//滑鼠進入的當前行
                numShow: true,//數獨的顯示
                optionNow: {},//輸入後的格子的座標
                optionNowInRow: {},//和輸入後的格子在同一行,並且同樣值的格子的座標
                optionNowInCol: {},//和輸入後的格子在同一列,並且同樣值的格子的座標
                isErr: false,//是否輸入錯誤後
                isShake: false//是否顯示震動的樣式
        },
        methods: {
            /**
             * @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;
                }
            },
            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;
            }
        },
        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)
            }
            //打亂行
            this.allNum.sort((n1, n2) => Math.random() - 0.5);
            //隨機獲取兩列的索引
            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;
                }
            }

            //記錄所有座標
            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);
            //隨機掏空
            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]] = '';
                }

            }
            //深度拷貝數獨的數字
            this.allNumText = JSON.parse(JSON.stringify(this.allNum));
        }
    })
</script>
</html>複製程式碼

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

5.小結

好了,用vue做的所謂的數獨,就寫到這裡了,主要就是邏輯有點繞,其它的問題相信都難不倒大家。這個例項比之前快速入門的三個小例項要麻煩一點,但是也很好理解!大家只要稍微看下估計都不難理解!最後,如果大家覺得文章寫得不好,哪裡寫錯了,歡迎給建議或者指點下迷津。期待和大家交流意見,共同進步!



-------------------------華麗的分割線--------------------
想了解更多,關注關注我的微信公眾號:守候書閣

用vue開發一個所謂的數獨


相關文章