前言
掃雷小遊戲已推入gitHub點擊此處試玩
歡迎各位體驗,菜雞的練手小項目,輕噴。
同樣可在留言處或在線諮詢提出您寶貴的意見,祝您玩得愉快
介紹
掃雷小遊戲通過洗牌算法進行隨機佈雷,通過用戶點擊對旁邊區域進行搜索判斷,達到空白的展開效果
目前遊戲中有9*9
,15*15
,20*20
三張地圖,後期會加入更多。雷數可自己調節或隨機生成
難點詳解
- 洗牌算法:
洗牌算法可實現集合的隨機排序,且各排序機率等同,因此正好可以實現隨機佈雷的效果
參考於:實現洗牌算法
function shuffle() {
for(let i = grids.length-1; i >0 ; i--) {
let randomIndex = Math.floor(Math.random()*(grids.length-1))
let temp = grids[i]
grids[i] = grids[randomIndex]
grids[randomIndex] = temp
}
}
- 渲染地圖
渲染地圖前首先要把數組分割,在計算機中二維數組
正好可以對應上平面中的x軸,y軸所以可把數組分割爲二維數組
function sliceArray(minColumns) {
let reasonable = grids.length % minColumns == 0 ? true:false
let newColumns = minColumns
columns = minColumns
do {
if(reasonable) {
lines = grids.length/columns
//console.log(grids.length + ' '+ columns + ' ' + lines)
break
} else {
newColumns++
console.log('分行失敗,已調整列數爲' + newColumns)
reasonable = grids.length % newColumns == 0 ? true:false
}
columns = newColumns
} while (newColumns< 10 + columns)
if(lines == 0){
console.log('棋盤創建失敗,請選擇合理的棋格數')
} else {
for (let i = 0; i < lines; i++) {
arr.push(grids.slice(i*lines,i*lines+lines))
}
arr.forEach((element, index) => {
element.forEach((ele, inde) =>{
ele.x = index
ele.y = inde
})
})
}
fillNumber(arr, lines, columns) //此處填充數字
for(let i = 0; i < lines; i++){
for(let j = 0; j < columns; j++) {
div = document.createElement('div')
div.index = arr[i][j].id
div.value = arr[i][j].number
div.dirx = arr[i][j].x
div.diry = arr[i][j].y
div.state = arr[i][j].state
div.className = 'grid'
main.appendChild(div)
}
}
main.style.width = 25*lines +2*(lines-1) +'px'
main.style.gridTemplateColumns = 'repeat(' + lines + ', 25px)'
}
- 填充數字
通過對每個元素進行遍歷,然後判斷其8個方向,如果是雷則方格數字+1
function fillNumber(arr, lines, columns) {
let dir = [[-1,0],[-1,1],[0,1],[1,1],[1,0],[1,-1],[0,-1],[-1,-1]]
for(let i = 0; i < lines; i++){
for(let j = 0; j < columns; j++) {
for(let k = 0; k < 8; k++) {
if(i + dir[k][0] < 0 || i+dir[k][0] >= lines || j + dir[k][1] < 0 || j + dir[k][1] >= columns){
continue
}
if(arr[i+dir[k][0]][j+dir[k][1]].sweep == true && arr[i][j].number != 9) {
arr[i][j].number += 1
}
}
}
}
}
- 對方格添加點擊事件
通過事件委託
方式添加點擊事件
function addClickEvent() {
main.addEventListener('click', (e) => {
switch(e.target.value) {
case 0: scanGrid(e.target); break
case 1: changeState(e.target); addColor(e.target, 'rgb(80, 228, 159)', '#aaa'); break
case 2: changeState(e.target); addColor(e.target, 'rgb(230, 199, 112)', '#aaa'); break
case 3: changeState(e.target); addColor(e.target, 'rgb(239, 243, 30)', '#aaa'); break
case 4:
case 5:
case 6:
case 7:
case 8: changeState(e.target); addColor(e.target, 'rgb(255, 115, 48)', '#aaa'); break
case 9: addColor(e.target, 'rgb(240, 78, 49)' , '#fbb', '?'); gameOver(); break
}
if(count == gridss - sweeps) {
console.log('你獲勝了')
mark.style.display = 'block'
}
})
main.addEventListener('contextmenu', (e) =>{
if(e.path.length == 9){
if (e.target.textContent == '?') {
addColor(e.target, '' , '', '')
} else {
addColor(e.target, '' , '', '?')
}
}
e.preventDefault()
})
}
- 掃描
通過廣搜算法進行掃描如果,點擊到0把所有0和其邊緣方格展開提高用戶體驗
PS:廣搜算法解析
function scanGrid(base) {
let dir = [[-1,0],[-1,1],[0,1],[1,1],[1,0],[1,-1],[0,-1],[-1,-1]]
let scanArr = new Array()
arr[base.dirx][base.diry].state = true
count++
scanArr.push(arr[base.dirx][base.diry])
while (scanArr.length != 0){
let element = scanArr.pop()
//console.log(scanArr.length)
divArr[element.x][element.y].style.backgroundColor = '#ccc'
for(let k = 0; k < 8; k++) {
if(element.x + dir[k][0] < 0 || element.x + dir[k][0] >= lines || element.y + dir[k][1] < 0 || element.y + dir[k][1] >= columns){
continue
}
if(arr[element.x+dir[k][0]][element.y+dir[k][1]].state == false && arr[element.x+dir[k][0]][element.y+dir[k][1]].number == 0) {
scanArr.push(arr[element.x+dir[k][0]][element.y+dir[k][1]])
arr[element.x+dir[k][0]][element.y+dir[k][1]].state = true
count++
} else if (arr[element.x+dir[k][0]][element.y+dir[k][1]].state == false && arr[element.x+dir[k][0]][element.y+dir[k][1]].number != 9) {
let a = arr[element.x+dir[k][0]][element.y+dir[k][1]].state == false && arr[element.x+dir[k][0]][element.y+dir[k][1]].number
let a_x = element.x+dir[k][0]
let a_y = element.y+dir[k][1]
arr[a_x][a_y].state = true
count++
switch(a) {
case 1: addColor(divArr[a_x][a_y], 'rgb(80, 228, 159)', '#aaa'); break
case 2: addColor(divArr[a_x][a_y], 'rgb(230, 199, 112)', '#aaa'); break
case 3: addColor(divArr[a_x][a_y], 'rgb(239, 243, 30)', '#aaa'); break
case 4:
case 5:
case 6:
case 7:
case 8: addColor(divArr[a_x][a_y], 'rgb(255, 115, 48)', '#aaa'); break
}
}
}
}
}
- 遊戲失敗
把地圖中所有雷顯示出來並且在1s後彈出遮罩層
function gameOver() {
divs.forEach(element => {
if(element.value == 9){
addColor(element, 'rgb(240, 78, 49)' , '#fbb', '?')
}
});
setTimeout(() => {
mark.style.display = 'block'
}, 1000);
}