简单五子棋制作

基本界面
[img]http://dl2.iteye.com/upload/attachment/0103/3231/e4380809-38e8-3dbe-85bf-ac9d0a7ce63c.jpg[/img]

一 主框架的创建及棋盘的绘制
①主框架函数的创建

public class ChessUI extends JFrame {

public static void main(String[] args) {
ChessUI ui= new ChessUI();
ui.initChessUI();
}

public void initChessUI(){
this.setSize(600,600);
this.setTitle("五子棋");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel panel = new MyPanel();
//设置面板颜色
panel.setBackground(new Color(200,200,100));
//为面板添加鼠标监听器
ChessListener lis = new ChessListener(panel);
panel.addMouseListener(lis);

this.add(panel);
this.setVisible(true);
}
}


②因为五子棋制作时一些数据比不可少 且每个类都要用到 所以定义一个接口 来存放数据
public interface Config {
int X0 = 40, Y0 = 40;// 棋盘左上角的起始点的坐标
int ROWS = 15, COLS = 15;// 棋盘的行和列
int SIZE = 36;// 单元格大小
int CHESS_SIZE = 30;// 棋子大小


//定义一个数组用来保存棋盘的状态
byte[][] CHESSES = new byte[ROWS][COLS];
}


注 byte CHESSES数组 用来存放棋盘每个位置的状态 没有棋子时时0 ,黑棋子时是1,白棋子时是-1,数组中每个元素都对应棋盘上相应的位置


③panel面板上 用来绘制棋盘 棋子 所以必须重写panit方法 且要加上MouseListener监听器

定义一个MyPanel类 来继承 Panel
public class MyPanel extends JPanel implements Config{

@Override
public void paint(Graphics g) {
// TODO Auto-generated method stub
super.paint(g);
}

}


④在Mypanel类中 paint函数里 画棋盘
for (int i = 0; i < ROWS; i++) {
g.drawLine(X0, Y0 + i * SIZE, X0 + (COLS-1) * SIZE, Y0 + i * SIZE);
}
for (int i = 0; i < COLS; i++) {
g.drawLine(X0 + SIZE * i, Y0, X0 + SIZE * i, Y0 + SIZE* (ROWS - 1));
}



二 鼠标监听器的添加
为panel面板添加鼠标监听器 当鼠标点击棋盘时 在棋盘上绘制 棋子


public class ChessListener implements MouseListener, Config {

public JPanel MyPanel;
public Graphics g;
private byte flag = 1; // 记录棋子颜色

private boolean isdraw = true; //判断是否继续绘制

public ChessListener(JPanel MyPanel) {
this.MyPanel = MyPanel;
}

@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub

}



@Override
public void mouseReleased(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 mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub

}

}

注 通过构造函数来获得panel面板 来获得Graphics 来绘制

②在ChessListener中添加函数 用来绘制棋子
public void putChess(int r, int c, byte flag) {
// 用数组记录绘制的位置 颜色
CHESSES[r][c] = flag;

// 当flag==1时 绘制黑子
if (flag == 1) {
g.setColor(Color.black);
flag = -1;
} else {
g.setColor(Color.white);
flag = 1;
}
// 以该交叉点坐标为圆心放棋子
g.fillOval(c * SIZE + X0 - CHESS_SIZE / 2, r * SIZE + Y0 - CHESS_SIZE
/ 2, CHESS_SIZE, CHESS_SIZE);

}


注:通过参数来传递要绘制棋子的位置 类型(颜色)再以该位置为圆心画圆

