八皇后小游戲規(guī)則與效果預(yù)覽
規(guī)則:

效果預(yù)覽:
用字母 Q 代表皇后,橫/豎/撇/捺處均無皇后可放置皇后,在橫/豎/撇/捺有皇后處放置皇后會(huì)彈出提示“該位置不能放置皇后!”。

實(shí)現(xiàn)步驟
之前創(chuàng)建了項(xiàng)目,筆記:http://www.rzrgm.cn/xiaoxuStudy/p/12663218.html
當(dāng)前目錄結(jié)構(gòu):
(注意:組件命名用大駝峰命名法。)

在 EightQueen.vue 中寫模板。
EightQueen.vue:
<template> <div> <div class="title">八皇后問題</div> </div> </template>

在 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>

此時(shí),頁面表現(xiàn):

EightQueen.vue :
棋盤格是一個(gè) 8x8 的矩陣,先寫八橫

先寫第一行的八縱

上面這樣寫不好。通過 v-if 去遍歷數(shù)據(jù)結(jié)構(gòu)來寫比較好。
下面是改進(jìn):
<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>

頁面表現(xiàn):
(頁面太長,截圖頭跟尾,輸出了 64 個(gè),key-0 到 key-63,對應(yīng)八行八縱的 64 個(gè)格子)


查看控制臺(tái):

代碼說明:
定義數(shù)據(jù)結(jié)構(gòu),通過函數(shù) data 返回?cái)?shù)據(jù)對象 grids

生成對象 girds,先生成一個(gè)八橫的數(shù)據(jù)結(jié)構(gòu),newArray(8) 是生成了一個(gè) length 為 8 的空數(shù)組。然后對八橫的數(shù)據(jù)結(jié)構(gòu)進(jìn)行填充,給該數(shù)組用 fill(1) 方法是將該空數(shù)組的 8 個(gè)元素替換為 1,也就是數(shù)組現(xiàn)在為 [1, 1, 1, 1, 1, 1, 1, 1]。給八橫的數(shù)據(jù)結(jié)構(gòu)填充八縱,給該數(shù)組用 map 方法,map 方法的參數(shù)是一個(gè)函數(shù),該函數(shù)的參數(shù) _ 是當(dāng)前值也就是 1 ,參數(shù) r 是當(dāng)前索引值,該函數(shù)作用于 [1, 1, 1, 1, 1, 1, 1, 1] 的每一個(gè)元素,因?yàn)橐獙?shí)現(xiàn)棋盤格八橫八縱,所以每一橫都對應(yīng)八縱,所以給每一橫返回一個(gè)八縱的數(shù)據(jù)結(jié)構(gòu),每一縱的數(shù)據(jù)結(jié)構(gòu)返回?cái)?shù)據(jù)對象 key 跟 ok,key 代表單元格唯一的鍵值,ok 代表是否被點(diǎn)擊或者說是否被皇后占領(lǐng)。grids 是一個(gè)包含 8 個(gè)元素的數(shù)組,每一個(gè)元素都是一個(gè) 8 個(gè)元素的數(shù)組。

方便理解,花了一個(gè)圖,圖中每小格對應(yīng)的 key 值是 r*8 + c

第 6 行:使用 v-for 去遍歷每一橫,grids 是數(shù)組對應(yīng)代碼第 16 行,row 是當(dāng)前值,每一個(gè) row 都是一個(gè)包含 8 個(gè)元素的數(shù)組,r_index 是當(dāng)前索引值,需要綁定 key 值來幫助引擎更好地渲染 dom 節(jié)點(diǎn)。
第 7 行:使用 v-for 去遍歷一橫中的每一縱,row 是一個(gè)包含 8 個(gè)元素的數(shù)組,cell 是當(dāng)前值對應(yīng)代碼第 18-21 行,cell 包含數(shù)據(jù)對象 key 與 ok。
第 8 行:寫這條語句主要是為了看看頁面效果。輸出 cell.key ,整個(gè)遍歷完后輸出了 key-0 到 key-63 總共 64 個(gè)元素,對應(yīng)棋盤格中八橫八縱的每一個(gè)單元格。

