在学校的Java课程中,我们被分配了一项有趣的任务:开发一款能够实现人机对弈的五子棋游戏。为了更好地理解Java GUI的运用,并与大家分享学习心得,我将整个开发过程记录在这篇博客中。欢迎大家阅读并提供宝贵的意见和建议!"
编辑
1.绘制棋盘
编辑
1.定义myPanel类。
myPanel相当于画板。
myPanel要继承 JPanel类,并要覆盖父类的paint方法,在paint方法里面写负责绘画的代码
java
public class myPanel extends JPanel {
static final int start = 6;
@Override
public void paint(Graphics g)
{
//调用父类的paint初始化画笔
super.paint(g);
//绘制背景
DrawBackground(g);
//绘制外边框
DrawBorder(g);
//绘制棋盘
DrawChessBoard(g);
}
public void DrawBackground(Graphics g)
{ //绘制背景
g.setColor(new Color(211, 152, 91));
g.fillRect(0, 0, 620,620);
}
public void DrawBorder(Graphics g)
{
//绘制外边框
g.setColor(Color.BLACK);
g.fillRect(5,5,610,5);
g.fillRect(610,5,5,610);
g.fillRect(5,610,610,5);
g.fillRect(5,5,5,610);
}
public void DrawChessBoard(Graphics g)
{
g.setColor(Color.BLACK);
//画横线
for (int i = 0; i < 19; i++) {
g.drawLine(6+i*32,6,6+i*32,614);
}
//画竖线
for (int i = 0; i < 19; i++) {
g.drawLine(6,6+i*32,614,6+i*32);
}
}
//画棋子
public void DrawChess(Graphics g,int x,int y,int type){
switch (type){
case 1:
g.setColor(Color.BLACK);
break;
case 2:
g.setColor(Color.WHITE);
}
g.fillOval(x*32+start,y*32+start,30,30);
}
}
2.定义myFrame类。
myFrame相当于窗口,画板要放在窗口里。
myFram要继承 JFram类,在初始化函数设置窗口参数
java
public class MyFrame extends JFrame {
myPanel mp = null;
public MyFrame() {
mp = new myPanel();
this.setTitle("五子棋");
this.setSize(620, 620);
//添加画板
this.add(mp);
//点击窗口叉叉退出程序
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
static public void main(String[] args) {
MyFrame mf = new MyFrame();
}
}
2.核心功能
1.实现下棋功能
1.定义相关变量
java
//偏移量
static final int IndexOffset = -10;
static final int ChessOffset = -10;
//黑子下棋标记
static boolean black = true;
boolean gameIsOver = false;
int chess[][]=new int[19][19];
2.添加事件监听
myPanel实现 MouseListener接口
重写mouseClicked方法
java
@Override
public void mouseClicked(MouseEvent e) {
//计算棋子坐标
//# 0表示空棋
//# 1表示黑棋
//# 2表示白棋
int x = (e.getX() - IndexOffset) / 32;
int y = (e.getY() - 32 - IndexOffset) / 32;
System.out.println(y);
chess[x][y] = 1;
this.repaint();
}
myFrame添加事件监听
java
public MyFrame() {
mp = new myPanel();
this.setTitle("五子棋");
this.setSize(620, 620);
//添加画板
this.add(mp);
//点击窗口叉叉退出程序
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.addMouseListener(mp);
this.setVisible(true);
}
2.实现自动下棋
1.按照优先级从高到低枚举出所有情况
java
//# 0表示空棋
//# 1表示黑棋
//# 2表示白棋
//# 3表示下棋的位置
private static final int[][] cdata = {
{3, 1, 1, 1, 1}, {1, 3, 1, 1, 1}, {1, 1, 3, 1, 1}, {1, 1, 1, 3, 1}, {1, 1, 1, 1, 3},
{2, 2, 3, 2, 2}, {2, 2, 2, 3, 2}, {2, 3, 2, 2, 2}, {3, 2, 2, 2, 2}, {2, 2, 2, 2, 3},
{3, 1, 1, 1, 0}, {1, 1, 1, 3, 0}, {1, 1, 3, 1, 0}, {1, 3, 1, 1, 0},
{3, 2, 2, 2, 0}, {2, 3, 2, 2, 0}, {2, 2, 3, 2, 0}, {2, 2, 2, 3, 0},
{1, 1, 3, 3, 0}, {3, 1, 1, 0, 0}, {0, 1, 3, 1, 0},
{3, 2, 2, 0, 0}, {2, 2, 3, 0, 0}, {1, 3, 1, 0, 0},
{3, 1, 0, 0, 0}, {1, 3, 0, 0, 0}
};
2.选出最佳下棋位置
java
public Point getBestPoint() {
//记录最低分(分值越低,优先级越高)
int score = 100;
//最佳位置
Point point = new Point(0, 0);
//每次都要遍历四个方向 左下 下 右下 右
int[] dx = {-1, 0, 1, 1};
int[] dy = {1, 1, 1, 0};
for (int i = 0; i < 19; i++) {
for (int j = 0; j < 19; j++) {
for (int k = 0; k < 4; k++) {
int cnt = 0;
for (int[] e : cdata) {
int m;
int x = i;
int y = j;
int bestX = 0;
int bestY = 0;
for (m = 0; m < 5; m++) {
if (e[m] == 3 && chess[x][y] == 0) {
bestX = x;
bestY = y;
} else {
if (chess[x][y] != e[m]) {
break;
}
}
x += dx[k];
y += dy[k];
if (x < 0 || x >= 19 || y < 0 || y >= 19) {
break;
}
}
if (m == 5) {
if (cnt < score) {
score = cnt;
point.x = bestX;
point.y = bestY;
}
break;
}
cnt++;
}
}
}
}
if (score < 100) {
return point;
} else {
int x = (int) (Math.random() * 19);
int y = (int) (Math.random() * 19);
while (chess[x][y] != 0) {
x = (int) (Math.random() * 19);
y = (int) (Math.random() * 19);
}
return new Point(x, y);
}
}
3.判断游戏是否结束
遍历棋盘
java
public boolean check() {
//每次都要遍历四个方向 左下 下 右下 右
int[] dx = {-1, 0, 1, 1};
int[] dy = {1, 1, 1, 0};
for (int i = 0; i < 19; i++) {
for (int j = 0; j < 19; j++) {
for (int k = 0; k < 4; k++) {
int x = i;
int y = j;
int m;
boolean flag = true;
for (m = 0; m < 4; m++) {
int tx = x + dx[k];
int ty = y + dy[k];
if (tx < 0 || tx > 19 || ty < 0 || ty > 19) {
flag = false;
break;
}
if (chess[x][y] != chess[x + dx[k]][y + dy[k]]) {
flag = false;
break;
} else if (chess[x][y] == 0) {
flag = false;
break;
}
x = tx;
y = ty;
}
if (flag) {
gameIsOver = true;
return true;
}
}
}
}
return false;
}
4.事件循环
java
@Override
public void paint(Graphics g) {
//调用父类的paint初始化画笔
super.paint(g);
//绘制背景
DrawBackground(g);
//绘制外边框
DrawBorder(g);
//绘制棋盘
DrawChessBoard(g);
DrawChess(g);
//开始游戏
if (!gameIsOver)
game();
//游戏结束
if (check()) {
gameOver(g);
}
}
完整代码
myPanel
java
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
/**
*
*
* @author yuwei
* @date 23:29 2024/4/23
*/
public class myPanel extends JPanel implements MouseListener {
//偏移量
static final int IndexOffset = -10;
static final int ChessOffset = -10;
//黑子下棋标记
static boolean black = true;
boolean gameIsOver = false;
//# 0表示空棋
//# 1表示黑棋
//# 2表示白棋
//# 3表示下棋的位置
private static final int[][] cdata = {
{3, 1, 1, 1, 1}, {1, 3, 1, 1, 1}, {1, 1, 3, 1, 1}, {1, 1, 1, 3, 1}, {1, 1, 1, 1, 3},
{2, 2, 3, 2, 2}, {2, 2, 2, 3, 2}, {2, 3, 2, 2, 2}, {3, 2, 2, 2, 2}, {2, 2, 2, 2, 3},
{3, 1, 1, 1, 0}, {1, 1, 1, 3, 0}, {1, 1, 3, 1, 0}, {1, 3, 1, 1, 0},
{3, 2, 2, 2, 0}, {2, 3, 2, 2, 0}, {2, 2, 3, 2, 0}, {2, 2, 2, 3, 0},
{1, 1, 3, 3, 0}, {3, 1, 1, 0, 0}, {0, 1, 3, 1, 0},
{3, 2, 2, 0, 0}, {2, 2, 3, 0, 0}, {1, 3, 1, 0, 0},
{3, 1, 0, 0, 0}, {1, 3, 0, 0, 0}
};
int chess[][] = new int[20][20];
@Override
public void paint(Graphics g) {
//调用父类的paint初始化画笔
super.paint(g);
//绘制背景
DrawBackground(g);
//绘制外边框
DrawBorder(g);
//绘制棋盘
DrawChessBoard(g);
DrawChess(g);
//开始游戏
if (!gameIsOver)
game();
//游戏结束
if (check()) {
gameOver(g);
}
}
public void gameOver(Graphics g) {
Font font = new Font("Arial", Font.BOLD, 24);
g.setColor(Color.red);
g.setFont(font);
g.drawString("游戏结束", 270, 270);
}
public void DrawBackground(Graphics g) { //绘制背景
g.setColor(new Color(211, 152, 91));
g.fillRect(0, 0, 620, 620);
}
public void DrawBorder(Graphics g) {
//绘制外边框
g.setColor(Color.BLACK);
g.fillRect(5, 5, 610, 5);
g.fillRect(610, 5, 5, 610);
g.fillRect(5, 610, 610, 5);
g.fillRect(5, 5, 5, 610);
}
public void DrawChessBoard(Graphics g) {
g.setColor(Color.BLACK);
//画横线
for (int i = 0; i < 19; i++) {
g.drawLine(6 + i * 32, 6, 6 + i * 32, 614);
}
//画竖线
for (int i = 0; i < 19; i++) {
g.drawLine(6, 6 + i * 32, 614, 6 + i * 32);
}
}
//画棋子
public void DrawChess(Graphics g) {
for (int i = 0; i < 19; i++) {
for (int j = 0; j < 19; j++) {
if (chess[i][j] == 1) {
g.setColor(Color.BLACK);
} else if (chess[i][j] == 2) {
g.setColor(Color.WHITE);
} else {
continue;
}
g.fillOval(i * 32 + ChessOffset, j * 32 + ChessOffset, 30, 30);
}
}
}
public Point getBestPoint() {
//记录最低分(分值越低,优先级越高)
int score = 100;
//最佳位置
Point point = new Point(0, 0);
//每次都要遍历四个方向 左下 下 右下 右
int[] dx = {-1, 0, 1, 1};
int[] dy = {1, 1, 1, 0};
for (int i = 0; i < 19; i++) {
for (int j = 0; j < 19; j++) {
for (int k = 0; k < 4; k++) {
int cnt = 0;
for (int[] e : cdata) {
int m;
int x = i;
int y = j;
int bestX = 0;
int bestY = 0;
for (m = 0; m < 5; m++) {
if (e[m] == 3 && chess[x][y] == 0) {
bestX = x;
bestY = y;
} else {
if (chess[x][y] != e[m]) {
break;
}
}
x += dx[k];
y += dy[k];
if (x < 0 || x >= 19 || y < 0 || y >= 19) {
break;
}
}
if (m == 5) {
if (cnt < score) {
score = cnt;
point.x = bestX;
point.y = bestY;
}
break;
}
cnt++;
}
}
}
}
if (score < 100) {
return point;
} else {
int x = (int) (Math.random() * 19);
int y = (int) (Math.random() * 19);
while (chess[x][y] != 0) {
x = (int) (Math.random() * 19);
y = (int) (Math.random() * 19);
}
return new Point(x, y);
}
}
public boolean check() {
//每次都要遍历四个方向 左下 下 右下 右
int[] dx = {-1, 0, 1, 1};
int[] dy = {1, 1, 1, 0};
for (int i = 0; i < 19; i++) {
for (int j = 0; j < 19; j++) {
for (int k = 0; k < 4; k++) {
int x = i;
int y = j;
int m;
boolean flag = true;
for (m = 0; m < 4; m++) {
int tx = x + dx[k];
int ty = y + dy[k];
if (tx < 0 || tx > 19 || ty < 0 || ty > 19) {
flag = false;
break;
}
if (chess[x][y] != chess[x + dx[k]][y + dy[k]]) {
flag = false;
break;
} else if (chess[x][y] == 0) {
flag = false;
break;
}
x = tx;
y = ty;
}
if (flag) {
gameIsOver = true;
return true;
}
}
}
}
return false;
}
public void game() {
if (check()) {
return;
}
if (black) {
Point point = getBestPoint();
chess[point.x][point.y] = 1;
black = false;
this.repaint();
}
}
@Override
public void mouseClicked(MouseEvent e) {
//计算棋子坐标
//# 0表示空棋
//# 1表示黑棋
//# 2表示白棋
if (!black&&!gameIsOver) {
int x = (e.getX() - IndexOffset) / 32;
int y = (e.getY() - 32 - IndexOffset) / 32;
chess[x][y] = 2;
black = true;
this.repaint();
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
myFrame
java
import javax.swing.*;
/**
* 用户服务
*
* @author yuwei
* @date 23:42 2024/4/23
*/
public class MyFrame extends JFrame {
myPanel mp = null;
public MyFrame() {
mp = new myPanel();
this.setTitle("五子棋");
this.setSize(620, 620);
//添加画板
this.add(mp);
//点击窗口叉叉退出程序
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.addMouseListener(mp);
this.setVisible(true);
}
static public void main(String[] args) {
MyFrame mf = new MyFrame();
}
}
感谢阅读,希望本文对你有所帮助