③在监听器中添加判断输赢的方法
通过扫描最后一次放子的位置 横向扫描 纵向扫描 左斜扫描 右斜扫描
来判断是否有5个相同颜色的棋子在同一条直线上
具体代码如下
// 判断获胜函数
public void Judge(int xx, int yy) {
int fg = CHESSES[xx][yy];
String winner = null;
if (fg == 1)
winner = "黑子";
else if (fg == -1)
winner = "白子";
// 设置计数器
int count = 0;

// ********************扫描纵向棋子************************

// 扫描当前棋子下面4个棋子
for (int i = 1; i <= 4; i++) {
if (xx + i >= 0 && xx + i < ROWS) {
if (CHESSES[xx + i][yy] == fg) {
count++; // 如果是相同棋子 count加1
} else
break; // 否则停止扫描
}
}
// 扫描当前棋子上面4个棋子
for (int i = 1; i <= 4; i++) {
if (xx - i >= 0 && xx - i < ROWS) {
if (CHESSES[xx - i][yy] == fg) {
count++;
} else
break;
}
}
if (count == 4) {
isdraw = false;
JOptionPane.showMessageDialog(null, "1恭喜" + winner + "获胜");
return;
}

// ********************扫描横向棋子************************
count = 0;
for (int i = 1; i <= 4; i++) {
if (yy + i >= 0 && yy + i < COLS) {
if (CHESSES[xx][yy + i] == fg) {
count++; // 如果是相同棋子 count加1
} else
// 否则停止扫描
break;
}
}
for (int i = 1; i <= 4; i++) {
if (yy - i >= 0 && yy - i < COLS) {
if (CHESSES[xx][yy - i] == fg) {
count++;
} else
break;
}
}
if (count == 4) {
isdraw = false;
JOptionPane.showMessageDialog(null, "2恭喜" + winner + "获胜");
return;
}

// ********************扫描右斜向棋子************************
count = 0;
// 扫描斜下
for (int i = 1; i <= 4; i++) {
if (xx + i >= 0 && xx + i < ROWS && yy + i >= 0 && yy + i < COLS) {
if (CHESSES[xx + i][yy + i] == fg) {
count++;
} else
break;
}
}

// 扫描斜上
for (int i = 1; i <= 4; i++) {
if (xx - i >= 0 && xx - i < ROWS && yy - i >= 0 && yy - i < COLS) {
if (CHESSES[xx - i][yy - i] == fg) {
count++;
} else
break;
}
}
if (count == 4) {
isdraw = false;
JOptionPane.showMessageDialog(null, "3恭喜" + winner + "获胜");
return;
}

// ********************扫描左斜向棋子************************
count = 0;
// 扫描斜下
for (int i = 1; i <= 4; i++) {
if (xx + i >= 0 && xx + i < ROWS && yy - i >= 0 && yy - i < COLS) {
if (CHESSES[xx + i][yy - i] == fg) {
count++;
} else
break;
}
}

// 扫描斜上
for (int i = 1; i <= 4; i++) {
if (xx - i >= 0 && xx - i < ROWS && yy + i >= 0 && yy + i < COLS) {
if (CHESSES[xx - i][yy + i] == fg) {
count++;
} else
break;
}
}

if (count == 4) {
isdraw = false;
JOptionPane.showMessageDialog(null, "4恭喜" + winner + "获胜");
return;
}

}


注:①参数是刚放下棋子的位置 flag为棋子类型(颜色)
②每次扫描右分为两个阶段


④实现监听器中mousePressed函数 当鼠标点击下后 要在棋盘上绘制棋子
public void mousePressed(MouseEvent e) {
// 获得鼠标的位置
int x = e.getX();
int y = e.getY();

// 获得和该位置最近的交叉点的坐标
int r = (y - Y0) / SIZE;
int c = (x - X0) / SIZE;

if ((y - Y0) % SIZE > SIZE / 2) {
r++;
}
if ((x - X0) % SIZE > SIZE / 2) {
c++;
}

if (!isOver && r >= 0 && r < ROWS && c >= 0 && c < COLS
&& CHESSES[r][c] == 0) {
// 计算交叉点坐标
int x1 = X0 + SIZE * c;
int y1 = Y0 + SIZE * r;

// 将棋子状态保存起来
CHESSES[r][c] = flag;

if (flag == 1) {
g.setColor(Color.BLACK);
flag = -1;
} else {
g.setColor(Color.WHITE);
flag = 1;
}
putChess(r, c, flag);
}


}


注:①要在putChess函数中 添加判断输赢函数Judge
②通过一系列运算 将点击时的坐标 转换为要绘制在棋盘上的坐标 再通过putChess函数来绘制棋子


