Java實(shí)現(xiàn)在線五子棋對戰(zhàn)游戲(人機(jī)對戰(zhàn))
1. 人機(jī)對戰(zhàn)
要增添一個人機(jī)對戰(zhàn)的模塊, 最大的難點(diǎn)就是如何讓人機(jī)知道下在什么位置是最好的, 不僅要具備進(jìn)攻的能力, 還需要具備防守的能力.
這里當(dāng)人機(jī)第一次走的時候, 采用標(biāo)準(zhǔn)開局, 下子在最中間.
當(dāng)玩家走了之后, 人機(jī)就需要去判定下在什么位置合理.
這里采用的是評分表的方法來計(jì)算落子在每一個位置的分?jǐn)?shù), 根據(jù)最高分?jǐn)?shù)來進(jìn)行下子.
1.1 演示
1.2 評分表
分析棋形的幾種情況.
例如, 自己是黑子.
"_" 代表 沒有子, "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
這里大概的情況分為這幾種, 分別對這幾種情況進(jìn)行一個分?jǐn)?shù)的設(shè)定, 讓機(jī)器人根據(jù)分?jǐn)?shù)的高低優(yōu)先去處理某種情況.
這里設(shè)計(jì)一種分?jǐn)?shù)表
一子情況
二子情況
三子情況
四子情況
五子情況
1.3 算法思路
使用暴力搜索的方法, 將棋盤中每個空格的子, 當(dāng)下子的時候, 去判定下子之后, 橫向得分情況, 豎向得分情況, 左斜得分情況, 右斜的得分情況.
例如, 下子是黑子.
- 橫向, 去看左邊有多少個黑子, 多少白子, 去看右邊有多少個黑子, 多少白子. 然后根據(jù)評分表, 算得分?jǐn)?shù).
- 縱向, 去看上方有多少黑子, 多少白子, 再去下方看有多少個黑子, 多少白子, 然后根據(jù)評分表, 算得分?jǐn)?shù).
- 左斜, 去左下方看有多少黑子, 多少白子, 再去右上方看有多少黑子, 多少白子, 然后根據(jù)評分表, 算得分?jǐn)?shù).
- 右斜. 去左上方看有多少黑子,多少白子, 再去右下方看有多少黑子, 多少白子, 然后根據(jù)評分表, 算得分?jǐn)?shù).
將四個方向的得分加起來, 算得分?jǐn)?shù), 進(jìn)行下子.
這里這種算法, 只具備了進(jìn)攻, 不具備防守的能力. 要想人機(jī)下棋具備防守的能力, 還需要讓人機(jī)對玩家落子的分?jǐn)?shù)進(jìn)行評估, 如果玩家落子得分更高, 就需要考慮去防守了.
這里就讓, 對每個位置, 機(jī)器人落子, 和玩家落子, 算得機(jī)器人落子的得分, 和玩家落子的得分, 對分?jǐn)?shù)進(jìn)行相加, 然后再去比較, 當(dāng)前是最大的得分情況, 就去當(dāng)前位置落子.
這里進(jìn)行測試的時候, 發(fā)現(xiàn)出現(xiàn)四子的時候, 會出現(xiàn)不進(jìn)攻 或者不防守的情況. 所以在判定的時候, 如果出現(xiàn)了五子連珠的情況, 首先進(jìn)攻. 如果對方有四子, 自己沒法五子, 首先防守.
1.4 具體代碼
1.4.1 評分表方法
根據(jù)評分表來分配分?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ì)算了
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ù)
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)于Java實(shí)現(xiàn)在線五子棋對戰(zhàn)游戲(人機(jī)對戰(zhàn))的文章就介紹到這了,更多相關(guān)Java在線五子棋游戲內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java實(shí)現(xiàn)圖片水平和垂直翻轉(zhuǎn)效果
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)圖片水平和垂直翻轉(zhuǎn)效果,圖片旋轉(zhuǎn)的靈活運(yùn)用,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-01-01面試題:java中為什么foreach中不允許對元素進(jìn)行add和remove
讀者遇到了一個比較經(jīng)典的面試題,也就是標(biāo)題上說的,為什么 foreach 中不允許對元素進(jìn)行 add 和 remove,本文就詳細(xì)的介紹一下,感興趣的可以了解一下2021-10-10解決在微服務(wù)環(huán)境下遠(yuǎn)程調(diào)用feign和異步線程存在請求數(shù)據(jù)丟失問題
這篇文章主要介紹了解決在微服務(wù)環(huán)境下遠(yuǎn)程調(diào)用feign和異步線程存在請求數(shù)據(jù)丟失問題,主要包括無異步線程得情況下feign遠(yuǎn)程調(diào)用,異步情況下丟失上下文問題,需要的朋友可以參考下2022-05-05使用Spring Boot實(shí)現(xiàn)操作數(shù)據(jù)庫的接口的過程
本文給大家分享使用Spring Boot實(shí)現(xiàn)操作數(shù)據(jù)庫的接口的過程,包括springboot原理解析及實(shí)例代碼詳解,感興趣的朋友跟隨小編一起看看吧2021-07-07