参照书本写了一个很简单的五子棋程序
主要有如下功能:
1、初始化棋盘initBoard()
2、下棋play()
未完成的功能:
1、没有实现棋子AI
2、没有实现连机
3、UI可以继续优化
个人感觉五子棋只有在判断输赢的算法上稍微需要思考一下,别的地方都可以参考书本或者网络自己完成。
具体如下:
1、首先定义一些常量和变量
// 定义一个二维数组来充当棋盘
private static String[][] board;
//五个棋子即赢
private final int WIN_COUNT = 5;
// 棋盘大小
public static final int BOARD_SIZE = 15;
//棋盘,黑棋,白棋和选择框图标
BufferedImage table;
BufferedImage black;
BufferedImage white;
BufferedImage selected;
//棋盘像素
private final int TABLE_WIDTH = 535;
private final int TABLE_HEIGHT = 536;
//棋盘坐标的像素值和棋盘数组之间的比率
private final int RATE = TABLE_WIDTH / BOARD_SIZE;
//棋盘坐标的像素值和棋盘数组之间的偏移距离
private final int X_OFFSET = 5;
private final int Y_OFFSET = 6;
//游戏窗口
JFrame f = new JFrame("五子棋");
//棋盘对应的Canvas组件
ChessBoard chessBoard = new ChessBoard();
//当前选中点坐标
private int selectedX = -1;
private int selectedY = -1;
2、初始化棋盘
public void initBoard() throws IOException {
table = ImageIO.read(new File("image/board.jpg"));
black = ImageIO.read(new File("image/black.gif"));
white = ImageIO.read(new File("image/white.gif"));
selected = ImageIO.read(new File("image/selected.gif"));
// 初始化棋盘数组
board = new String[BOARD_SIZE][BOARD_SIZE];
// 把每个元素赋值为“十”
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
board[i][j] = "十";
}
}
chessBoard.setPreferredSize(new Dimension(TABLE_WIDTH, TABLE_HEIGHT));
f.add(chessBoard);
f.pack();
f.setVisible(true);
}
3、下棋
public void play() {
chessBoard.addMouseListener(new MouseAdapter() {
@Override
//用户点击事件转换成棋子坐标
public void mouseClicked(MouseEvent e) {
int xPos = (e.getX() - X_OFFSET) / RATE;
int yPos = (e.getY() - Y_OFFSET) / RATE;
if (board[xPos][yPos] != "●" && board[xPos][yPos] != "○") {
board[xPos][yPos] = "●";
}
//电脑随机生成坐标,这里可以优化算法,做出AI,我自己写的比较简单,就用随机函数 实现了下。
int[] computerPosArr = computerPlay();
board[computerPosArr[0]][computerPosArr[1]] = "○";
chessBoard.repaint();
if (isWin(xPos, yPos, "●")) {
// System.out.println("black win");
JOptionPane.showMessageDialog(null, "黑棋获得了胜利");
}
if (isWin(xPos, yPos, "○")) {
// System.out.println("black win");
JOptionPane.showMessageDialog(null, "白棋获得了胜利");
}
}
@Override
public void mouseExited(MouseEvent e) {
selectedX = -1;
selectedY = -1;
// chessBoard.repaint();
}
});
chessBoard.addMouseMotionListener(new MouseMotionAdapter() {
@Override
//当鼠标移动时候,改变选中点坐标
public void mouseMoved(MouseEvent e) {
selectedX = (e.getX() - X_OFFSET) / RATE;
selectedY = (e.getY() - Y_OFFSET) / RATE;
chessBoard.repaint();
}
});
}
4、电脑的随机下棋
public int[] computerPlay() {
int posX = (int) (Math.random() * (BOARD_SIZE - 1));
int posY = (int) (Math.random() * (BOARD_SIZE - 1));
while (board[posX][posY] != "十") {
posX = (int) (Math.random() * (BOARD_SIZE - 1));
posY = (int) (Math.random() * (BOARD_SIZE - 1));
}
int[] result = { posX, posY };
return result;
}
5、判断输赢
public boolean isWin(int posX, int posY, String ico) {
// 直线起点的X坐标
int startX = 0;
// 直线起点Y坐标
int startY = 0;
// 直线结束pX坐标
int endX = BOARD_SIZE - 1;
// 直线结束Y坐标
int endY = BOARD_SIZE - 1;
// 同条直线上相邻棋子累积数
int sameCount = 0;
int temp = 0;
// 计算起点的最小X坐标与Y坐标
temp = posX - WIN_COUNT + 1;
startX = temp < 0 ? 0 : temp;
temp = posY - WIN_COUNT + 1;
startY = temp < 0 ? 0 : temp;
// 计算终点的最大X坐标与Y坐标
temp = posX + WIN_COUNT - 1;
endX = temp > BOARD_SIZE - 1 ? BOARD_SIZE - 1 : temp;
temp = posY + WIN_COUNT - 1;
endY = temp > BOARD_SIZE - 1 ? BOARD_SIZE - 1 : temp;
// 从左到右方向计算相同相邻棋子的数目
String[][] board = Gobang.getBoard();
for (int i = startY; i < endY; i++) {
if (board[posX][i] == ico && board[posX][i + 1] == ico) {
sameCount++;
} else if (sameCount != WIN_COUNT - 1) {
sameCount = 0;
}
}
if (sameCount == 0) {
// 从上到下计算相同相邻棋子的数目
for (int i = startX; i < endX; i++) {
if (board[i][posY] == ico && board[i + 1][posY] == ico) {
sameCount++;
} else if (sameCount != WIN_COUNT - 1) {
sameCount = 0;
}
}
}
if (sameCount == 0) {
// 从左上到右下计算相同相邻棋子的数目
int j = startY;
for (int i = startX; i < endX; i++) {
if (j < endY) {
if (board[i][j] == ico && board[i + 1][j + 1] == ico) {
sameCount++;
} else if (sameCount != WIN_COUNT - 1) {
sameCount = 0;
}
j++;
}
}
}
if (sameCount == 0) {
// 从左上下到右上计算相同相邻棋子的数目
int j = endY;
for (int i = startX; i < endX; i++) {
if (j > startY) {
if (board[i][j] == ico && board[i + 1][j - 1] == ico) {
sameCount++;
} else if (sameCount != WIN_COUNT - 1) {
sameCount = 0;
}
j--;
}
}
}
return sameCount >= WIN_COUNT - 1 ? true : false;
}
6、画棋盘
public class ChessBoard extends JPanel {
@Override
public void paint(Graphics g) {
g.drawImage(table, 0, 0, null);
if (selectedX >= 0 && selectedY >= 0) {
g.drawImage(selected, selectedX * RATE + X_OFFSET, selectedY
* RATE + Y_OFFSET, null);
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (board[i][j].equals("●")) {
g.drawImage(black, i * RATE + X_OFFSET, j * RATE
+ Y_OFFSET, null);
}
if (board[i][j].equals("○")) {
g.drawImage(white, i * RATE + X_OFFSET, j * RATE
+ Y_OFFSET, null);
}
}
}
}
}
}
7、主函数main
public static void main(String args[]) throws IOException{
Gobang gobang=new Gobang();
gobang.initBoard();
gobang.play();
}