以上只基本实现了人人对战
我自己做了一个简易版的人机对战

三 添加机器算法

①添加机器人 Robot类 用来计算出机器要下棋子的坐标
public class Robot implements Config {

Point p;// 机器放棋子的位置

// 如何根据棋盘的局势计算放子位置
public Point checkPoint() {
}
}


②要实现checkPoint函数 我又创建了一个类 CheckChess类
该类中有四个函数 分别扫描指定位置4个方向 并返回相同颜色棋子个数
具体代码如下:
public class CheckChess implements Config {

public int flag = -1;

public CheckChess(int flag) {
this.flag = flag;
}

public void Setflag(int flag){
this.flag = flag;
}

// 判断当前位置横向相同的棋子个数
public int HengCheck(int r, int c) {
int count = 0;
for (int i = c + 1; i < COLS; i++) {
if (CHESSES[r][i] == flag) {
count++; // 如果是相同棋子 count加1
} else
// 否则停止扫描
break;
}
for (int i = c - 1; i >= 0; i--) {
if (CHESSES[r][i] == flag) {
count++;
} else
break;
}
return count;
}

// 判断当前位置竖向的棋子个数
public int ShuCheck(int r, int c) {
// 扫描当前棋子下面棋子
int count = 0;
for (int i = r + 1; i < ROWS; i++) {

if (CHESSES[i][c] == flag) {
count++; // 如果是相同棋子 count加1
} else
break; // 否则停止扫描

}
// 扫描当前棋子上面棋子
for (int i = r - 1; i >= 0; i--) {
if (CHESSES[i][c] == flag) {
count++;
} else
break;
}
return count;
}

// 判断当前位置左斜的棋子个数
public int LCheck45(int r, int c) {
int count = 0;
for (int i = r - 1, j = c + 1; i >= 0 && j < COLS; i--, j++) {
if (CHESSES[i][j] == flag) {
count++;
} else {
break;
}

}

for (int i = r + 1, j = c - 1; i < ROWS && j >= 0; i++, j--) {
if (CHESSES[i][j] == flag) {
count++;
} else {
break;
}

}

return count;

}

// 判断当前位置左斜的棋子个数
public int RCheck45(int r, int c) {
int count = 0;
for (int i = r - 1, j = c - 1; i >= 0 && j >=0; i--, j--) {
if (CHESSES[i][j] == flag) {
count++;
} else {
break;
}

}

for (int i = r + 1, j = c + 1; i < ROWS && j <COLS; i++, j++) {
if (CHESSES[i][j] == flag) {
count++;
} else {
break;
}

}

return count;

}

}


注; flag为要扫描棋子的颜色