接下來寫樣式。
使用 scoped 防止組件樣式全局污染。(scoped相關(guān)筆記:http://www.rzrgm.cn/xiaoxuStudy/p/13235418.html#three)
一個(gè) class 為 cell 的 div 對應(yīng) 8x8 棋盤格中的一個(gè)格子。設(shè)置一個(gè)小格子寬高為 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>

頁面表現(xiàn)(總共有64個(gè)格子):

棋盤格相鄰格子顏色不同。:nth-child(2n) 表示對索引是 2 的倍數(shù) 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>

頁面表現(xiàn)(總共有64個(gè)格子):

設(shè)置樣式讓格子按照八行顯示。一個(gè) class 為 row 的 div 相當(dāng)于棋盤格的一行,一共有八個(gè) class 為 row 的 div,設(shè)置 class 為 row 的 div 高 50px 寬 400px(即8x50px),因?yàn)橐恍杏邪藗€(gè)格子。
class 為 cell 的 div 是 class 為 row 的 div 子盒子,子盒子設(shè)置了浮動(dòng)可能會(huì)導(dǎo)致高度塌陷所以需要在父盒子設(shè)置 display:flow-root 觸發(fā) 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>

頁面表現(xiàn):

之前設(shè)置了.cell:nth-child(2n){background: #efefef;},所以每一縱顏色都是相同的。
設(shè)置樣式實(shí)現(xiàn)每個(gè)格子上下左右相鄰顏色均不同。設(shè)置索引是 2 的倍數(shù)的行的樣式即可。
第50-52行:索引是 2 的倍數(shù) class 為 row 的 div 元素且索引是 2 的倍數(shù) class 為 cell 的 div 元素背景顏色為 #999
第53-55行:索引是 2 的倍數(shù) class 為 row 的 div 元素且索引是 2n-1 的倍數(shù) 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>

頁面表現(xiàn):

設(shè)置棋盤居中。
<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>

頁面表現(xiàn):

接著,實(shí)現(xiàn)鼠標(biāo)點(diǎn)擊棋盤格放置皇后,這里字母 “Q” 代表皇后。
實(shí)現(xiàn)光標(biāo)移動(dòng)到棋盤格內(nèi)時(shí),光標(biāo)為“一只手”。
<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>

頁面表現(xiàn)(說明:下圖是用相機(jī)拍攝的,截圖顯示不出光標(biāo)):

實(shí)現(xiàn)為每個(gè)格子添加點(diǎn)擊事件。
第 8 行: 添加一個(gè) v-if 判斷 cell.ok (對應(yīng)第20行) 是否為 true,如果為 true 則顯示皇后“Q”
第 7 行:使用 @click 添加點(diǎn)擊事件,使用 .stop 修飾符阻止默認(rèn)冒泡,添加一個(gè) select 函數(shù)。棋盤格八橫八縱,r_index 是遍歷橫時(shí)的當(dāng)前索引,c_index 是遍歷縱時(shí)的當(dāng)前索引。給 select 函數(shù)傳入 r_index 跟 c_index 作為參數(shù)。當(dāng)點(diǎn)擊棋盤格格子時(shí)觸發(fā)點(diǎn)擊事件執(zhí)行 select 函數(shù)。
第 32 行: 在 methods 里添加 select 函數(shù)。grids[rindex][cindex]對應(yīng)棋盤中的一個(gè)格子,select 函數(shù)的作用是設(shè)置 ok (對應(yīng)20行)為true,ok 為 true 后 "Q" 就顯示出來(對應(yīng)第 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>


頁面表現(xiàn):
在棋盤格上隨意點(diǎn)擊幾個(gè)格子,點(diǎn)擊的格子里出現(xiàn)了“Q”

八皇后小游戲要滿足一個(gè)皇后的同一橫、豎、撇、捺都不能放置皇后。
可以先把每個(gè)小格子的坐標(biāo)都顯示出來,方便找出規(guī)律,進(jìn)行邏輯運(yùn)算。

根據(jù)坐標(biāo),寫 validate 方法,實(shí)現(xiàn)一個(gè)皇后的同一橫、豎、撇、捺都不能放置皇后。
順便把標(biāo)題改了,把游戲規(guī)則寫上了。
<template> <div> <div class="introduction"> <div class="title">八皇后小游戲</div> <div class="rule">規(guī)則:在8x8的棋盤上放置8個(gè)皇后,即任兩個(gè)皇后都不能處于同一條橫線、縱線或者斜線上。</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>

頁面表現(xiàn):
如果在皇后的同一橫、豎、撇、捺上放置皇后,會(huì)彈出提示

放下八個(gè)皇后的成功例子

至此,已經(jīng)簡單完成了一個(gè)八皇后小游戲。
浙公網(wǎng)安備 33010602011771號