使用原生JS快速寫出一個(gè)五子棋小游戲
1.棋盤和棋子的繪制。
let arr = [ [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},], [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},], [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},], [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},], [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},], [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},], [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},], [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},], [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},], [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},], [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},], [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},], [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},], [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},], [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {},], ] //封裝渲染函數(shù) const render = () => { document.querySelector('table').innerHTML = '' arr.forEach((item, index) => { let tr = document.createElement('tr') item.forEach((item2, index2) => { let td = document.createElement('td')//遍歷數(shù)組,繪制棋盤 //給td標(biāo)簽設(shè)置自定義屬性,用來(lái)作為坐標(biāo)使用 td.dataset.y = index td.dataset.x = index2 tr.appendChild(td) //給數(shù)組里面的對(duì)象做條件判斷,這樣就能渲染出顏色 if (item2.num === 1) { td.classList.add('bgc1') } else if (item2.num === 2) { td.classList.add('bgc2') } }) document.querySelector('table').appendChild(tr) }) } render()
先創(chuàng)建一個(gè)15 * 15的二維數(shù)組,通過(guò)對(duì)數(shù)組的兩層遍歷,創(chuàng)建出一個(gè)15*15的表格,這樣棋盤就有了。用數(shù)組來(lái)繪制棋盤的好處是便于查找和篩選。 每一個(gè)td都對(duì)應(yīng)著一個(gè)空對(duì)象,下棋的時(shí)候通過(guò)給這個(gè)對(duì)象添加一個(gè)num的屬性,num為1時(shí),就渲染成黑色,2就渲染成白色,再稍微調(diào)整一下css樣式,這樣棋盤和棋子就繪制好了。每一個(gè)td都有自己的自定義屬性x和y,類似于坐標(biāo),這樣就可以很方便的把td標(biāo)簽和數(shù)組里對(duì)應(yīng)的值聯(lián)系起來(lái)。 下面是css代碼
<style> * { margin: 0; padding: 0; box-sizing: border-box; list-style: none; } table { position: relative; width: 730px; height: 730px; margin: 0 auto; border: 5px solid black; background: url(./src=http___pic45.nipic.com_20140804_2372131_155038114014_2.jpg&refer=http___pic45.nipic.webp) no-repeat; background-size: 100%; background-position: center; padding: 24px 12px; } td { width: 35px; height: 35px; border-radius: 50%; margin-right: 13px; margin-bottom: 11px; cursor: pointer; } .bgc1 { background-color: black; } .bgc2 { background-color: white; } button { position: absolute; width: 200px; height: 100px; bottom: 100px; right: 200px; text-align: center; line-height: 100px; font-size: 25px; } </style>
<table></table> <button>悔棋</button>
2.輪流下棋的點(diǎn)擊事件
下棋的邏輯很簡(jiǎn)單,就是點(diǎn)擊棋盤的時(shí)候,給點(diǎn)擊的td對(duì)應(yīng)的那個(gè)對(duì)象添加一個(gè)num屬性,黑棋就是1,白棋就是2,然后渲染出來(lái)就可以了。下棋順序可以通過(guò)一個(gè)全局變量flag來(lái)控制,同時(shí)聲明兩個(gè)全局?jǐn)?shù)組,用來(lái)存放所有的黑棋和白棋。后面判斷勝負(fù)時(shí),要對(duì)這兩個(gè)數(shù)組先進(jìn)行遍歷。
//判斷下棋順序的全局變量 let flag = true //所有黑棋數(shù)組 let blackArr = [] //所有白棋數(shù)組 let whiteArr = [] //輪流下棋邏輯 document.querySelector('table').addEventListener('click', function (e) { if (e.target.dataset.x) { let td = e.target //判斷黑白棋子的順序 if (flag) { //判斷點(diǎn)擊的地方是否已經(jīng)有棋子了,避免棋子覆蓋 if (!arr[td.dataset.y][td.dataset.x].num) { flag = !flag arr[td.dataset.y][td.dataset.x].num = 1 //每走一步,就將其添加至對(duì)應(yīng)的數(shù)組當(dāng)中 blackArr.push([td.dataset.y, td.dataset.x]) } } else { if (!arr[td.dataset.y][td.dataset.x].num) { flag = !flag arr[td.dataset.y][td.dataset.x].num = 2 whiteArr.push([td.dataset.y, td.dataset.x]) } } //調(diào)用判斷勝負(fù)的函數(shù) XWin(td) YWin(td) X_YWin(td) Y_XWin(td) } render() })
3.獲勝條件判斷
接下來(lái)就是寫獲勝條件了。我分成了4種情況,橫軸,數(shù)軸,正斜軸和反斜軸。這4種情況邏輯和方法大致都是相同的,就是里面的數(shù)據(jù)有些細(xì)微差別。
3.1橫軸獲勝
以橫軸為例,如何判斷獲勝,先判斷是黑棋還是白棋,然后遍歷對(duì)應(yīng)的數(shù)組。已黑棋為例,遍歷之后把y值相同的黑棋篩選出來(lái)都放入一個(gè)數(shù)組中,也就是同一行的黑棋。接著比較這一行的這些黑棋的x值,如果有5個(gè)連續(xù)的x值,則說(shuō)明橫軸上有5個(gè)連續(xù)的黑棋,就可以判斷獲勝了。怎么比較這些x值呢,我的做法是先將他們用sort()方法排序,接著從小到大依次比較。建一個(gè)新數(shù)組,第二個(gè)值等于第一個(gè)值加1,就把他們?nèi)拥竭@個(gè)新數(shù)組中,如果出現(xiàn)某個(gè)值不連續(xù)了,就將這個(gè)數(shù)組清空,這樣通過(guò)判斷這個(gè)數(shù)組的長(zhǎng)度,就能判斷勝負(fù)了。
//橫軸獲勝邏輯 function XWin(td) { //當(dāng)前X軸的所有棋子集合 let xAllArr = [] //判斷橫軸勝負(fù)邏輯的X軸棋子 let xWinArr = [] //判斷下的是黑棋還是白棋 if (!flag) { blackArr.map(item => { if (item[0] == td.dataset.y) { //將當(dāng)前排的所有棋子加入對(duì)應(yīng)數(shù)組 xAllArr.push(item[1]) } }) } else { whiteArr.map(item => { if (item[0] == td.dataset.y) { xAllArr.push(item[1]) } }) } //把橫排總數(shù)組排序,方便比較 xAllArr.sort((a, b) => a - b) for (let i = 1; i < xAllArr.length; i++) { // console.log(xAllArr[i]); if (xAllArr[i] == (+xAllArr[i - 1] + 1)) { //如果相鄰的兩個(gè)棋子數(shù)量相差1,就將其添加至勝負(fù)邏輯數(shù)組 xWinArr.push(xAllArr[i]) } else { //否則得清空 xWinArr = [] } } //獲勝條件 if (xWinArr.length == 4) { //這里要用定時(shí)器將彈框變成異步任務(wù),否則第五顆棋子渲染不出來(lái)就提示獲勝了 if (!flag) { setTimeout(function () { alert('黑棋獲勝!') location.reload() }, 100) } else { setTimeout(function () { alert('白棋獲勝!') location.reload() }, 100) } } }
3.2數(shù)軸獲勝
豎軸和橫軸代碼基本上也相同
只是換了個(gè)條件,把if (item[0] == td.dataset.y)
換成了if (item[1] == td.dataset.x)
,意思就是選出這一列所有的棋子。后面的邏輯和代碼就和橫軸一樣了。
//豎軸獲勝邏輯 function YWin(td) { //當(dāng)前Y軸的所有棋子集合 let yAllArr = [] //判斷豎軸勝負(fù)邏輯的X軸棋子 let yWinArr = [] if (!flag) { blackArr.map(item => { if (item[1] == td.dataset.x) { yAllArr.push(item[0]) } }) } else { whiteArr.map(item => { if (item[1] == td.dataset.x) { yAllArr.push(item[0]) } }) } //豎排總數(shù)組排序 yAllArr.sort((a, b) => a - b) for (let i = 1; i < yAllArr.length; i++) { // console.log(xAllArr[i]); if (yAllArr[i] == (+yAllArr[i - 1] + 1)) { yWinArr.push(yAllArr[i]) } else { yWinArr = [] } } if (yWinArr.length == 4) { if (!flag) { setTimeout(function () { alert('黑棋獲勝!') location.reload() }, 100) } else { setTimeout(function () { alert('白棋獲勝!') location.reload() }, 100) } } }
3.3正斜軸獲勝
斜軸困難一點(diǎn)的地方就是,怎么篩選出這一條斜線上的所有棋子。
只要能把這條斜線上的棋子給找出來(lái),后面的邏輯判斷就都一樣了。所有的斜線都是45度角,也就是說(shuō)斜線上的任意兩個(gè)棋子,他們的x值之差于y值之差是相等的。這樣的話,判斷起來(lái)就簡(jiǎn)單了。 if ((item[0] - td.dataset.y) == (item[1] - td.dataset.x))
這樣就可以了。斜線上的棋子找出來(lái)后,后面的步驟就都一樣了,復(fù)制粘貼即可。
//正斜軸獲勝邏輯 function X_YWin(td) { //當(dāng)前X軸的所有棋子集合 let x_yAllArr = [] //判斷橫軸勝負(fù)邏輯的X軸棋子 let x_yWinArr = [] if (!flag) { blackArr.map(item => { //判斷斜軸棋子,斜軸棋子的x和y之差都是相同的 if ((item[0] - td.dataset.y) == (item[1] - td.dataset.x)) { x_yAllArr.push(item[1]) } }) } else { whiteArr.map(item => { if ((item[0] - td.dataset.y) == (item[1] - td.dataset.x)) { x_yAllArr.push(item[1]) } }) } x_yAllArr.sort((a, b) => a - b) for (let i = 1; i < x_yAllArr.length; i++) { if (x_yAllArr[i] == (+x_yAllArr[i - 1] + 1)) { //如果相鄰的兩個(gè)棋子數(shù)量相差1,就將其添加至勝負(fù)邏輯數(shù)組 x_yWinArr.push(x_yAllArr[i]) } else { //否則得清空 x_yWinArr = [] } } //獲勝條件 if (x_yWinArr.length == 4) { if (!flag) { setTimeout(function () { alert('黑棋獲勝!') location.reload() }, 100) } else { setTimeout(function () { alert('白棋獲勝!') location.reload() }, 100) } } }
3.4反斜軸獲勝
反斜軸同理,條件改成 if (0 - (item[0] - td.dataset.y) == (item[1] - td.dataset.x))
,其余的復(fù)制粘貼。
//反斜軸獲勝邏輯 function Y_XWin(td) { //當(dāng)前X軸的所有棋子集合 let y_xAllArr = [] //判斷橫軸勝負(fù)邏輯的X軸棋子 let y_xWinArr = [] if (!flag) { blackArr.map(item => { //判斷斜軸棋子 if (0 - (item[0] - td.dataset.y) == (item[1] - td.dataset.x)) { y_xAllArr.push(item[1]) } }) } else { whiteArr.map(item => { if (0 - (item[0] - td.dataset.y) == (item[1] - td.dataset.x)) { y_xAllArr.push(item[1]) } }) } y_xAllArr.sort((a, b) => a - b) for (let i = 1; i < y_xAllArr.length; i++) { if (y_xAllArr[i] == (+y_xAllArr[i - 1] + 1)) { //如果相鄰的兩個(gè)棋子數(shù)量相差1,就將其添加至勝負(fù)邏輯數(shù)組 y_xWinArr.push(y_xAllArr[i]) } else { //否則得清空 y_xWinArr = [] } } //獲勝條件 if (y_xWinArr.length == 4) { if (!flag) { setTimeout(function () { alert('黑棋獲勝!') location.reload() }, 100) } else { setTimeout(function () { alert('白棋獲勝!') location.reload() }, 100) } } }
把這些函數(shù)放到下棋事件里面調(diào)用,整個(gè)功能就完成了。
4.悔棋功能
最后寫一下悔棋功能,點(diǎn)擊悔棋,把對(duì)應(yīng)數(shù)組里面的數(shù)據(jù)刪除,然后重新渲染棋盤就完事了。
//悔棋 document.querySelector('button').addEventListener('click', function () { //判斷前面一步是黑棋還是白棋 if (!flag) { //黑棋 //獲取對(duì)應(yīng)棋子總數(shù)組的最后一個(gè)數(shù)據(jù)的值 const y = blackArr[blackArr.length - 1][0] const x = blackArr[blackArr.length - 1][1] //將對(duì)應(yīng)的對(duì)象里的num值刪除,這樣渲染出來(lái)對(duì)應(yīng)棋子就消失了 delete arr[y][x].num //刪除總數(shù)組里的最后一個(gè)數(shù)據(jù),否則勝負(fù)邏輯會(huì)有問(wèn)題 blackArr.splice(blackArr.length - 1, 1) //重置下棋順序 flag = !flag } else { //白棋 const y = whiteArr[whiteArr.length - 1][0] const x = whiteArr[whiteArr.length - 1][1] delete arr[y][x].num whiteArr.splice(whiteArr.length - 1, 1) flag = !flag } render() })
總結(jié)
整個(gè)代碼寫下來(lái),都是些js的基本語(yǔ)法,幾個(gè)數(shù)組的方法來(lái)回用,希望能給js初學(xué)者一些幫助。
到此這篇關(guān)于使用原生JS快速寫出一個(gè)五子棋小游戲的文章就介紹到這了,更多相關(guān)原生JS寫五子棋小游戲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深入理解JavaScript中的call、apply、bind方法的區(qū)別
下面小編就為大家?guī)?lái)一篇深入理解JavaScript中的call、apply、bind方法的區(qū)別。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-05-05詳解js根據(jù)百度地圖提供經(jīng)緯度計(jì)算兩點(diǎn)距離
這篇文章主要介紹了js根據(jù)百度地圖提供經(jīng)緯度計(jì)算兩點(diǎn)距離,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05JavaScript實(shí)現(xiàn)網(wǎng)頁(yè)帶動(dòng)畫返回頂部的方法詳解
這篇文章主要為大家詳細(xì)介紹了如何利用JavaScript實(shí)現(xiàn)網(wǎng)頁(yè)帶動(dòng)畫返回頂部的效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-08-08IE8利用自帶的setCapture和releaseCapture解決iframe的拖拽事件方法
最近有個(gè)需求須要實(shí)現(xiàn)左右拖拽功能,頁(yè)面右邊是個(gè)iframe頁(yè)面,在chrome測(cè)試通過(guò)之后,發(fā)現(xiàn)在ie8上面效果不是很理想,查閱相關(guān)資料找到可以使用ie自帶的setCapture和releaseCapture來(lái)解決,需要的朋友可以參考下2016-10-10JavaScript 判斷數(shù)據(jù)類型的4種方法
這篇文章主要介紹了JavaScript 判斷數(shù)據(jù)類型的4種方法,幫助大家更好的理解和學(xué)習(xí)JavaScript,感興趣的朋友可以了解下2020-09-09setTimeout()遞歸調(diào)用不加引號(hào)出錯(cuò)的解決方法
用了setTimeout()想實(shí)現(xiàn)遞歸調(diào)用,如果第一個(gè)參數(shù)不加引號(hào)的話,就會(huì)出錯(cuò),下面與大家分享下該如何解決2014-09-09