③实现Robot类中 checkPoint函数
// 如何根据棋盘的局势计算放子位置
public Point checkPoint() {

CheckChess check = new CheckChess(-1);
// 扫描棋盘上没放子的地方 周围有4个一样的棋子
for (int r = 0; r < ROWS; r++) {
for (int c = 0; c < COLS; c++) {
if (CHESSES[r][c] == 0) {
// 寻找横纵斜4个方向是否有4个相同的白子
check.Setflag(-1);
if (check.HengCheck(r, c) == 4 || check.ShuCheck(r, c) == 4
|| check.RCheck45(r, c) == 4
|| check.LCheck45(r, c) == 4)
return new Point(r, c);
check.Setflag(1);
if (check.HengCheck(r, c) == 4 || check.ShuCheck(r, c) == 4
|| check.RCheck45(r, c) == 4
|| check.LCheck45(r, c) == 4)
return new Point(r, c);

}
}
}

// 扫描棋盘上没放子的地方 周围有3个一样的棋子
check.Setflag(-1);
for (int r = 0; r < ROWS; r++) {
for (int c = 0; c < COLS; c++) {
if (CHESSES[r][c] == 0) {
// 寻找横纵斜4个方向是否有3个相同的白子
check.Setflag(-1);
if (check.HengCheck(r, c) == 3 || check.ShuCheck(r, c) == 3
|| check.RCheck45(r, c) == 3
|| check.LCheck45(r, c) == 3)
return new Point(r, c);

check.Setflag(1);
if (check.HengCheck(r, c) == 3 || check.ShuCheck(r, c) == 3
|| check.RCheck45(r, c) == 3
|| check.LCheck45(r, c) == 3)
return new Point(r, c);

}
}
}

// 扫描棋盘上没放子的地方 周围有2个一样的棋子

for (int r = 0; r < ROWS; r++) {
for (int c = 0; c < COLS; c++) {
if (CHESSES[r][c] == 0) {
// 寻找横纵斜4个方向是否有2个相同的白子
check.Setflag(-1);
if (check.HengCheck(r, c) == 2 || check.ShuCheck(r, c) == 2
|| check.RCheck45(r, c) == 2
|| check.LCheck45(r, c) == 2)
return new Point(r, c);
}
}
}

// 扫描棋盘上没放子的地方 周围有1个一样的棋子
for (int r = 0; r < ROWS; r++) {
for (int c = 0; c < COLS; c++) {
if (CHESSES[r][c] == 0) {
// 寻找横纵斜4个方向是否有1个相同的白子
check.Setflag(-1);
if (check.HengCheck(r, c) == 1 || check.ShuCheck(r, c) == 1
|| check.RCheck45(r, c) == 1
|| check.LCheck45(r, c) == 1)
return new Point(r, c);
}
}
}
return new Point(7, 7);

}


注:① 函数返回的时机器要下棋子在棋盘上的位置
② 该函数只是最简易的算法 先逐个扫描棋盘 当扫描到没有放棋子的位置时 判断这个位置4个方向有没有4相同白色的棋子 如果有则在返回该位置 如果没有就判断该位置有没有4个相同的黑色棋子 如果有则返回该位置 没有就继续扫描。当扫描完棋盘后还是没有返回位置,就再重新扫描棋盘 这次判断的是 是否具有3个相同的棋子 以此类推
③最后返回的是白子的起始位置


④修改监听器中mousePressed函数
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
g = MyPanel.getGraphics();

int x, y; // 按下鼠标时坐标
x = e.getX();
y = e.getY();
int r = (y - Y0) / SIZE; // 行数
int c = (x - X0) / SIZE; // 列数

if ((x - X0) % SIZE > SIZE / 2) {
c++;
}
if ((y - Y0) % SIZE > SIZE / 2) {
r++;
}

if (r >= 0 && r < ROWS && c >= 0 && c < COLS && CHESSES[r][c] == 0
&& isdraw) {

// 绘制玩家下的棋子
putChess(r, c, (byte) 1);
// 产生机器要下的棋子坐标 并绘制棋子
Point p = robot.checkPoint();
putChess(p.x, p.y, (byte) -1);


}

}


四 重写MyPanel中panit方法
public void paint(Graphics g) {
// TODO Auto-generated method stub
super.paint(g);
for (int i = 0; i < ROWS; i++) {
g.drawLine(X0, Y0 + i * SIZE, X0 + (COLS-1) * SIZE, Y0 + i * SIZE);
}
for (int i = 0; i < COLS; i++) {
g.drawLine(X0 + SIZE * i, Y0, X0 + SIZE * i, Y0 + SIZE* (ROWS - 1));
}

for(int i=0;i<ROWS;i++){
for(int j=0;j<ROWS;j++){
if(CHESSES[i][j]!=0){
switch ((int)CHESSES[i][j]){
case 1:
g.setColor(Color.black);
break;
case -1:
g.setColor(Color.white);
break;
}
g.fillOval(j * SIZE + X0 - CHESS_SIZE / 2, i * SIZE + Y0- CHESS_SIZE / 2, CHESS_SIZE, CHESS_SIZE);
}
}
}

}



上面过程基本实现了五子棋方法 添加了简单的机器人 但还存在许多缺陷 比如机器算法没有算出放棋子的最优位置 机器算法起始位置都是一样 的 等 这些bug还有待我去完善
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值