一、算法思想
1、搜索树
甲乙两人下棋,甲有很多种落子方式,乙也有多种应对走法,如果把所有的走法列出来,自然就构成了一棵树,即为搜索树,也称博弈树。树的根结点为先手的第一步走法,下面的走法构成了树的子结点,直至棋局结束。显然,如果棋盘足够大,子结点数会以几何级数上升,而我们的任务是从这些子结点中寻找一个对己方最有利的结点,从而得到棋局的最佳走法。
估值函数
估值函数通常是为了评价棋型的状态,根据实现定义的一个棋局估值表,对双方的棋局形态进行计算,根据得到的估值来判断应该采用的走法。棋局估值表是根据当前的棋局形势,定义一个分值来反映其优势程度,来对整个棋局形势进行评价。
3、极大极小搜索
极大极小搜索算法就是在博弈树在寻找最优解的一个过程,这主要是一个对各个子结点进行比较取舍的过程,定义一个估值函数F(n)来分别计算各个终结点的分值,通过双方的分值来对棋局形势进行分析判断。还是以甲乙两人下棋为例,甲为max,乙为min。当甲走棋时,自然在博弈树中寻找最大点的走法,轮到乙时,则寻找最小点的走法,如此反复,这就是一个极大极小搜索过程,以此来寻找对机器的最佳走法。
4、剪枝算法
αβ剪枝算法简单来说,就是在搜索过程中减少一定的冗余现象,如已经找到极大值,执行该走法就可以获胜,则无须再往下进行搜索比较,此过程即为剪枝。对于极大的MAX结点,称为α剪枝;反之为β剪枝。具体规则可以简单描述如下:
α剪枝:对于极大值层结点的α值如果不小于它的任一祖先极小值层结点的β值,即α(后续层)≥β(祖先层),则可中止该极大值层中这个MAX节点以下的搜索过程,这个MAX节点最终的倒推值就确定为这个α值。
β剪枝:对于极小值结点层的β值如果不大于它任一祖先极大值层结点的α值,即α(祖先层)≥β(后续层),则可中止对该极小值层中这个MIN节点以下结点的搜索,这个MIN节点最终的倒推值就确定为这个β值。
二、详细设计
2.1总体设计
在算法设计中,比较重要的是评价函数的求法,因为评价函数是在中级或者高级难度的游戏模式中,计算机选择落棋位置的重要依据。
在五子棋游戏中,棋型很重要,其中有连五(表示已经有五子连线),活四(四子连线并且两边都没有被堵住),眠四(四子连线有一边被堵住),活三(三子连线两边都没有被堵上),眠三(三子连线,有一边被堵上),活二,眠二依次类推,其中还有一些其他的情况如:EUUOUU,OUUOUUO等,其中E表示有冲突(边界或者对方的棋子),U表示已经连线的棋子,O表示空白的位置,我们对这些很有可能连线的棋型,按照连成五子的概率大小不同定义不同的分值。因为我们求评价函数的作用是选择一个合适的地方落子,所以求评价值是针对空位置。假如我要求某位置黑子的评价值,就是试验性的将这个位置放上黑子,在横向,纵向,两个斜线方向分别以这个位置(x,y)为中心,向两边分别截取4位(因为第五位和此位置无关)一共截取9位,再看棋型,得到分数,再将这四个方向的分数相加。就为此位置的评价值。具体的截取方法,匹配方法与计算的方法我在详细设计部分会很清楚的表达。这部分用方法public int calculateScore(final int x,final int y,int color)实现,x,y为横坐标,纵坐标,color为棋子的颜色。返回求得的评价值。
中级难度的下法为,遍历棋盘,找到己方评价函数最高的位置A,再找到对方评价值最高的位置B,假如自己方的分数高于或者等于对方的分数,就将棋子落在A,反之落在位置B。
高级的下法为
整个程序设计的类,属性,方法如下:
1、类fivechess:
public class fivechess extends JFrame implements ActionListener
成员:
JButton back=new JButton(“悔棋”);
JButton start=new JButton(“开始”);
JButton game=new JButton(“中级难度”);
JButton game2=new JButton(“高级难度”);
GameBoard gb=new GameBoard();
JPanel pb=new JPanel();
JPanel pg=new JPanel();
方法:
public fivechess()//构造函数
public void actionPerformed(ActionEvent e)//实现按钮事件
2、类GameBoard:
public class GameBoard extends JPanel implements MouseListener
成员:
public int row=14;//棋盘行数
public int col=14;//棋盘列数
public int length=30;//每个格子的大小
public int edgedis=30;//边距
public int[][] ChessBoard=new int[row+1][col+1];//棋子代表的二维数组,
int chessNum=0;//已经下了的棋子数目
boolean IsBlack=true;//判断哪方下子(黑子先行)
int lastx=-1,lasty=-1; //最后下子的位置
int llastx=-1,llasty=-1; //倒数第二次下的位置,方便悔棋
boolean Win=false;//是否胜利的标志
static final int radius=15;
//棋盘的位置的分值(固定为15x15的棋盘)
方法:
public GameBoard()//构造函数
public void paintComponent(Graphics g)//画棋局
public void mousePressed(MouseEvent e)//鼠标事件
public void computerplayer()//中级下法
public void computerplayerhigher()//高级下法
public int maxMinWithAlphaBetaCut(int chessBoard[][], int whiteOrBlack, int depth, int x,int y, int alpha, int beta)//剪枝算法
public int calculateScore(final int x,final int y,int color)//算分值
public boolean isExit(int x,int y)//此位置有没有棋子
public boolean IsWin()//判断是否已经有五子连线的情况
public int ChessCount(int xChange,int yChange,int color)//计算棋子在xChange和yChange方向上连接的数量(1,0)横向,(0,1)纵向,(1,1)主对角线,(-1,-1)副对角线
2.2 算法设计
这部分只介绍重要的算法,在此程序中重要的算法有三个,评价值的计算,中级难度下法
1.评价值计算
在横向,纵向,两个斜线方向分别以这个位置(x,y)为中心,向两边分别截取4位(因为第五位和此位置无关)一共截取9位,再看棋型,得到分数,再将这四个方向的分数相加。就为此位置的评价值。
首先需要定义棋型,我将棋型用字符串来表示存储在string类型的数组type中,将相应的得分存储在int类型的数组score中。其中E表示有冲突(边界或者对方的棋子),U表示已经连线的棋子,O表示空白的位置。用下标对应
每种棋型的类型,以及棋型的评分合理与否很大程度上反应了智能程度,所以在设置上要多留心,也可以在后续的测试中留意分值的设置是否合理。首先我们需要在棋盘中截取棋型,以指定的坐标(x,y)为中心,在横向,竖向,正斜个,反斜上向两边扩展,定义一temp[4]数组其为string类型,分别用来存放在横向,竖向,正斜,反斜方向截取的棋型。在横向上的截取是保持y坐标不变,设扩展的位数为bite。在x轴左向扩展时坐标的变化为(x-bite,y)所以要确保x-bite>=0,由于棋盘是以0开始的,所以当x小于4时能扩展的位数为bite=4-Math.abs(x-4)。
在往右向扩展时坐标的变化为(x+bite,y)所以要确保x+bite<=14,当在bite小于等于4而x+bite>14时就停止扩展。当在扩展到的位置遇到自己方的棋子有temp[0]=temp[0]+”U”当在扩展位置遇到对方的棋子或者遇到边界则有temp[0]=temp[0]+”C”扩展到的位置的为空位置则有temp[0]=temp[0]+”O”。同理在其他方向也按照这个原则进行扩展生成自己的棋型temp[]。
各个方向扩展的坐标变化如下:
竖向向上(x,y-bite) 竖向向下(x,y+bite)
正斜向上(x-bite,y-bite) 正斜向下(x+bite,y+bite)
反斜向上(x+bite,y-bite) 反斜向下(x-bite,y+bite)
需要注意边界问题。代码实现如下:
///////////////////////////在x轴方向上取////////////////////////////////
if(x-4<0){
int bite=4-Math.abs(x-4);
temp[0]=temp[0]+"C";
while(bite!=0){
if(ChessBoard[x-bite][y]==0){
temp[0]=temp[0]+"O";
}
else if(ChessBoard[x-bite][y]==color){
temp[0]=temp[0]+"U";
}
else {
temp[0]=temp[0]+"C";
}
bite--;
}
}
else {
for(int i=4;i>0;i--){
if(ChessBoard[x-i][y]==0){
temp[0]=temp[0]+"O";
}
else if(ChessBoard[x-i][y]==color){
temp[0]=temp[0]+"U";
}
else {
temp[0]=temp[0]+"C";
}
}
}
for(int i=0;i<=4;i++){
if(x+i>14) {
temp[0]=temp[0]+"C";
break;
}
if(ChessBoard[x+i][y]==0){
temp[0]=temp[0]+"O";
}
else if(ChessBoard[x+i][y]==color){
temp[0]=temp[0]+"U";
}
else {
temp[0]=temp[0]+"C";
}
}
//////////////////在y方向截取////////////////////////////
if(y-4<0){
int bite=4-Math.abs(y-4);
temp[1]=temp[1]+"C";
while(bite!=0){
if(ChessBoard[x][y-bite]==0){
temp[1]=temp[1]+"O";
}
else if(ChessBoard[x][y-bite]==color){
temp[1]=temp[1]+"U";
}
else {
temp[1]=temp[1]+"C";
}
bite--;
}
}
else {
for(int i=4;i>0;i--){
if(ChessBoard[x][y-i]==0){
temp[1]=temp[1]+"O";
}
else if(ChessBoard[x][y-i]==color){
temp[1]=temp[1]+"U";
}
else {
temp[1]=temp[1]+"C";
}
}
}
for(int i=0;i<=4;i++){
if(y+i>14) {
temp[1]=temp[1]+"C";
break;
}
if(ChessBoard[x][y+i]==0){
temp[1]=temp[1]+"O";
}
else if(ChessBoard[x][y+i]==color){
temp[1]=temp[1]+"U";
}
else {
temp[1]=temp[1]+"C";
}
}
//////////////////////在左下,右上方向上//////////////////////////////
if(x-4<0||14-(y+4)<0){
int b=0;
if(x-4<0&&14-(y+4)<0){
b=Math.min(4-Math.abs(x-4),14-y);
}
else if(x-4<0&&y<=10){
b=4-Math.abs(x-4);
}
else if(14-(y+4)<0&&x-4>=0){
b=14-y;
}
temp[2]=temp[2]+"C";
while(b!=0){
if(ChessBoard[x-b][y+b]==0){
temp[2]=temp[2]+"O";
}
else if(ChessBoard[x-b][y+b]==color){
temp[2]=temp[2]+"U";
}
else {
temp[2]=temp[2]+"C";
}
b--;
}
}
else{
for(int i=4;i>0;i--){
if(ChessBoard[x-i][y+i]==0){
temp[2]=temp[2]+"O";
}
else if(ChessBoard[x-i][y+i]==color){
temp[2]=temp[2]+"U";
}
else {
temp[2]=temp[2]+"C";
}
}
}
if(y-4<0||14-(x+4)<0){
int b=0;
if(y-4<0&&14-(x+4)<0){
b=Math.min(4-Math.abs(y-4),14-x);
}
else if(y-4<0&&x<=10){
b=4-Math.abs(y-4);
}
else if(14-(x+4)<0&&y-4>=0){
b=14-x;
}
while(b!=0){
if(ChessBoard[x+b][y-b]==0){
temp[2]=temp[2]+"O";
}
else if(ChessBoard[x+b][y-b]==color){
temp[2]=temp[2]+"U";
}
else {
temp[2]=temp[2]+"C";
}
b--;
}
temp[2]=temp[2]+"C";
}
else{
for(int i=0;i<=4;i++){
if(ChessBoard[x+i][y-i]==0){
temp[2]=temp[2]+"O";
}
else if(ChessBoard[x+i][y-i]==color){
temp[2]=temp[2]+"U";
}
else {
temp[2]=temp[2]+"C";
}
}
}
//////////////////////在左上,右下方向上////////////////////////////////
if(x-4<0||y-4<0){
int bite=0;
if(x-4<0&&y-4<0){
bite=Math.min(4-Math.abs(x-4),4-Math.abs(y-4));
}
else if(x-4<0&&y-4>=0){
bite=4-Math.abs(x-4);
}
if(y-4<0&&x-4>=0){
bite=4-Math.abs(y-4);
}
temp[3]=temp[3]+"C";
while(bite!=0){
if(ChessBoard[x-bite][y-bite]==0){
temp[3]=temp[3]+"O";
}
else if(ChessBoard[x-bite][y-bite]==color){
temp[3]=temp[3]+"U";
}
else {
temp[3]=temp[3]+"C";
}
bite--;
}
}
else {
for(int i=4;i>0;i--){
if(ChessBoard[x-i][y-i]==0){
temp[3]=temp[3]+"O";
}
else if(ChessBoard[x-i][y-i]==color){
temp[3]=temp[3]+"U";
}
else {
temp[3]=temp[3]+"C";
}
}
}
for(int i=0;i<=4;i++){
if(y+i>14||x+i>14) {
temp[3]=temp[3]+"C";
break;
}
if(ChessBoard[x+i][y+i]==0){
temp[3]=temp[3]+"O";
}
else if(ChessBoard[x+i][y+i]==color){
temp[3]=temp[3]+"U";
}
else {
temp[3]=temp[3]+"C";
}
}
截取完之后我们需要计算得分,因为截取到的长度是长于定义的棋型的,所以只要在截取到棋型构成的字符串里面,有已经定义的棋型的子串,那么就算匹配上,该位置的得分加上该棋型对应的分数。匹配引入包:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
调用方法来求得
Pattern p=Pattern.compile(type[j]);
Matcher m=p.matcher(temp[i]);
if(m.find())
因为棋型在type数组里面存储顺序是按分数递减存储的,所以最开始找到的棋型为最好的,在这四个方向上找到最好的就停止寻找,继续找下一个方向的。直到得到四个方向的分数并且相加,就为最终的结果。
代码实现为:
int result=0;
for(int i=0;i<4;i++){
for(int j=0;j<38;j++){
Pattern p=Pattern.compile(type[j]);
Matcher m=p.matcher(temp[i]);
if(m.find()){
result+=score[j];
break;
}
}
}
3.3.2中级下法
中级难度的下法为,遍历棋盘,找到己方评价函数最高的位置A,再找到对方评价值最高的位置B,假如自己方的分数高于或者等于对方的分数,就将棋子落在A,反之落在位置B。
代码实现如下:
public void computerplayer(){
/////////////默认黑棋先行///////////////////////////
int MaxScoreBlack=0;
int MaxScorewhite=0;
int TempScore=0;
int maxXB=0,maxYB=0,maxXW=0,maxYW=0;
int color=2;
llastx=lastx;
llasty=lasty;
///////////////////////算白棋总分,当对方的棋局威胁不大时,自己方就进攻选择得分最高的棋局////////////////
TempScore=0;
for(int i=0;i<15;i++){
for(int j=0;j<15;j++){
if(ChessBoard[i][j]==0){
TempScore=this.calculateScore(i, j,color);
if(TempScore>MaxScorewhite){
MaxScorewhite=TempScore;
maxXW=i;
maxYW=j;
}
}
}
}
/////////////////////////算黑棋总分///////////////////////////////
color=1;
TempScore=0;
for(int i=0;i<15;i++){
for(int j=0;j<15;j++){
if(ChessBoard[i][j]==0){
TempScore=this.calculateScore(i, j,color);
if(TempScore>MaxScoreBlack){
MaxScoreBlack=TempScore;
maxXB=i;
maxYB=j;
}
}
}
}
if(MaxScorewhite>=MaxScoreBlack){
lastx=maxXW;
lasty=maxYW;
}
else {
lastx=maxXB;
lasty=maxYB;
}
System.out.println(MaxScorewhite);
System.out.println(MaxScoreBlack);
ChessBoard[lastx][lasty]=2;
IsBlack=!IsBlack; //换白棋
chessNum++;
return;
}
3、代码源码
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RadialGradientPaint;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class fivechess extends JFrame implements ActionListener{
JButton back=new JButton("悔棋");
JButton start=new JButton("开始");
JButton game=new JButton("中级难度");
JButton game2=new JButton("高级难度");
GameBoard gb=new GameBoard();
JPanel pb=new JPanel();
JPanel pg=new JPanel();
public fivechess(){
pb.add(start);
pb.add(back);
pb.add(game);
pb.add(game2);
setLayout(new BorderLayout());
add(pb,BorderLayout.NORTH);
add(pg);
gb.setOpaque(true);
add(gb);
back.addActionListener(this);
start.addActionListener(this);
game.addActionListener(this);
game2.addActionListener(this);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(526,549);
setLocation(400,100);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
fivechess f=new fivechess();
f.setTitle("五子棋");
f.setVisible(true);
}
public class GameBoard extends JPanel implements MouseListener{
public BufferedImage bgImage=null;//背景图片
public int row=14;//棋盘行数
public int col=14;//棋盘列数
public int length=30;//每个格子的大小
public int edgedis=30;//边距
public int[][] ChessBoard=new int[row+1][col+1];//棋子代表的二维数组,其中0代表没有落子1代表黑子2代表白子
//棋局判断,其中为有可能出现五子连线的类型,并判分,分数d额合理不合理影响了智能程度,*代表了有想相同颜色的棋子,O为空#代表被堵住了
//一共32种棋型
public String[] type={"UUUUU",//胜利
"OUUUUO","UOUUUU",//活四
"OUUUUC","CUUUUO","CUOUUU","CUUUOU","CUUOUU","UUOUUC","UUOUUC","UUUOUC",//眠四
"OOUUUOO","OUUUO",
"COUUUOO","COOUUUO","COUUUOO","OUUUOOC","OOUUUOC","OUUUOOC",//活三和上一个评分差别不大
"OUOUUO","OUUOUO",//活三
"CUUUOO","OOUUUC",
"OUOUUC","CUUOUO","OUUOUC",//眠三
"OOOUUOOO","OOUUOO","OUUO","OOUOUOO","OUOOUO",//活二
"OOOUUC","CUUOOO","OOUOUC","CUOUOO",//眠二
"OOOOUOOOO","OOUOO","OUO"//都为空白
};
public int[] score={10000000, //胜利
900000,850000,//活四
8000,8000,8000,8000,8000,8000,8000,8000,//眠四
7500, 7500, //活三
7200,7200,7200,7200,7200,7200,//活三
5000,5000,
3000,3000,//眠三
2500,2500,2500,//眠三
1000,1000,1000,800,800,
500,500,500,500,
80,50,20,
};
int chessNum=0;//已经下了的棋子数目
boolean IsBlack=true;//判断哪方下子(黑子先行)
int lastx=-1,lasty=-1; //最后下子的位置
int llastx=-1,llasty=-1; //倒数第二次下的位置,方便悔棋
boolean Win=false;//是否胜利的标志
Vector allx=new Vector();
Vector ally=new Vector();
// int[][][]Player=new int[row+1][col+1][2];//最后【】【】【0】表示有没有棋子,【】【】【1】表示评分
//int[][][]Computer=new int[row+1][col+1][2];
//设置棋子半径
static final int radius=15;
//棋盘的位置的分值(固定为15x15的棋盘)
//构造函数
public GameBoard() {
try {
bgImage=ImageIO.read(new File("src/wuziqi.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
this.addMouseListener(this);
//初始化棋盘
for(int i=0;i<row+1;i++){
for(int j=0;j<col+1;j++){
ChessBoard[i][j]=0;
}
}
}
/*public void copyChess(){
for(int i=0;i<15;i++){
for(int j=0;j<15;j++){
if(ChessBoard[i][j]==1){
Player[i][j][0]=1;
}
else if(ChessBoard[i][j]==2){
Computer[i][j][0]=1;
}
}
}
}
*/
//绘制棋盘
public void paintComponent(Graphics g){
super.paintComponent(g);
//g.drawImage(bgImage, 0, 0, row*length+2*edgedis, col*length+2*edgedis, null);
g.drawImage(bgImage, 0, 0, 526, 549, null);
//绘制线条
for(int i=0;i<=row;i++){//横线
g.drawLine(edgedis, edgedis+i*length, col*length+edgedis, edgedis+i*length);
}
for(int j=0;j<=col;j++){//竖线
g.drawLine(edgedis+j*length, edgedis, edgedis+j*length, row*length+edgedis);
}
//绘制棋子
for(int i=0;i<row+1;i++){
for(int j=0;j<col+1;j++){
if(ChessBoard[i][j]!=0){//存在落子
//获取网格交叉点的坐标(在屏幕上的)
int x=i*length+edgedis;
int y=j*length+edgedis;
if(ChessBoard[i][j]==1){//如果落黑子
g.setColor(Color.BLACK);
RadialGradientPaint paint=new RadialGradientPaint(x-radius+25,y-radius+10,20,new float[]{0f,1f},new Color[]{Color.WHITE,Color.BLACK});
((Graphics2D) g).setPaint(paint);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT);
}
else if(ChessBoard[i][j]==2){//如果落白子
g.setColor(Color.WHITE);
RadialGradientPaint paint=new RadialGradientPaint(x-radius+25,y-radius+10,70,new float[]{0f,1f},new Color[]{Color.WHITE,Color.BLACK});
((Graphics2D) g).setPaint(paint);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT);
}
Ellipse2D e = new Ellipse2D.Float(x-radius, y-radius, 30, 30);
((Graphics2D) g).fill(e);
if(i==lastx&&j==lasty){
g.setColor(Color.RED);
g.drawRect(x-radius, y-radius, 30, 30);
}
}
}
}
}
@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
String info="";
String ChessColor=IsBlack?"黑子":"白子";
if(Win){
info=String.format("游戏结束!%s已经取得游戏胜利,请重新开始游戏!", ChessColor);
JOptionPane.showMessageDialog(this, info);
return;
}
if(chessNum==(row+1)*(col+1)){
info="棋盘已满!";
JOptionPane.showMessageDialog(this, info);
return;//不执行任何操作
}
//获得鼠标落点在二维数组的索引
lastx=(e.getX()-edgedis+length/2)/length;
lasty=(e.getY()-edgedis+length/2)/length;
//落点不在棋盘内不能落子
if(lastx<0||lastx>row||lasty<0||lasty>col){
info="落子处超出棋盘范围!";
JOptionPane.showMessageDialog(this, info);
return;
}
//落点已经存在棋子不能落子
if(isExit(lastx,lasty)){
info="该处已有落子!";
JOptionPane.showMessageDialog(this, info);
return;
}
//绘制落子
if(IsBlack)
ChessBoard[lastx][lasty]=1;
else ChessBoard[lastx][lasty]=2;
allx.add(lastx);
ally.add(lasty);
chessNum++;
repaint();
if(IsWin()){
Win=true;
info=String.format("恭喜,%s赢了!", ChessColor);
JOptionPane.showMessageDialog(this, info);
return;
}
computerplayer();
repaint();
//判断胜负
ChessColor=IsBlack?"黑子":"白子";
if(IsWin()){
Win=true;
info=String.format("恭喜,%s赢了!", ChessColor);
JOptionPane.showMessageDialog(this, info);
return;
}
IsBlack=!IsBlack;//换黑棋
}
public void computerplayer(){
/////////////默认黑棋先行///////////////////////////
int MaxScoreBlack=0;
int MaxScorewhite=0;
int TempScore=0;
int maxXB=0,maxYB=0,maxXW=0,maxYW=0;
int color=2;
llastx=lastx;
llasty=lasty;
///////////////////////算白棋总分,当对方的棋局威胁不大时,自己方就进攻选择得分最高的棋局////////////////
TempScore=0;
for(int i=0;i<15;i++){
for(int j=0;j<15;j++){
if(ChessBoard[i][j]==0){
TempScore=this.calculateScore(i, j,color);
if(TempScore>MaxScorewhite){
MaxScorewhite=TempScore;
maxXW=i;
maxYW=j;
}
}
}
}
/////////////////////////算黑棋总分///////////////////////////////
color=1;
TempScore=0;
for(int i=0;i<15;i++){
for(int j=0;j<15;j++){
if(ChessBoard[i][j]==0){
TempScore=this.calculateScore(i, j,color);
if(TempScore>MaxScoreBlack){
MaxScoreBlack=TempScore;
maxXB=i;
maxYB=j;
}
}
}
}
if(MaxScorewhite>=MaxScoreBlack){
lastx=maxXW;
lasty=maxYW;
}
else {
lastx=maxXB;
lasty=maxYB;
}
System.out.println(MaxScorewhite);
System.out.println(MaxScoreBlack);
ChessBoard[lastx][lasty]=2;
allx.add(lastx);
ally.add(lasty);
//System.out.println(ChessBoard[maxX][maxY]);
IsBlack=!IsBlack; //换白棋
chessNum++;
return;
}
public int calculateScore(final int x,final int y,int color){//输入坐标,若有活4,连5直接返回-1,下此位置,否则返回评分
String[] temp=new String [4];
for(int i=0;i<4;i++){
temp[i]="";
}
ChessBoard[x][y]=color;
///////////////////////////在x轴方向上取////////////////////////////////
if(x-4<0){
int bite=4-Math.abs(x-4);
temp[0]=temp[0]+"C";
while(bite!=0){
if(ChessBoard[x-bite][y]==0){
temp[0]=temp[0]+"O";
}
else if(ChessBoard[x-bite][y]==color){
temp[0]=temp[0]+"U";
}
else {
temp[0]=temp[0]+"C";
}
bite--;
}
}
else {
for(int i=4;i>0;i--){
if(ChessBoard[x-i][y]==0){
temp[0]=temp[0]+"O";
}
else if(ChessBoard[x-i][y]==color){
temp[0]=temp[0]+"U";
}
else {
temp[0]=temp[0]+"C";
}
}
}
for(int i=0;i<=4;i++){
if(x+i>14) {
temp[0]=temp[0]+"C";
break;
}
if(ChessBoard[x+i][y]==0){
temp[0]=temp[0]+"O";
}
else if(ChessBoard[x+i][y]==color){
temp[0]=temp[0]+"U";
}
else {
temp[0]=temp[0]+"C";
}
}
//////////////////在y方向截取////////////////////////////
if(y-4<0){
int bite=4-Math.abs(y-4);
temp[1]=temp[1]+"C";
while(bite!=0){
if(ChessBoard[x][y-bite]==0){
temp[1]=temp[1]+"O";
}
else if(ChessBoard[x][y-bite]==color){
temp[1]=temp[1]+"U";
}
else {
temp[1]=temp[1]+"C";
}
bite--;
}
}
else {
for(int i=4;i>0;i--){
if(ChessBoard[x][y-i]==0){
temp[1]=temp[1]+"O";
}
else if(ChessBoard[x][y-i]==color){
temp[1]=temp[1]+"U";
}
else {
temp[1]=temp[1]+"C";
}
}
}
for(int i=0;i<=4;i++){
if(y+i>14) {
temp[1]=temp[1]+"C";
break;
}
if(ChessBoard[x][y+i]==0){
temp[1]=temp[1]+"O";
}
else if(ChessBoard[x][y+i]==color){
temp[1]=temp[1]+"U";
}
else {
temp[1]=temp[1]+"C";
}
}
//////////////////////在左下,右上方向上//////////////////////////////
if(x-4<0||14-(y+4)<0){
int b=0;
if(x-4<0&&14-(y+4)<0){ //两者都小取小的
b=Math.min(4-Math.abs(x-4),14-y);
}
else if(x-4<0&&y<=10){
b=Math.abs(x);
}
else if(y>10&&x-4>=0){
b=14-y;
}
temp[2]=temp[2]+"C";
while(b!=0){
if(ChessBoard[x-b][y+b]==0){
temp[2]=temp[2]+"O";
}
else if(ChessBoard[x-b][y+b]==color){
temp[2]=temp[2]+"U";
}
else {
temp[2]=temp[2]+"C";
}
b--;
}
}
else{
for(int i=4;i>0;i--){
if(ChessBoard[x-i][y+i]==0){
temp[2]=temp[2]+"O";
}
else if(ChessBoard[x-i][y+i]==color){
temp[2]=temp[2]+"U";
}
else {
temp[2]=temp[2]+"C";
}
}
}
if(y-4<0||x>10){
int b=0;
if(y-4<0&&x>10){
b=Math.min(4-Math.abs(y-4),14-x);
}
else if(y-4<0&&x<=10){
b=4-Math.abs(y-4);
}
else if(14-(x+4)<0&&y-4>=0){
b=14-x;
}
/*while(b!=0){
if(ChessBoard[x+b][y-b]==0){
temp[2]=temp[2]+"O";
}
else if(ChessBoard[x+b][y-b]==color){
temp[2]=temp[2]+"U";
}
else {
temp[2]=temp[2]+"C";
}
b--;
}*/
for(int i=0;i<=b;i++){
if(ChessBoard[x+i][y-i]==0){
temp[2]=temp[2]+"O";
}
else if(ChessBoard[x+i][y-i]==color){
temp[2]=temp[2]+"U";
}
else {
temp[2]=temp[2]+"C";
}
}
temp[2]=temp[2]+"C";
}
else{
for(int i=0;i<=4;i++){
if(ChessBoard[x+i][y-i]==0){
temp[2]=temp[2]+"O";
}
else if(ChessBoard[x+i][y-i]==color){
temp[2]=temp[2]+"U";
}
else {
temp[2]=temp[2]+"C";
}
}
}
//////////////////////在左上,右下方向上////////////////////////////////
if(x-4<0||y-4<0){
int bite=0;
if(x-4<0&&y-4<0){
bite=Math.min(4-Math.abs(x-4),4-Math.abs(y-4));
}
else if(x-4<0&&y-4>=0){
bite=4-Math.abs(x-4);
}
if(y-4<0&&x-4>=0){
bite=4-Math.abs(y-4);
}
temp[3]=temp[3]+"C";
//System.out.println(bite);
//System.out.println(x);
//System.out.println(y);
while(bite!=0){
if(ChessBoard[x-bite][y-bite]==0){
temp[3]=temp[3]+"O";
}
else if(ChessBoard[x-bite][y-bite]==color){
temp[3]=temp[3]+"U";
}
else {
temp[3]=temp[3]+"C";
}
bite--;
}
}
else {
for(int i=4;i>0;i--){
if(ChessBoard[x-i][y-i]==0){
temp[3]=temp[3]+"O";
}
else if(ChessBoard[x-i][y-i]==color){
temp[3]=temp[3]+"U";
}
else {
temp[3]=temp[3]+"C";
}
}
}
for(int i=0;i<=4;i++){
if(y+i>14||x+i>14) {
temp[3]=temp[3]+"C";
break;
}
if(ChessBoard[x+i][y+i]==0){
temp[3]=temp[3]+"O";
}
else if(ChessBoard[x+i][y+i]==color){
temp[3]=temp[3]+"U";
}
else {
temp[3]=temp[3]+"C";
}
}
//////////////////////////////求出棋型之后计算分数////////////////////////////
int result=0;
for(int i=0;i<4;i++){
for(int j=0;j<38;j++){
Pattern p=Pattern.compile(type[j]);
Matcher m=p.matcher(temp[i]);
if(m.find()){
result+=score[j];
//因为棋型在type数组里面存储顺序是按分数递减存储的,所以最开始找到的棋型为最好的
//在这四个方向上找到最好的就停止寻找,继续找下一个方向的。直到得到四个方向的分数
break;
}
}
}
ChessBoard[x][y]=0;//只是实验下在此处会有什么情况,算出分值之后就回复原样
return result;
}
public void regret(){//悔棋操所
ChessBoard[(int)allx.lastElement()][(int)ally.lastElement()]=0;
allx.removeElementAt(allx.size()-1);
ally.removeElementAt(ally.size()-1);
ChessBoard[(int)allx.lastElement()][(int)ally.lastElement()]=0;
allx.removeElementAt(allx.size()-1);
ally.removeElementAt(ally.size()-1);
repaint();
}
public void startagain(){
Win=false;
IsBlack=true;
for(int i=0;i<15;i++){
for(int j=0;j<15;j++){
ChessBoard[i][j]=0;
}
}
repaint();
}
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
public boolean isExit(int x,int y){
if(ChessBoard[x][y]!=0)
return true;
return false;
}
public boolean IsWin(){
int count=1;
int color=ChessBoard[lastx][lasty];
//判断横向上的相同颜色的棋子数量
count=this.ChessCount(1, 0, color);
if(count>=5)
return true;
//判断纵向上的相同颜色棋子的数量
count=this.ChessCount(0, 1, color);
if(count>=5)
return true;
//判断主对角线上/的相同颜色棋子的数量
count=this.ChessCount(1, 1, color);
if(count>=5)
return true;
//判断副对角线上\的相同颜色棋子的数量
count=this.ChessCount(1, -1, color);
if(count>=5)
return true;
return false;
}
//计算棋子在xChange和yChange方向上连接的数量
public int ChessCount(int xChange,int yChange,int color){
int count=1;//棋子计数器
int tempx=xChange;
int tempy=yChange;
//xChange取值范围(1,0,1,1)和yChange取值范围(0,1,1,-1)分别代表(横向,纵向,/,\)
//先计算正方向上的数量
while (lastx + xChange >= 0 && lastx + xChange <= row && lasty + yChange >= 0 && lasty + yChange <= col && color == ChessBoard[lastx + xChange][lasty + yChange]) {
count++;
if (xChange != 0) {
xChange++;
}
if (yChange != 0) {
if (yChange > 0)
yChange++;
else
yChange--;
}
}
//回到最开始的方向
xChange = tempx;
yChange = tempy;
//接着计算反方向上的数量
while (lastx - xChange >= 0 && lastx - xChange <= row && lasty - yChange >= 0 && lasty - yChange <= col && color == ChessBoard[lastx - xChange][lasty - yChange]) {
count++;
if (xChange != 0) {
xChange++;
}
if (yChange != 0) {
if (yChange > 0)
yChange++;
else
yChange--;
}
}
return count;
}
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO 自动生成的方法存根
if(e.getSource()==back){
gb.regret();
}
if(e.getSource()==start){
gb.startagain();
}
if(e.getSource()==game){
gb.startagain();
}
if(e.getSource()==game2){
gb.startagain();
}
}
}