zoukankan      html  css  js  c++  java
  • 用 Vue 简单实现一个八皇后小游戏

    八皇后小游戏规则与效果预览

    规则:

    效果预览:

      用字母 Q 代表皇后,横/竖/撇/捺处均无皇后可放置皇后,在横/竖/撇/捺有皇后处放置皇后会弹出提示“该位置不能放置皇后!”。

    实现步骤

    之前创建了项目,笔记:https://www.cnblogs.com/xiaoxuStudy/p/12663218.html

    当前目录结构:

    (注意:组件命名用大驼峰命名法。)

    在 EightQueen.vue 中写模板。

    EightQueen.vue:

    <template>
        <div>
            <div class="title">八皇后问题</div>
        </div>
    </template>
    View Code

    在 App.vue 中局部注册、引入、使用 EightQueen.vue 组件。

    App.vue:

    <template>
        <div id="app">
            <eight-queen />
        </div>
    </template>
     
    <script>
    import EightQueen from "./components/EightQueen";
     
    export default {
        name: "app",
        components: {
            EightQueen
        }
    }
    </script>
    View Code

    此时,页面表现:

    EightQueen.vue :

    棋盘格是一个 8x8 的矩阵,先写八横

    先写第一行的八纵

    上面这样写不好。通过 v-if 去遍历数据结构来写比较好。

    下面是改进:

    <template>
        <div>
            <div class="title">八皇后问题</div>
            
            <div class="gird">
                <div class="row" v-for="(row, r_index) in grids" :key="r_index">
                    <div class="cell" v-for="cell in row" :key="cell.key">
                        {{ `${cell.key}` }}
                    </div>
                </div>
            </div>
        </div>
    </template>
    
    <script>
    const grids = new Array(8).fill(1).map((_, r) => {
        return new Array(8).fill(1).map((_, c) => {
            return {
                key: `key-${r*8 + c}`,
                ok: false
            }
        })
    })
    
    export default {
        data(){
            return{
                grids
            }
        }
    }
    </script>
    View Code

    页面表现:

    (页面太长,截图头跟尾,输出了 64 个,key-0 到 key-63,对应八行八纵的 64 个格子)

    查看控制台:

    代码说明:

    定义数据结构,通过函数 data 返回数据对象 grids

    生成对象 girds,先生成一个八横的数据结构,newArray(8) 是生成了一个 length 为 8 的空数组。然后对八横的数据结构进行填充,给该数组用 fill(1) 方法是将该空数组的 8 个元素替换为 1,也就是数组现在为 [1, 1, 1, 1, 1, 1, 1, 1]。给八横的数据结构填充八纵,给该数组用 map 方法,map 方法的参数是一个函数,该函数的参数 _ 是当前值也就是 1 ,参数 r 是当前索引值,该函数作用于 [1, 1, 1, 1, 1, 1, 1, 1] 的每一个元素,因为要实现棋盘格八横八纵,所以每一横都对应八纵,所以给每一横返回一个八纵的数据结构,每一纵的数据结构返回数据对象 key 跟 ok,key 代表单元格唯一的键值,ok 代表是否被点击或者说是否被皇后占领。grids 是一个包含 8 个元素的数组,每一个元素都是一个 8 个元素的数组。

    方便理解,花了一个图,图中每小格对应的 key 值是 r*8 + c

    第 6 行:使用 v-for 去遍历每一横,grids 是数组对应代码第 16 行,row 是当前值,每一个 row 都是一个包含 8 个元素的数组,r_index 是当前索引值,需要绑定 key 值来帮助引擎更好地渲染 dom 节点。

    第 7 行:使用 v-for 去遍历一横中的每一纵,row 是一个包含 8 个元素的数组,cell 是当前值对应代码第 18-21 行,cell 包含数据对象 key 与 ok。

    第 8 行:写这条语句主要是为了看看页面效果。输出 cell.key ,整个遍历完后输出了 key-0 到 key-63 总共 64 个元素,对应棋盘格中八横八纵的每一个单元格。

    接下来写样式。

    使用 scoped 防止组件样式全局污染。(scoped相关笔记:https://www.cnblogs.com/xiaoxuStudy/p/13235418.html#three)

    一个 class 为 cell 的 div 对应 8x8 棋盘格中的一个格子。设置一个小格子宽高为 50 px、水平垂直居中、背景颜色为 #999。

    <template>
        <div>
            <div class="title">八皇后问题</div>
            
            <div class="gird">
                <div class="row" v-for="(row, r_index) in grids" :key="r_index">
                    <div class="cell" v-for="cell in row" :key="cell.key">
                    </div>
                </div>
            </div>
        </div>
    </template>
    
    <script>
    const grids = new Array(8).fill(1).map((_, r) => {
        return new Array(8).fill(1).map((_, c) => {
            return {
                key: `key-${r*8 + c}`,
                ok: false
            }
        })
    })
    
    export default {
        data(){
            return{
                grids
            }
        }
    }
    </script>
    
    <style scoped>
        .cell{
            width: 50px;
            height: 50px;
            line-height: 50px;
            text-align: center;
            background-color: #999;
        }
    </style>
    View Code

    页面表现(总共有64个格子):

    棋盘格相邻格子颜色不同。:nth-child(2n)  表示对索引是 2 的倍数 class 为 cell 的 div 元素指定背景颜色。

    <template>
        <div>
            <div class="title">八皇后问题</div>
            
            <div class="gird">
                <div class="row" v-for="(row, r_index) in grids" :key="r_index">
                    <div class="cell" v-for="cell in row" :key="cell.key">
                    </div>
                </div>
            </div>
        </div>
    </template>
    
    <script>
    const grids = new Array(8).fill(1).map((_, r) => {
        return new Array(8).fill(1).map((_, c) => {
            return {
                key: `key-${r*8 + c}`,
                ok: false
            }
        })
    })
    
    export default {
        data(){
            return{
                grids
            }
        }
    }
    </script>
    
    <style scoped>
        .cell{
            width: 50px;
            height: 50px;
            line-height: 50px;
            text-align: center;
            background-color: #999;
        }
        .cell:nth-child(2n){
            background: #efefef;
        }
    </style>
    View Code

    页面表现(总共有64个格子):

    设置样式让格子按照八行显示。一个 class 为 row 的 div 相当于棋盘格的一行,一共有八个 class 为 row 的 div,设置 class 为 row 的 div 高 50px 宽 400px(即8x50px),因为一行有八个格子。

    class 为 cell 的 div 是 class 为 row 的 div 子盒子,子盒子设置了浮动可能会导致高度塌陷所以需要在父盒子设置 display:flow-root 触发 BFC。

    <template>
        <div>
            <div class="title">八皇后问题</div>
            
            <div class="gird">
                <div class="row" v-for="(row, r_index) in grids" :key="r_index">
                    <div class="cell" v-for="cell in row" :key="cell.key">
                    </div>
                </div>
            </div>
        </div>
    </template>
    
    <script>
    const grids = new Array(8).fill(1).map((_, r) => {
        return new Array(8).fill(1).map((_, c) => {
            return {
                key: `key-${r*8 + c}`,
                ok: false
            }
        })
    })
    
    export default {
        data(){
            return{
                grids
            }
        }
    }
    </script>
    
    <style scoped>
        .cell{
            width: 50px;
            height: 50px;
            line-height: 50px;
            text-align: center;
            background-color: #999;
            float: left;
        }
        .cell:nth-child(2n){
            background: #efefef;
        }
        .row{
            height: 50px;
            width: 400px;
            display: flow-root;
        }
    </style>
    View Code

    页面表现:

    之前设置了.cell:nth-child(2n){background#efefef;},所以每一纵颜色都是相同的。

    设置样式实现每个格子上下左右相邻颜色均不同。设置索引是 2 的倍数的行的样式即可。

    第50-52行:索引是 2 的倍数 class 为 row 的 div 元素且索引是 2 的倍数 class 为 cell 的 div 元素背景颜色为 #999

    第53-55行:索引是 2 的倍数 class 为 row 的 div 元素且索引是 2n-1 的倍数 class 为 cell 的 div 元素背景颜色为 #efefef

    <template>
        <div>
            <div class="title">八皇后问题</div>
            
            <div class="gird">
                <div class="row" v-for="(row, r_index) in grids" :key="r_index">
                    <div class="cell" v-for="cell in row" :key="cell.key">
                    </div>
                </div>
            </div>
        </div>
    </template>
    
    <script>
    const grids = new Array(8).fill(1).map((_, r) => {
        return new Array(8).fill(1).map((_, c) => {
            return {
                key: `key-${r*8 + c}`,
                ok: false
            }
        })
    })
    
    export default {
        data(){
            return{
                grids
            }
        }
    }
    </script>
    
    <style scoped>
        .cell{
            width: 50px;
            height: 50px;
            line-height: 50px;
            text-align: center;
            background-color: #999;
            float: left;
        }
        .cell:nth-child(2n){
            background: #efefef;
        }
        .row{
            height: 50px;
            width: 400px;
            display: flow-root; 
        }
        .row:nth-child(2n) .cell:nth-child(2n){
            background: #999;
        }
        .row:nth-child(2n) .cell:nth-child(2n-1){
            background: #efefef;
        }
    </style>
    View Code

    页面表现:

    设置棋盘居中。

    <template>
        <div>
            <div class="title">八皇后问题</div>
            
            <div class="grid">
                <div class="row" v-for="(row, r_index) in grids" :key="r_index">
                    <div class="cell" v-for="cell in row" :key="cell.key">
                    </div>
                </div>
            </div>
        </div>
    </template>
    
    <script>
    const grids = new Array(8).fill(1).map((_, r) => {
        return new Array(8).fill(1).map((_, c) => {
            return {
                key: `key-${r*8 + c}`,
                ok: false
            }
        })
    })
    
    export default {
        data(){
            return{
                grids
            }
        }
    }
    </script>
    
    <style scoped>
        .grid{
            width: 400px;
            margin: 0 auto;
        }
        .cell{
            width: 50px;
            height: 50px;
            line-height: 50px;
            text-align: center;
            background-color: #999;
            float: left;
        }
        .cell:nth-child(2n){
            background: #efefef;
        }
        .row{
            height: 50px;
            width: 400px;
            display: flow-root; 
        }
        .row:nth-child(2n) .cell:nth-child(2n){
            background: #999;
        }
        .row:nth-child(2n) .cell:nth-child(2n-1){
            background: #efefef;
        }
    </style>
    View Code

    页面表现:

    接着,实现鼠标点击棋盘格放置皇后,这里字母 “Q” 代表皇后。

    实现光标移动到棋盘格内时,光标为“一只手”。

    <template>
        <div>
            <div class="title">八皇后问题</div>
            
            <div class="grid">
                <div class="row" v-for="(row, r_index) in grids" :key="r_index">
                    <div class="cell" v-for="cell in row" :key="cell.key">
                    </div>
                </div>
            </div>
        </div>
    </template>
    
    <script>
    const grids = new Array(8).fill(1).map((_, r) => {
        return new Array(8).fill(1).map((_, c) => {
            return {
                key: `key-${r*8 + c}`,
                ok: false
            }
        })
    })
    
    export default {
        data(){
            return{
                grids
            }
        }
    }
    </script>
    
    <style scoped>
        .grid{
            width: 400px;
            margin: 0 auto;
        }
        .cell{
            width: 50px;
            height: 50px;
            line-height: 50px;
            text-align: center;
            background-color: #999;
            float: left;
            cursor: pointer;
        }
        .cell:nth-child(2n){
            background: #efefef;
        }
        .row{
            height: 50px;
            width: 400px;
            display: flow-root; 
        }
        .row:nth-child(2n) .cell:nth-child(2n){
            background: #999;
        }
        .row:nth-child(2n) .cell:nth-child(2n-1){
            background: #efefef;
        }
    </style>
    View Code

    页面表现(说明:下图是用相机拍摄的,截图显示不出光标):

    实现为每个格子添加点击事件。

    第 8 行: 添加一个 v-if 判断 cell.ok (对应第20行) 是否为 true,如果为 true 则显示皇后“Q”

    第 7 行:使用 @click 添加点击事件,使用 .stop 修饰符阻止默认冒泡,添加一个 select 函数。棋盘格八横八纵,r_index 是遍历横时的当前索引,c_index 是遍历纵时的当前索引。给 select 函数传入 r_index 跟 c_index 作为参数。当点击棋盘格格子时触发点击事件执行 select 函数。

    第 32 行: 在 methods 里添加 select 函数。grids[rindex][cindex]对应棋盘中的一个格子,select 函数的作用是设置 ok (对应20行)为true,ok 为 true 后 "Q" 就显示出来(对应第 8 行)。

    <template>
        <div>
            <div class="title">八皇后问题</div>
            
            <div class="grid">
                <div class="row" v-for="(row, r_index) in grids" :key="r_index">
                    <div class="cell" v-for="(cell, c_index) in row" :key="cell.key" @click.stop="select(r_index, c_index)">
                        <div v-if="cell.ok">Q</div>
                    </div>
                </div>
            </div>
        </div>
    </template>
    
    <script>
    const grids = new Array(8).fill(1).map((_, r) => {
        return new Array(8).fill(1).map((_, c) => {
            return {
                key: `key-${r*8 + c}`,
                ok: false
            }
        })
    })
    
    export default {
        data(){
            return{
                grids
            }
        },
        methods: {
            select(rindex, cindex) {
                this.grids[rindex][cindex].ok = true;
            }
        }
    }
    </script>
    
    <style scoped>
        .grid{
            width: 400px;
            margin: 0 auto;
        }
        .cell{
            width: 50px;
            height: 50px;
            line-height: 50px;
            text-align: center;
            background-color: #999;
            float: left;
            cursor: pointer;
        }
        .cell:nth-child(2n){
            background: #efefef;
        }
        .row{
            height: 50px;
            width: 400px;
            display: flow-root; 
        }
        .row:nth-child(2n) .cell:nth-child(2n){
            background: #999;
        }
        .row:nth-child(2n) .cell:nth-child(2n-1){
            background: #efefef;
        }
    </style>
    View Code

    页面表现:

    在棋盘格上随意点击几个格子,点击的格子里出现了“Q”

    八皇后小游戏要满足一个皇后的同一横、竖、撇、捺都不能放置皇后。

    可以先把每个小格子的坐标都显示出来,方便找出规律,进行逻辑运算。

    根据坐标,写 validate 方法,实现一个皇后的同一横、竖、撇、捺都不能放置皇后。

    顺便把标题改了,把游戏规则写上了。

    <template>
        <div>
            <div class="introduction">
                <div class="title">八皇后小游戏</div>
                <div class="rule">规则:在8x8的棋盘上放置8个皇后,即任两个皇后都不能处于同一条横线、纵线或者斜线上。</div>
            </div>
            <div class="grid">
                <div class="row" v-for="(row, r_index) in grids" :key="r_index">
                    <div class="cell" v-for="(cell, c_index) in row" :key="cell.key" @click.stop="select(r_index, c_index)">
                        <div v-if="cell.ok">Q</div>
                    </div>
                </div>
            </div>
        </div>
    </template>
    
    <script>
    const grids = new Array(8).fill(1).map((_, r) => {
        return new Array(8).fill(1).map((_, c) => {
            return {
                key: `key-${r*8 + c}`,
                ok: false
            }
        })
    })
    
    export default {
        data(){
            return{
                grids
            }
        },
        methods: {
            select(rindex, cindex) {
                if(this.validate(rindex, cindex)){
                    this.grids[rindex][cindex].ok = !this.grids[rindex][cindex].ok;
                }else{
                    alert('该位置不能放置皇后!');
                }
            },
            validate(rindex, cindex){
                //
                for(let i=0; i<this.grids[rindex].length; i++){
                    if(this.grids[rindex][i].ok){
                        return false;
                    }
                }
                //
                for(let i=0; i<this.grids.length; i++){
                    if(this.grids[i][cindex].ok){
                        return false;
                    }
                }
                //
                for(let i=0; i<this.grids[0].length; i++){
                    let y = rindex + cindex - i;
                    if( y>=0 &&  y<this.grids.length && this.grids[y][i].ok){
                        return false;
                    }y
                }
                //
                for(let i=0; i<this.grids[0].length; i++){
                    let y = rindex - cindex + i;
                    if( y>=0 && y<this.grids.length && this.grids[y][i].ok ){
                        return false;
                    }
                }
    
                return true;
            }
        }
    }
    </script>
    
    <style scoped>
        .grid{
            width: 400px;
            margin: 0 auto;
        }
        .cell{
            width: 50px;
            height: 50px;
            line-height: 50px;
            text-align: center;
            background-color: #999;
            float: left;
            cursor: pointer;
        }
        .cell:nth-child(2n){
            background: #efefef;
        }
        .row{
            height: 50px;
            width: 400px;
            display: flow-root; 
        }
        .row:nth-child(2n) .cell:nth-child(2n){
            background: #999;
        }
        .row:nth-child(2n) .cell:nth-child(2n-1){
            background: #efefef;
        }
        .title{
            font-size: 30px;
            padding-bottom: 20px;
        }
        .introduction{
            text-align: center;
            padding: 30px 0;
        }
    </style>
    App.vue

    页面表现:

    如果在皇后的同一横、竖、撇、捺上放置皇后,会弹出提示

     放下八个皇后的成功例子

    至此,已经简单完成了一个八皇后小游戏。

  • 相关阅读:
    感知机简单算法的实现
    C语言博客作业02
    我的第二次C语言作业
    [原]wpf foundation Part 1 of n (object resource )
    [orginal]TabControlView based on css ,js and html .
    [orginal]checkBox based on web(thinking in & implementation)
    [orginal] Progressbar implementation with js,css,and html
    [orginal]Combolist visual design & and implementation ( based on css ,js and html)
    [orginal] nice look ListBox with powerful methodes designing & implementation based on web technology.
    [orginal]treeView control based on WEB
  • 原文地址:https://www.cnblogs.com/xiaoxuStudy/p/13216592.html
Copyright © 2011-2022 走看看