Java项目(五子棋)

功能分析

界面绘制

界面分为棋盘区域按键面板

  • 整体界面为1500×1000
  • 棋盘区域背景色为浅灰色,棋盘为21×21大小间隔45个像素点,放置在左侧
  • 按键面板背景色为白色,大小为500×1000,共放置5个按键“开始游戏悔棋认输回放退出游戏

下棋策略

  • 棋子放置在棋盘线的交汇点上
  • 黑白交替下棋

胜负判定

  • 每下颗棋子后进行胜负判定
  • 输出胜负信息

棋局录制与回放

  • 回放下棋过程的每一步,并间隔一段时间

悔棋

  • 撤销最新下的棋子

功能实现

界面绘制与更新

  • 继承JFrame类,重写paint方法。在paint方法中绘制棋盘
    棋盘从(50,50)到(950,950)像素坐标;间隔45个像素坐标;一共21根线
@Override
    public void paint(Graphics g) {
        super.paint(g);
        g.setColor(Color.black);
        for (int i = 0; i <= 20; i++) {
            //画横线
            g.drawLine(50, 50 + i*45, 950, 50 + i*45);
            //画竖线
            g.drawLine(50 + i*45, 50, 50 + i*45, 950);
        }

    }
  • 棋子绘制与更新
    棋子分为白色和黑色两种,如何使其看起来立体,需要控制同心圆颜色的变化
    黑色棋子RGB值变化:0~200;
    白色棋子RGB值变化:205~255;
public static void drawpiece (int x, int y, int color){
        for (int i = 0; i < 40; i++) {
            if (color == 1){
                //黑色
                g.setColor(new Color(i*5, i*5, i*5));
            }
            else if (color == 2){
                //白色
                g.setColor(new Color(205+i,205+i ,205+i));
            }
            g.fillOval(x + i/2, y + i/2, 40-i, 40-i);
        }
    }

棋子更新使用update方法绘制棋子,在画面更新或者回放时调用
本案例使用列表储存坐标点使其包含时间顺序
回放模式加入500ms的停顿,回放会更加清晰每一子的情况

