HarmonyOS - 方舟開發(fā)框架ArkUI基于JSAPI實(shí)現(xiàn)五子棋游戲
??想了解更多內(nèi)容,請(qǐng)?jiān)L問:??
??51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)??
前言
最近逛社區(qū)發(fā)現(xiàn)已經(jīng)有童鞋實(shí)現(xiàn)了java版的五子棋了,作為前端開發(fā)人員,怎能沒有js版的五子棋呢,所以趕緊擼起來。
效果展示
實(shí)現(xiàn)過程
一、 繪制棋盤
首先我們使用css繪制棋盤,繪制一個(gè)14*14的正方形格子棋盤,但是需要注意,因?yàn)槲覀兟渥邮锹湓谒膫€(gè)格子之間的交界點(diǎn)上的,而不是落在格子里的,所以怎辦呢?我們可以先繪制一個(gè)15*15的輔助正方形格子,然后再在其中間繪制一個(gè)14*14,這樣落棋在15*15的格子里,而在14*14的格子里就可以看到落棋是在交界點(diǎn)里。
首先繪制一個(gè)15*15的正方形格子。
2. 然后再在其中間繪制一個(gè)14*14的正方形格子,這樣的話,棋子就繪制在15*15的格子里,而在14*14的棋盤里就顯示是在格子交界點(diǎn)上了。
最后把15*15的邊距去掉,就得到一個(gè)正常的14*14的棋盤了,怎樣是不是很漂亮。
做過前端開發(fā)的同學(xué)知道其實(shí)不需要這么麻煩的,直接繪制一個(gè)14*14的格子就可以了,可以使用css的::before和::after選擇器來繪制格子線條。一開始也想用這么這樣處理的,但是發(fā)現(xiàn)在目前好像還沒集成這兩個(gè)選擇器進(jìn)來,這個(gè)后續(xù)估計(jì)會(huì)更新,敬請(qǐng)期待。
二、實(shí)現(xiàn)落棋功能
首先我們?cè)赿ata聲明一個(gè)arr為15*15的空數(shù)組,也就是長(zhǎng)度為225的空數(shù)組。數(shù)組值只能更新為:
- 1:存放黑棋。
- -1:存放白棋。
在標(biāo)簽里定義兩個(gè)class來繪制黑棋和白棋。
<div
class="li{{item == '1' ? 'black' : ''}} {{item == '-1' ? 'white': ''}}"
for="{{(index,item) in arr}}"
tid="item"
onclick="play(index)"
></div>
在點(diǎn)擊play落棋時(shí),傳入當(dāng)前落棋的位置。
play(e){
// 針對(duì)數(shù)組內(nèi)的數(shù)據(jù)修改,請(qǐng)使用splice方法生效數(shù)據(jù)綁定變更
this.arr.splice(e,1,'1');
}
上面代碼傳入1,則點(diǎn)擊顯示黑棋,看看效果怎樣。
當(dāng)然到這里還不行,需要做交換走棋,黑棋走完,到白棋走,并且走過的位置不允許再走棋。
在data定義holder為當(dāng)前持棋者:
- 1:存放黑棋,默認(rèn)持黑棋先走。
- -1:存放白棋。
play(e){
if(this.arr[e] == '1' || this.arr[e] == '-1'){
console.log('該處已經(jīng)有棋了');
return false;
}
// 針對(duì)數(shù)組內(nèi)的數(shù)據(jù)修改,請(qǐng)使用splice方法生效數(shù)據(jù)綁定變更
this.arr.splice(e,1,this.holder);
// 交換走棋
this.holder = this.holder == '1' ? '-1' : '1';
},
三、計(jì)算贏棋方式
我們都知道要贏棋就得同色5顆棋子連成一條線,包括橫向,豎向,斜向,斜向左邊和斜向右邊四種方式。那么我們就要把這幾種方式拆分出來一一計(jì)算統(tǒng)計(jì)。
通過上面的序號(hào),我們不難發(fā)現(xiàn)幾個(gè)規(guī)律。
1、橫向贏棋方式
橫向贏棋方式是五個(gè)棋子每?jī)蓛上嗖钜粋€(gè)數(shù)值,所以每相鄰棋子就是一個(gè)+1和-1的過程。
2、豎向贏棋方式
豎向贏棋方式上下連成一排,我們知道一行只有15個(gè)格子,每個(gè)棋子都相差15數(shù)值,所以每相鄰棋子之間都是+15和-15的過程。
3、左斜向贏棋
左斜方向通過觀察不難發(fā)現(xiàn)每?jī)蓛善遄又g相差+14和-14。
4、右斜向贏棋
右邊斜方向也可以看出每相鄰棋子之間相差+16和16。
四、實(shí)現(xiàn)贏棋計(jì)算
通過上面一比較,是不是瞬間就覺得其實(shí)沒那么難了呢,我們只要計(jì)算好每次落棋的序號(hào)和之前落棋的序號(hào)進(jìn)行一對(duì)比,只要滿足條件的五個(gè)棋子,就贏棋了。
實(shí)現(xiàn)思路: 以黑棋、橫向?yàn)槔?,通過遞歸算法,通過計(jì)算+1 || -1是否都有黑棋的記錄,有則記錄累計(jì)一次,每次計(jì)算完成,則去判斷當(dāng)前累計(jì)次數(shù)是否等于5,如果不是,則還沒有贏,如果為5次,則說明贏棋了。
實(shí)現(xiàn)代碼如下:
//id: 當(dāng)前棋子的序號(hào) d: 計(jì)算方式,比如橫向是 +1 和 -1,arr是累計(jì)下來的序號(hào)結(jié)果。
compute(id,d,arr){
id = parseInt(id);
if(this.arr[id + d] && this.arr[id + d] == this.holder){
arr.push(id);
this.compute(id + d, d, arr);
} else{
arr.push(id);
}
},
判斷是否贏棋的方法:
// 判斷是否贏了
getResult(arr){
if(arr.length > 5){
console.log(this.holder + '贏棋'); //this.holder是定義的當(dāng)前下棋的一方
// 累計(jì)清0
arr.length = 0;
} else {
// 累計(jì)清0
arr.length = 0;
}
},
我們?cè)诿看吸c(diǎn)擊下棋的時(shí)候,都調(diào)用一次統(tǒng)計(jì)累計(jì)次數(shù)方法和計(jì)算贏棋的方法。
// 橫向贏方法
this.compute(e, 1, this.arr1); //arr1是定義好的累計(jì)次數(shù)多數(shù)組
this.compute(e, -1, this.arr1);
this.getResult(this.arr1);
結(jié)合上面計(jì)算方式,我們其他的贏棋方式一樣可以這樣統(tǒng)計(jì)來計(jì)算。
// 點(diǎn)擊下棋方法
play(e){
if(this.isEnd) return;
if(this.arr[e] == '1' || this.arr[e] == '-1'){
console.log('該處已經(jīng)有棋了');
return false;
}
// 針對(duì)數(shù)組內(nèi)的數(shù)據(jù)修改,請(qǐng)使用splice方法生效數(shù)據(jù)綁定變更
this.arr.splice(e,1,this.holder);
// 橫向贏方法
this.compute(e, 1, this.arr1);
this.compute(e, -1, this.arr1);
this.getResult(this.arr1);
// 豎向贏方法
this.compute(e, 15, this.arr1);
this.compute(e, -15, this.arr1);
this.getResult(this.arr1);
//右斜贏方法
this.compute(e, 14, this.arr1);
this.compute(e, -14, this.arr1);
this.getResult(this.arr1);
// 左斜贏方法
this.compute(e, 16, this.arr1);
this.compute(e, -16, this.arr1);
this.getResult(this.arr1);
// 交換走棋
this.holder = this.holder == '1' ? '-1' : '1';
下面看看效果。
到這里結(jié)束了嗎?不,還沒結(jié)束,這里還存在一些bug問題,比如說我們橫向的時(shí)候是通過計(jì)算兩棋子之間是否存在+1和-1的關(guān)系,但是如果兩個(gè)棋子是14,15呢?這時(shí)候是已經(jīng)換行了,顯然是不能成立的,但是計(jì)算結(jié)果這種方式是成立的。所以我們要解決掉這個(gè)問題,包括斜向。
五、優(yōu)化計(jì)算方法
其實(shí)無非兩種結(jié)果,一種就是換行了,+1的時(shí)候換行到第一列數(shù)值了,-1的時(shí)候換行到最后一列數(shù)值了,那么我們把第一列和最后一列單獨(dú)拉出來,進(jìn)行比較。
- 是否在+1、-14,+16的數(shù)值是否在第一列存在,如果存在就不進(jìn)行累計(jì)。
- 是否在-1、+14、-16的數(shù)值是否在最后一列存在,如果存在就不進(jìn)行累計(jì)。
- 這里為什么沒有+15和-15呢,因?yàn)樨Q向不存在這個(gè)問題。
下面我們來用代碼實(shí)現(xiàn)。
// id: 為原id+d, d: 為計(jì)算方式。
scree(id,d){
if((d == 1 && this.colOne.indexOf(id) > -1)
|| (d == -1 && this.colEnd.indexOf(id) > -1)
|| (d == 14 && this.colEnd.indexOf(id) > -1)
|| (d == -14 && this.colOne.indexOf(id) > -1)
|| (d == 16 && this.colOne.indexOf(id) > -1)
|| (d == -16 && this.colEnd.indexOf(id) > -1)){
return false;
}
return true;
},
最后,我們?cè)谟?jì)算判斷的時(shí)候加上這個(gè)判斷條件即可 this.scree(id+d,d)。
compute(id,d,arr){
id = parseInt(id);
if(this.arr[id + d] && this.arr[id + d] == this.holder && this.scree(id+d,d)){
arr.push(id);
this.compute(id + d, d, arr);
} else{
arr.push(id);
}
},
最終的效果
源碼地址:
https://gitee.com/yango520/gobang
總結(jié)
該方法是使用div+css+js實(shí)現(xiàn)的雙人對(duì)戰(zhàn)游戲,在使用css的時(shí)候發(fā)現(xiàn)相比web端的屬性,還是少了很多,比如繪制棋盤的時(shí)候想用::before和::after選擇器來繪制,但是發(fā)現(xiàn)當(dāng)前還沒有這個(gè)屬性,還有想繪制一個(gè)好看有弧度高光的棋子,想使用內(nèi)陰影實(shí)現(xiàn),但是目前也還并不支持內(nèi)陰影。不過相信后續(xù)會(huì)更新,這樣web前端開發(fā)上手HarmonyOS JSAPI就容易多了。
??想了解更多內(nèi)容,請(qǐng)?jiān)L問:??
??51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)??