1. 人機(jī)對(duì)戰(zhàn)
要增添一個(gè)人機(jī)對(duì)戰(zhàn)的模塊, 最大的難點(diǎn)就是如何讓人機(jī)知道下在什么位置是最好的, 不僅要具備進(jìn)攻的能力, 還需要具備防守的能力.
這里當(dāng)人機(jī)第一次走的時(shí)候, 采用標(biāo)準(zhǔn)開局, 下子在最中間.
當(dāng)玩家走了之后, 人機(jī)就需要去判定下在什么位置合理.
這里采用的是評(píng)分表的方法來計(jì)算落子在每一個(gè)位置的分?jǐn)?shù), 根據(jù)最高分?jǐn)?shù)來進(jìn)行下子.
1.1 演示
1.2 評(píng)分表
分析棋形的幾種情況.
例如, 自己是黑子."_"
代表 沒有子
, "1"
代表 黑子
, "0"
代表 白子
當(dāng)落子只有一顆子的情況
① _ 1 _
② _ 1 0
③ 0 1 _
④ 0 1 0
當(dāng)落子有兩顆子的情況
① _ 1 1 _
② _ 1 1 0
③ 0 1 1 _
④ 0 1 1 0
當(dāng)落子有三顆子的情況
① _ 1 1 1 _
② _ 1 1 1 0
③ 0 1 1 1 _
④ 0 1 1 1 0
當(dāng)落子有四顆子的情況
① _ 1 1 1 1 _
② _ 1 1 1 1 0
③ 0 1 1 1 1 _
④ 0 1 1 1 1 0
當(dāng)落子有五顆子的情況
① _ 1 1 1 1 1 _
② _ 1 1 1 1 1 0
③ 0 1 1 1 1 1 _
④ 0 1 1 1 1 1 0
這里大概的情況分為這幾種, 分別對(duì)這幾種情況進(jìn)行一個(gè)分?jǐn)?shù)的設(shè)定, 讓機(jī)器人根據(jù)分?jǐn)?shù)的高低優(yōu)先去處理某種情況.
這里設(shè)計(jì)一種分?jǐn)?shù)表
一子情況
二子情況
三子情況
四子情況
五子情況
1.3 算法思路
使用暴力搜索的方法, 將棋盤中每個(gè)空格的子, 當(dāng)下子的時(shí)候, 去判定下子之后, 橫向得分情況, 豎向得分情況, 左斜得分情況, 右斜的得分情況.
例如, 下子是黑子.
?
橫向, 去看左邊有多少個(gè)黑子, 多少白子, 去看右邊有多少個(gè)黑子, 多少白子. 然后根據(jù)評(píng)分表, 算得分?jǐn)?shù).
?
縱向, 去看上方有多少黑子, 多少白子, 再去下方看有多少個(gè)黑子, 多少白子, 然后根據(jù)評(píng)分表, 算得分?jǐn)?shù).
?
左斜, 去左下方看有多少黑子, 多少白子, 再去右上方看有多少黑子, 多少白子, 然后根據(jù)評(píng)分表, 算得分?jǐn)?shù).
?
右斜. 去左上方看有多少黑子,多少白子, 再去右下方看有多少黑子, 多少白子, 然后根據(jù)評(píng)分表, 算得分?jǐn)?shù).
將四個(gè)方向的得分加起來, 算得分?jǐn)?shù), 進(jìn)行下子.
這里這種算法, 只具備了進(jìn)攻, 不具備防守的能力. 要想人機(jī)下棋具備防守的能力, 還需要讓人機(jī)對(duì)玩家落子的分?jǐn)?shù)進(jìn)行評(píng)估, 如果玩家落子得分更高, 就需要考慮去防守了.
這里就讓, 對(duì)每個(gè)位置, 機(jī)器人落子, 和玩家落子, 算得機(jī)器人落子的得分, 和玩家落子的得分, 對(duì)分?jǐn)?shù)進(jìn)行相加, 然后再去比較, 當(dāng)前是最大的得分情況, 就去當(dāng)前位置落子.
這里進(jìn)行測(cè)試的時(shí)候, 發(fā)現(xiàn)出現(xiàn)四子的時(shí)候, 會(huì)出現(xiàn)不進(jìn)攻 或者不防守的情況. 所以在判定的時(shí)候, 如果出現(xiàn)了五子連珠的情況, 首先進(jìn)攻. 如果對(duì)方有四子, 自己沒法五子, 首先防守.
1.4 具體代碼
1.4.1 評(píng)分表方法
根據(jù)評(píng)分表來分配分?jǐn)?shù), my表示我下的棋子, his表示他下的棋子
public int score(int my,int his){
if(my > 5) return 200000;
if(my == 5 && his == 0) return 200000;
if(my == 5 && his == 1) return 200000;
if(my == 5 && his == 2) return 200000;
if(my == 4 && his == 1) return 3000;
if(my == 4 && his == 0) return 50000;
if(my == 4 && his == 2) return 1000;
if(my == 3 && his == 0) return 3000;
if(my == 3 && his == 1) return 1000;
if(my == 3 && his == 2) return 500;
if(my == 2 && his == 0) return 500;
if(my == 2 && his == 1) return 200;
if(my == 2 && his == 2) return 100;
if(my == 1 && his == 0) return 100;
if(my == 1 && his == 1) return 50;
if(my == 1 && his == 2) return 30;
return 0;
}
1.4.2 橫向得分方法
算得橫向自己棋子數(shù), 和他的棋子數(shù)
如果遇到空格就不計(jì)算了, 遇到別人的棋子也不計(jì)算了
public int getXScore(int x,int y, int chess){
int my = 1;
int his = 0;
for(int i = x-1; i >= 0; i--){
if(chess == board[i][y]){
my++;
}else if(board[i][y] == 0){
break;
}else{
his++;
break;
}
}
for(int i = x+1; i<board.length; i++) {
if(chess == board[i][y]){
my++;
}else if(board[i][y] == 0){
break;
}else{
his++;
break;
}
}
return score(my,his);
}
1.4.3 縱向得分方法
算得縱向自己棋子數(shù), 和他的棋子數(shù)
如果遇到空格就不計(jì)算了, 遇到別人的棋子也不計(jì)算了
private int getYScore(int x, int y, int chess) {
int my = 1;
int his = 0;
for(int i = y-1; i >= 0; i--){
if(chess == board[x][i]){
my++;
}else if(board[x][i] == 0){
break;
}else{
his++;
break;
}
}
for(int i = y+1; i < board.length; i++){
if(chess == board[x][i]){
my++;
}else if(board[x][i] == 0){
break;
}else{
his++;
break;
}
}
return score(my,his);
}
1.4.4 左斜得分方法
算得左斜向自己棋子數(shù), 和他的棋子數(shù)
如果遇到空格就不計(jì)算了, 遇到別人的棋子也不計(jì)算了
private int getSkewScore2(int x, int y, int chess) {
int my = 1;
int his = 0;
for(int i = x+1,j=y-1; i<board.length && j >=0; i++,j--){
if(chess == board[i][j]){
my++;
}else if(board[i][j] == 0){
break;
}else{
his++;
break;
}
}
for(int i = x-1,j=y+1; i>=0 && j<board.length; i--,j++){
if(chess == board[i][j]){
my++;
}else if(board[i][j] == 0){
break;
}else{
his++;
break;
}
}
return score(my,his);
}
1.4.5 右斜得分方法
算得右斜向自己棋子數(shù), 和他的棋子數(shù)
如果遇到空格就不計(jì)算了, 遇到別人的棋子也不計(jì)算了文章來源:http://www.zghlxwxcb.cn/news/detail-451679.html
private int getSkewScore1(int x, int y, int chess) {
int my = 1;
int his = 0;
for(int i = x-1,j =y-1; i >=0 && j>=0; i--,j--){
if(chess == board[i][j]){
my++;
}else if(board[i][j] == 0){
break;
}else{
his++;
break;
}
}
for(int i = x+1,j=y+1; j<board.length && i < board.length; i++,j++){
if(chess == board[i][j]){
my++;
}else if(board[i][j] == 0){
break;
}else{
his++;
break;
}
}
return score(my,his);
}
1.4.6 落子總得分方法
這里如果自己下的子可以優(yōu)先五子連珠就直接下棋.
如果沒有這種情況, 再去判定是否他可以五子連珠, 如果有直接堵住
其他就計(jì)算總分?jǐn)?shù)文章來源地址http://www.zghlxwxcb.cn/news/detail-451679.html
public int getScore(int x,int y) {
int numX1 = getXScore(x,y,1);
int numX2 = getXScore(x,y,2);
int numY1 = getYScore(x,y,1);
int numY2 = getYScore(x,y,2);
int skew1 = getSkewScore1(x,y,1);
int skew2 = getSkewScore1(x,y,2);
int skew3 = getSkewScore2(x,y,1);
int skew4 = getSkewScore2(x,y,2);
if(numX2 >= 200000 || numY2 >= 200000 || skew2 >= 200000 || skew4 >= 200000) {
return Integer.MAX_VALUE;
}
if(numX1 >= 200000 || numY1 >= 200000 || skew1 >= 200000 || skew3 >= 200000){
return Integer.MAX_VALUE;
}
int xScore = getXScore(x,y,1)+getXScore(x,y,2);
int yScore = getYScore(x,y,1)+getYScore(x,y,2);
int skewScore1 = getSkewScore1(x,y,1)+getSkewScore1(x,y,2);
int skewScore2 = getSkewScore2(x,y,1)+getSkewScore2(x,y,2);
return xScore + yScore + skewScore1 + skewScore2;
}
1.4.7 確認(rèn)落子位置的方法
public int[] concluate() {
int[] res = new int[2];
int max = 0;
for(int i = 0; i < Constant.ROW; i++) {
for(int j = 0; j < Constant.COL; j++) {
if(board[i][j] != 0) {
continue;
}
int num = getScore(i,j);
if(num == 200000){
res[0] = i;
res[1] = j;
return res;
}
if(num > max) {
max = num;
res[0] = i;
res[1] = j;
}
}
}
return res;
}
到了這里,關(guān)于在線五子棋對(duì)戰(zhàn) --- 人機(jī)對(duì)戰(zhàn)的實(shí)現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!