用java打个五子棋,主要理清思路就很简单了,还有就是规则的制定。
完成一个人机对战的五子棋项目,基本效果如下:
第一部分 Java绘图原理
1.基本概念
像素,坐标
2.组件自定义绘图原理
参见:https://www.cnblogs.com/leier/archive/2012/03/31/2426520.html
3.Graphics对象的常用方法
setFont(), setColor(), drawLine(), drawString(), drawOval(), drawRect(), fillOval(), fillRect(), drawImage()
第二部分 绘制棋盘
1.基本思路
在一个JPanel上绘制一个背景,然后绘制水平和垂直的若干条线,使其构成等距离的格子,通常是15*15(条线)。
2.代码实现
(1)主类代码:
(2) ChessPanel代码:
第三部分 绘制棋子
1.基本思路
使用drawOval()可以绘制空心的圆,使用fillOval()可以填充实心的圆。
2.坐标计算
由于格子是水平和垂直的有下标的,而绘制时需要使用实际的像素坐标,所以,需要进行行列下标到像素坐标的转换:
int x = col * GRID_WIDTH;
int y = row * GRID_WIDTH;
3.代码实现
(1)ChessPanel代码:
第四部分 鼠标下棋
1.基本思路
需要处理鼠标单点事件,获取鼠标所在的位置,然后计算出应该绘制棋子的行列下标,并使用一个二维数组来全局存储棋子的位置。
2.鼠标位置与行列下标计算
int x = e.getX();
int y = e.getY();
int row = y / GRID_WIDTH;
int col = x / GRID_WIDTH;
3.代码实现
(1) ChessPanel属性和构造方法代码:
(2)监听器类(内部类)代码:
(3)绘图代码:
第五部分 判断胜负
1.基本思路
判断胜负是因为在当前位置(row, col)落子导致了胜负,所以,判断胜负其实是在当前落子位置为中心,横向搜索左边第4个位置开始到右边第4个位置(其余位置不需要考虑),或者从上到下,或者正向45度,或者反向45度位置。
2.处理方法
处理方法有很多,可以采用计数的方式,也可以采用字符串连接的方式,此处采用了将从左边第4颗开始,到右边第4颗结束,将每颗的颜色表示成字符1(黑色)或者2(白色),只需要判断其中是否有连续的5个1或5个2,即“11111”或“22222”即可知道胜负。
3.代码实现
(1)监听器类(内部类)代码:
(2)checkWin判断胜负的代码:
/** 判断胜负
* @param row 落子的行下标
* @param col 落子的列下标
* @return 是否获胜,true-是,false-否
*/
public boolean checkWin(int row, int col) {}
(3)重置游戏状态
第六部分 人机对战
1.基本思路
当人点了鼠标落子以后,轮到电脑下棋,电脑的基本思想就是,在棋盘的空白处的每个位置,进行判断,当前位置的进攻指数和防守指数分别为多少,在进攻指数和防守指数中取一个较大值作为当前位置的评估值,在整个棋盘的所有空白处找到一个最大值,最大值的那个位置即为应该落子的位置。
2.某个位置的进攻指数和防守指数的评估方法
可以参见:https://www.cnblogs.com/songdechiu/p/5768999.html
本例中简化此问题,依据第五部分中胜负判断的方式,对连续9个位置形成的字符串进行搜索、评分,得出一个评估方案。如“11111”代表连续5个黑色,评分100,“011110”代表连续4个黑色,两端为空位置,评分90……。
3.代码实现
(1)监听器类(内部类)代码:
(2)电脑下棋的代码:
(3)评估关键参数代码:
(4) 评估方法代码:
下面见完整代码:
代码一:(使用直接在面板上绘色代表棋子,我分成两个java文件写的)
import java.awt.Color;
import java.awt.Container;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.omg.CORBA.PUBLIC_MEMBER;
//界面
public class MyFrame extends JFrame {
public MyFrame(){
this.setTitle("五子棋");
this.setSize(630,650);
Container cp = getContentPane();
JPanel jPanel = new ChessBang();
jPanel.setBackground(Color.orange);
cp.add(jPanel);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
//)设置窗口相对于指定组件的位置。 如果组件当前未显示,或者 c 为 null,则此窗口将置于屏幕的中央
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
//设置窗口不可改变
setResizable(false);
}
public static void main(String[] args) {
JFrame frame = new MyFrame();
frame.setVisible(true);
}
}
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
//实现
public class ChessBang extends JPanel {
public static final int GRID_WIDTH = 40;
// 下棋的长度
public static final int LINE_COUNT = 15;
//光圈的点所在位置
Point lastchessPoint = new Point(-1,-1);
private String[] blackKey = {
"11111", "011110", "11110", "01111", "11011",
"10111", "11101", "01110", "11100", "00111",
"0111", "1110","1011", "1101", "111",
"01100", "00110", "011", "110", "11" };
private String[] whiteKey = {
"22222", "022220", "22220", "02222", "22022",
"20222", "22202", "02220", "22200", "00222", "0222", "2220",
"2022", "2202", "222", "02200", "00220", "022", "220", "22" };
private int[] keyValues = {
100, 90, 80, 80, 80, 80, 80, 70, 60, 60, 50,
50, 50, 50, 40, 30, 30, 20, 20, 10 };
private MouseListener listener = null;
int[][] chessItems = new int[LINE_COUNT][LINE_COUNT];
public boolean isBlack = true;// 记录成黑色的
// 构造方法
public ChessBang() {
listener = new ChessListener();
// 监听器
this.addMouseListener(listener);
}
// 求点
public class ChessListener extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
int row = y / 40; // 不是x除
int col = x / 40;
// 在空处填棋子
if (chessItems[row][col] == 0) {
if (isBlack == true)
chessItems[row][col] = 1;
else
chessItems[row][col] = 2;
ChessBang.this.repaint();
// 判输赢
if (IsWin(row, col) == true) {
JOptionPane.showMessageDialog(null, "你赢了!");
reset();
return;
}
// 这个放在后面的效率会更高
isBlack = !isBlack;
computer();
}
}
}
//
public void computer() {
// 落子的颜色
int chesscomputer = isBlack ? 1 : 2;
int t = 0;
int rowcomputer = -1;
int colcomputer = -1;
for (int i = 0; i < LINE_COUNT; i++) {
for (int j = 0; j < LINE_COUNT; j++) {
if (chessItems[i][j] != 0)
continue;
int atack = checkMax(i, j, chesscomputer);
int defend = checkMax(i, j, 3 - chesscomputer) - 1;
int max = Math.max(atack, defend);
if (max > t) {
rowcomputer = i;
colcomputer = j;
t = max;
}
}
}
//记录位置
lastchessdraw(rowcomputer, colcomputer);
// 下棋
chessItems[rowcomputer][colcomputer] = chesscomputer;
isBlack = !isBlack;
repaint();
// 判输赢
if (IsWin(rowcomputer, colcomputer) == true) {
JOptionPane