@Override
    public void update(Graphics g) {
        super.update(g);
        for (int i = 0; i < Pieces.num; i++) {
            if (Gobang_Listerner.name.equals("回放")){
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Gobang_Listerner.drawpiece(Gobang_Listerner.pieces[i].x - 20, Gobang_Listerner.pieces[i].y - 20, Gobang_Listerner.pieces[i].color);
        }
    }

胜负判定策略

每下一个棋子都应该进行胜负判定。策略如图所示,寻找一条直线上的五个棋子
实现的过程需要一个二维数组,将其初始化为全0;黑色棋子存为1;白色棋子存为2;

胜负策略

回放

回放的功能主要是把棋子的时间顺序记录下来,然后按照时间先后重新绘制在棋盘上

悔棋

删除最新下的一颗棋子;需要注意的问题是,除了在棋子列表,还需要修改二维数组以及棋子颜色

if (Pieces.num > 0) {
	color_flag = !color_flag;
	Piece_x.remove(Pieces.num - 1);
	Piece_y.remove(Pieces.num - 1);
	piece_coordinates[x/45 - 1][y/45 - 1] = 0;
	Pieces.num--;
	jf.update(g);
}
else {
	System.err.println("不能撤销");
}

项目优化

界面重构时棋盘闪烁问题解决方案

在更新界面的时候我们通常会使用repaint方法,但是repaint方法会把paint方法重新调用,这使得棋盘和棋子都重新绘制了一遍,因此造成了画面闪烁。
解决办法如下:将棋盘绘制与棋子绘制进行分开,当程序需要对界面上的棋子进行重绘的时候调用update方法而并非使用repaint。

整体展示

界面展示

界面
在这里插入图片描述

代码

  • GobangUI
package Gobang;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;

public class GobangUI extends JFrame{

    public static void main(String[] args) {
        GobangUI go = new GobangUI();
        go.initUI();
    }

    public void initUI() {
        JFrame jf = this;

        jf.setTitle("五子棋");
        jf.setSize(1500, 1000);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setBackground(Color.LIGHT_GRAY);

        Gobang_Listerner gl = new Gobang_Listerner();

        JPanel bt_panel = new JPanel();
        bt_panel.setBackground(Color.WHITE);
        init_bt_panel(bt_panel, gl);

        jf.add(bt_panel, BorderLayout.EAST);

        jf.setVisible(true);

        gl.setJf(jf);

        jf.addMouseListener(gl);
        jf.addMouseMotionListener(gl);
        Gobang_Listerner.g = jf.getGraphics();
    }

    public void init_bt_panel(JPanel bt_panel, ActionListener actionListener) {
        Dimension dimension = new Dimension(500, 1000);
        bt_panel.setPreferredSize(dimension);

        bt_panel.setLayout(new FlowLayout());
        String[] strs = {"开始游戏","悔棋","认输","回放"
                ,"退出游戏"};

        Dimension bt_dimension = new Dimension(250, 45);
        for (String str : strs) {
            JButton btn = new JButton(str);
            btn.setBackground(Color.WHITE);
            btn.setPreferredSize(bt_dimension);
            btn.addActionListener(actionListener);
            bt_panel.add(btn, BorderLayout.CENTER);
        }

    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.setColor(Color.black);
        for (int i = 0; i <= 20; i++) {
            //画横线
            g.drawLine(50, 50 + i*45, 950, 50 + i*45);
            //画竖线
            g.drawLine(50 + i*45, 50, 50 + i*45, 950);
        }

    }
    @Override
    public void update(Graphics g) {
        super.update(g);
        for (int i = 0; i < Pieces.num; i++) {
            if (Gobang_Listerner.name.equals("回放")){
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Gobang_Listener.drawpiece(Gobang_Listener.pieces[i].x - 20, Gobang_Listener.pieces[i].y - 20, Gobang_Listener.pieces[i].color);
        }
    }
}

  • Gobang_Listener
package Gobang;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;

public class Gobang_Listener implements MouseListener, ActionListener, MouseMotionListener {
    JFrame jf;
    static Graphics g;

    boolean repetition_flag = false;
    boolean color_flag = false;
    int color = 0;

    static String name = "a";

    int x, y;
    ArrayList<Integer> Piece_x = new ArrayList<>();
    ArrayList<Integer> Piece_y = new ArrayList<>();

    int[][] piece_coordinates = new int[21][21];

    static Pieces[] pieces = new Pieces[441];

    public Gobang_Listener(){
        for (int i = 0; i < 441; i++) {
            pieces[i] = new Pieces();
        }
    }

    public void setJf(JFrame jf) {
        this.jf = jf;
    }

    public boolean Victory(int x, int y, int color){
        boolean victory = false;
        int index_x = x/45 - 1;
        int index_y = y/45 - 1;
        int i = 1;
        int num = 1;
        boolean disconnect_L = false;
        boolean disconnect_R = false;
        boolean disconnect_U = false;
        boolean disconnect_D = false;

        //左-右
        while (i < 5) {
            if (index_x - i >= 0 && disconnect_L == false) {
                if (piece_coordinates[index_x - i][index_y] == color) {
                    num++;

                }
                else {
                    disconnect_L = true;
                }
            }
            if (index_x + i <= 20 && disconnect_R == false) {
                if (piece_coordinates[index_x + i][index_y] == color) {
                    num++;

                }
                else {
                    disconnect_R = true;
                }
            }
            if (num == 5) {
                victory = true;
                break;
            } else {
                i++;
            }
        }

        //上-下
        if (!victory) {
            i  = 1;
            num = 1;
            while (i < 5) {
                if (index_y - i >= 0 && !disconnect_U) {
                    if (piece_coordinates[index_x][index_y - i] == color) {
                        num++;

                    }
                    else {
                        disconnect_U = true;
                    }
                }
                if (index_y + i <= 20 && !disconnect_D) {
                    if (piece_coordinates[index_x][index_y + i] == color) {
                        num++;

                    }
                    else {
                        disconnect_D = true;
                    }
                }
                if (num == 5) {
                    victory = true;
                    break;
                } else {
                    i++;
                }
            }
        }

        //左下-右上
        if (!victory) {
            i  = 1;
            num = 1;
            disconnect_L = false;
            disconnect_R = false;
            while (i < 5) {
                if (index_x - i >= 0 && index_y + i <= 20 && !disconnect_L) {
                    if (piece_coordinates[index_x - i][index_y + i] == color) {
                        num++;

                    }
                    else {
                        disconnect_L = true;
                    }
                }
                if (index_x + i <= 20 && index_y - i >= 0 && !disconnect_R) {
                    if (piece_coordinates[index_x + i][index_y - i] == color) {
                        num++;

                    }
                    else{
                        disconnect_R = true;
                    }
                }
                if (num == 5) {
                    victory = true;
                    break;
                } else {
                    i++;
                }
            }
        }
        //左上-右下
        if (!victory) {
            i  = 1;
            num = 1;
            disconnect_L = false;
            disconnect_R = false;
            while (i < 5) {
                if (index_x - i >= 0 && index_y - i >= 0 && !disconnect_L) {
                    if (piece_coordinates[index_x - i][index_y - i] == color) {
                        num++;

                    }
                    else {
                        disconnect_L = true;
                    }
                }
                if (index_x + i <= 20 && index_y + i <= 20 && !disconnect_R) {
                    if (piece_coordinates[index_x + i][index_y + i] == color) {
                        num++;

                    }
                    else{
                        disconnect_R = true;
                    }
                }
                if (num == 5) {
                    victory = true;
                    break;
                } else {
                    i++;
                }
            }
        }
        return victory;
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        x = e.getX();
        y = e.getY();

        if (x >= 50 && x <= 950 && y >= 50 && y <= 950){
            for (int i = 50; i < 950; i = i+45) {
                if (x >= i && x <= i + 45){
                    if (x - i > i + 45 - x){
                        x = i + 45;
                    }
                    else {
                        x = i;
                    }
                }
                if (y > i && y < i + 45){
                    if (y - i > i + 45 - y){
                        y = i + 45;
                    }
                    else {
                        y = i;
                    }
                }
            }

            if (Piece_x.isEmpty()) {
                repetition_flag = false;
            }
            else{
                for (int i = 0; i < Piece_x.size(); i++) {
                    if (Piece_x.get(i) == x/45 && Piece_y.get(i) == y/45){
                        repetition_flag = true;
                        break;
                    }
                    if (Piece_x.get(i) != x/45 && Piece_y.get(i) != y/45){
                        repetition_flag = false;
                    }
                }
            }

            if (repetition_flag){
                System.err.println("重复下子");
            }
            else {
                color_flag = !color_flag;

                if (color_flag){
                    color = 1;
                }
                else {
                    color = 2;
                }
                Piece_x.add(x/45);
                Piece_y.add(y/45);
                piece_coordinates[x/45 - 1][y/45 - 1] = color;
                drawpiece(x-20, y-20, color);

                boolean victor = Victory(x, y, color);
                System.out.println(victor);

                if (victor){
                    if (color == 1){
                        JOptionPane.showMessageDialog(null, "恭喜黑子胜利");
                    }
                    else if (color == 2){
                        JOptionPane.showMessageDialog(null, "恭喜白子胜利");
                    }
                }

                pieces[Pieces.num].x = x;
                pieces[Pieces.num].y = y;
                pieces[Pieces.num].color = color;
                Pieces.num++;
            }
        }
        else {
            System.err.println("请在棋盘内下棋子!");
        }

    }

    @Override
    public void mousePressed(MouseEvent e) {

    }

    @Override
    public void mouseReleased(MouseEvent e) {

    }

    @Override
    public void mouseEntered(MouseEvent e) {
        jf.update(g);
    }

    @Override
    public void mouseExited(MouseEvent e) {

    }

    public static void drawpiece (int x, int y, int color){
        for (int i = 0; i < 40; i++) {
            if (color == 1){
                //黑色
                g.setColor(new Color(i*5, i*5, i*5));
            }
            else if (color == 2){
                //白色
                g.setColor(new Color(205+i,205+i ,205+i));
            }
            g.fillOval(x + i/2, y + i/2, 40-i, 40-i);
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        name = e.getActionCommand();
        switch (name) {
            case ("开始游戏") -> {
                color_flag = false;
                Piece_x.clear();
                Piece_y.clear();
                Pieces.num = 0;
                for (int i = 0; i < 21; i++) {
                    for (int j = 0; j < 21; j++){
                        piece_coordinates[i][j] = 0;
                    }
                }
                jf.update(g);
            }
            case ("退出游戏") -> {
                System.out.println("退出游戏");
                color_flag = false;
                Piece_x.clear();
                Piece_y.clear();
                Pieces.num = 0;
                for (int i = 0; i < 21; i++) {
                    for (int j = 0; j < 21; j++){
                        piece_coordinates[i][j] = 0;
                    }
                }
                jf.setVisible(false);
            }
            case ("悔棋") -> {
                if (Pieces.num > 0) {
                    color_flag = !color_flag;
                    Piece_x.remove(Pieces.num - 1);
                    Piece_y.remove(Pieces.num - 1);
                    piece_coordinates[x/45 - 1][y/45 - 1] = 0;
                    Pieces.num--;
                    jf.update(g);
                }
                else {
                    System.err.println("不能撤销");
                }
            }
            case ("回放") -> {
                jf.update(g);
                name = "a";
            }
            case ("认输") -> {
                if (color == 1) {
                    JOptionPane.showMessageDialog(null, "恭喜黑子胜利");
                } else if (color == 2) {
                    JOptionPane.showMessageDialog(null, "恭喜白子胜利");
                }
            }
        }
    }

    @Override
    public void mouseDragged(MouseEvent e) {

    }

    @Override
    public void mouseMoved(MouseEvent e) {

    }
}

  • Pieces
package Gobang;

public class Pieces {
    int x;
    int y;
    int color;
    static int num = 0;
}


  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

G_Y_Chen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值