📄 gobang.java
字号:
import java.util.Date;
import java.util.Random;
import java.util.concurrent.*;
import javax.swing.JOptionPane;
public final class Gobang {
public static final int NONE = 0,//无子
BLACK = 1, //黑子
WHITE = -1,//白子
SIZE = 15,
HUM_VS_AI = 0,
AI_VS_HUM = 1,
EAZY = 2,
HAND = 4,
WANG = 0,//横方向
SHAFT = 1,//竖
R_RAMP = 2,//右斜
L_RAMP = 3;//左斜
public static final int FIVE = 10000,//五连的分数
L_FOUR = 2000,//活四
D_FOUR = 1200,//冲四
L_THREE = 800,//活三
D_THREE = 180,//冲三
L_TWO = 80,//活二
D_TWO = 20;//冲二
private int model;
private int aiSide,humSide;
private int[][] tempB;//棋盘数组
private int[] rows;//记录行
private int[] cols;//记录列
private int level;//级别
private int stepNum;//步数
private int winner;//赢家
private int minRow,maxRow,minCol,maxCol;//控制搜索范围
private boolean oneRoundisEnd;//一轮是否结束
private Game frame;
public Gobang(Game f, int[][] b ,int m, int l)
{
frame = f;
b = new int[SIZE][SIZE];
model = m;
level = l;
winner = NONE;
stepNum = 0;
rows = new int[SIZE*SIZE];
cols = new int[SIZE*SIZE];
tempB = new int[SIZE][SIZE];
for(int r = 0; r<SIZE; r++)
for(int c = 0; c<SIZE; c++)
tempB[r][c] = b[r][c];
if(model == HUM_VS_AI)
{
humSide = BLACK;
aiSide = WHITE;
frame.rep(SIZE,SIZE,tempB);
}
else if(model == AI_VS_HUM)//若电脑下,第一步天元
{
humSide = WHITE;
aiSide = BLACK;
step(7,7,aiSide);
}
oneRoundisEnd = true;
}
public void setLevel(int l)
{
level = l;
}
private boolean step(int r,int c,int side)//生成一步棋
{
if(tempB[r][c] == NONE)
{
tempB[r][c] = side;
rows[stepNum] = r;
cols[stepNum] = c;
frame.rep(r,c,tempB);
stepNum++;
win(r,c,side);
if(stepNum == 1)//计算范围
{
minRow = r-level-1;
maxRow = r+level+1;
minCol = c-level-1;
maxCol = c+level+1;
}
else
{
if(r-level-1<minRow) minRow = Math.max(r-level-1,0);
if(r+level+1>maxRow) maxRow = Math.min(r+level+1,SIZE-1);
if(c-level-1<minCol) minCol = Math.max(c-level-1,0);
if(c+level+1>maxCol) maxCol = Math.min(c+level+1,SIZE-1);
}
return true;
}
else
return false;
}
public void back()//悔棋
{
if(stepNum >1)
{
oneRoundisEnd = true;
winner = NONE;
stepNum--;
tempB[rows[stepNum]][cols[stepNum]] = NONE;
stepNum--;
tempB[rows[stepNum]][cols[stepNum]] = NONE;
frame.rep(rows[stepNum-1],cols[stepNum-1],tempB);
}
}
private boolean win(int r,int c,int side)//判断是否胜利
{
if( score(side,r,c,WANG)==FIVE||
score(side,r,c,SHAFT)==FIVE||
score(side,r,c,L_RAMP)==FIVE||
score(side,r,c,R_RAMP)==FIVE){
winner = side;
String s;
if(side == BLACK)
s = "黑方胜";
else
s = "白方胜";
JOptionPane.showMessageDialog(frame,
s, "结束",
JOptionPane.INFORMATION_MESSAGE);
return true;
}
return false;
}
private void aiPlay(int d)//电脑下,用线程是因为防止与panel的重绘冲突
{
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new AI());
}
private boolean humPlay(int row,int col)//人下
{
if(step(row,col,humSide)){
oneRoundisEnd = false;
return true;
}
else
return false;
}
public void oneRound(int r,int c)//人机下一轮
{
if(oneRoundisEnd && winner==NONE)
if(humPlay(r,c) && winner==NONE)
aiPlay(level);
}
private int score(int side,int r,int c,int direction)//返回一个方向的棋形
{
int num = 1,//棋形
m = 1,n = 1;
final int ltag = 10,rtag = 100,//两个tag为两端死活标志,为方便switch使用(提高效率)为整型
a,b;
switch(direction)
{
case WANG : a = 0; b = 1; break;
case SHAFT : a = 1; b = 0; break;
case R_RAMP : a = 1; b = 1; break;
case L_RAMP : a = 1; b = -1; break;
default : a = 0; b = 0;
}
for(m = 1; m < 5; m++)
{
int row = r-a*m, col = c-b*m;
if(row<0||col>=SIZE||col<0){
num = num+ltag;//若为死num加上标志,下类同
break;
}
int temp = tempB[row][col];
if(temp == side)
num++;
else if(temp == NONE)
break;
else{
num = num+ltag;
break;
}
}
for(n = 1; n < 5; n++)
{
int row = r+a*n, col = c+b*n;
if(row>=SIZE||col>=SIZE||col<0){
num = num+rtag;
break;
}
int temp = tempB[row][col];
if(temp == side)
num++;
else if(temp == NONE)
break;
else{
num = num+rtag;
break;
}
}
int row,col;
switch(num)
{
case 1 :return 0;
case 11 :return 0;
case 101:return 0;
case 111:return 0;
case 2 :
m++;
row = r-a*m;
col = c-b*m;
if(row>=0&&col>=0&&col<SIZE)
if(tempB[row][col]!=-side)
return L_TWO;
n++;
row = r+a*n;
col = c+b*n;
if(row<SIZE&&col>=0&&col<SIZE)
if(tempB[row][col]!=-side)
return L_TWO;
return 0;
case 12 :
n=n+2;
row = r+a*n;
col = c+b*n;
if(row<SIZE&&col>=0&&col<SIZE)
if(tempB[row][col]!=-side&&tempB[row-a][col-b]!=-side)
return D_TWO;
return 0;
case 102:
m=m+2;
row = r-a*m;
col = c-b*m;
if(row>=0&&col>=0&&col<SIZE)
if(tempB[row][col]!=-side&&tempB[row+a][col+b]!=-side)
return D_TWO;
return 0;
case 112:return 0;
case 3 :return L_THREE;
case 13:
n++;
row = r+a*n;
col = c+b*n;
if(row<SIZE&&col>=0&&col<SIZE)
if(tempB[row][col]!=-side)
return D_THREE;
return 0;
case 103:
m++;
row = r-a*m;
col = c-b*m;
if(row>=0&&col>=0&&col<SIZE)
if(tempB[row][col]!=-side)
return D_THREE;
return 0;
case 113:return 0;
case 4 :return L_FOUR;
case 14 :return D_FOUR;
case 104:return D_FOUR;
case 114:return 0;
default :return FIVE;
}
}
final class AI implements Runnable//ai线程类
{
private int aiR,aiC;//记录电脑所下的位置
public final int INFINITY = 10000000;
private void play(int d)
{
if(stepNum == 1){//第一步在人下周围随机选择
Random r = new Random(new Date().getTime());
int row = 0,
col = 0,
humR = rows[0],
humC = cols[0];
do
{
switch(r.nextInt(8))
{
case 0: row = humR+1; col = humC+1; break;
case 1: row = humR+1; col = humC; break;
case 2: row = humR+1; col = humC-1; break;
case 3: row = humR ; col = humC+1; break;
case 4: row = humR ; col = humC-1; break;
case 5: row = humR-1; col = humC+1; break;
case 6: row = humR-1; col = humC ; break;
case 7: row = humR-1; col = humC-1; break;
}
}while(!step(row,col,aiSide));
}
else if(!must()){//判断有没有必须应的着,若没,进行搜索
search(d,aiSide,-INFINITY,INFINITY);
step(aiR,aiC,aiSide);
}
oneRoundisEnd = true;
}
private int search(int d,int side,int alpha, int beta)
{//alpha beta搜索
if(d <= 0)
return evlation();
for (int row = minRow; row <= maxRow; row++)
for (int col = minCol; col <= maxCol; col++)
{
if(tempB[row][col] == NONE)
{
tempB[row][col] = side;
int v = -search(d-1,-side,-beta,-alpha);
tempB[row][col] = NONE;
if (v >= beta) {
return beta;
}
if (v > alpha) {
if(d == level){
aiR = row;
aiC = col;
}
alpha = v;
}
}
}
return alpha;
}
private boolean must()
{//判断有没有必须应的着,如五连双三之类
int aiR = 0,aiC = 0,aiScore = 0,
humR = 0,humC = 0,humScore = 0;
for (int r = 0; r < SIZE; r++)
for (int c = 0; c < SIZE; c++){
if(tempB[r][c] == NONE){
int ais =score(aiSide,r,c,WANG)+
score(aiSide,r,c,SHAFT)+
score(aiSide,r,c,R_RAMP)+
score(aiSide,r,c,L_RAMP);
int hums = score(humSide,r,c,WANG)+
score(humSide,r,c,SHAFT)+
score(humSide,r,c,R_RAMP)+
score(humSide,r,c,L_RAMP);
if(aiScore < ais){
aiScore = ais;
aiR = r;
aiC = c;
}
if(humScore < hums){
humScore = hums;
humR = r;
humC = c;
}
}
}
if(aiScore>=humScore&&aiScore>=L_THREE*2){
step(aiR,aiC,aiSide);
return true;
}
if(aiScore<humScore&&humScore>=L_THREE*2){
step(humR,humC,aiSide);
return true;
}
return false;
}
private int evlation()//评价函数
{
int s1, s2, s3, s4,score = 0;
for (int r = minRow; r <= maxRow; r++)
for (int c = minCol; c <= maxRow; c++)
if(tempB[r][c] == NONE)
{
s1=score(aiSide,r,c,WANG)-score(-aiSide,r,c,WANG)/2;
s2=score(aiSide,r,c,SHAFT)-score(-aiSide,r,c,SHAFT)/2;
s3=score(aiSide,r,c,R_RAMP)-score(-aiSide,r,c,R_RAMP)/2;
s4=score(aiSide,r,c,L_RAMP)-score(-aiSide,r,c,L_RAMP)/2;
score = score+s1+s2+s3+s4;
}
return score;
}
public void run() {
play(level);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -