五子棋-java实现

文章介绍了如何使用Java编程语言,结合Swing库创建一个五子棋游戏的图形界面。代码包括棋盘画板类、配置类、线条类、坐标类、棋子类和辅助类,实现了棋盘绘制、棋子放置和胜利判断等功能。游戏在一方达到指定连珠数时结束,提供了一个简单的交互体验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

突发奇想,使用java来写一个游戏,今日实现的程序为:五子棋。

实现后的效果图

代码实现
五子棋的棋盘画板类
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author jack
 */
public class GoBangBoard extends JPanel {

    private List<LineBean> lineList;
    private List<StrBean> strList;

    public GoBangBoard(List<LineBean> lineList) {
        this.lineList = lineList;
        this.strList = new ArrayList<>();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (LineBean lineBean : lineList) {
            g.drawLine(lineBean.getStartX(), lineBean.getStartY(),
                    lineBean.getEndX(), lineBean.getEndY());
        }
        // 字体高度
        g.setFont(new Font("宋体", Font.PLAIN, 20));
        for (StrBean strBean : strList) {
            g.setColor(strBean.getTextColor());
            g.drawString(strBean.getStr(), strBean.getX() - 10, strBean.getY() - 22);
        }
    }

    public void drawString(String str, int x, int y, Color textColor) {
        strList.add(new StrBean(str, x, y, textColor));
        repaint();
    }
}
五子棋配置类
import lombok.Builder;
import lombok.Data;

/**
 * Description:画板配置
 *
 * @author jack
 * @version 1.0
 */
@Data
@Builder
public class GoBangBoardConfig {

    private GoBangBoardConfig() {}

    private GoBangBoardConfig(int sideCount, int sideLen, int successCount) {
        this.sideCount = sideCount;
        this.sideLen = sideLen;
        this.successCount = successCount;
    }

    /***
     * <p>
     * 横纵格子数
     * </p>
     */
    private int sideCount;
    /***
     * <p>
     * 边长
     * </p>
     */
    private int sideLen;

    /***
     * <p>
     * 成功所需要连的棋子数,譬如五子棋即为5
     * </p>
     */
    private int successCount;
}

线条类
import lombok.Getter;
import lombok.Setter;

/**
 * Description:线条
 *
 * @author jack
 * @version 1.0
 */
@Getter
@Setter
public class LineBean {

    public LineBean(int startX, int startY, int endX, int endY) {
        this.startX = startX;
        this.startY = startY;
        this.endX = endX;
        this.endY = endY;
    }

    private int startX;
    private int startY;
    private int endX;
    private int endY;

    public LineBean add(int borderMargin) {
        this.startX += borderMargin;
        this.startY += borderMargin;
        this.endX += borderMargin;
        this.endY += borderMargin;
        return this;
    }
}

坐标类
import lombok.Getter;
import lombok.Setter;

import java.util.Objects;

/**
 * Description:坐标类
 *
 * @author jack
 * @version 1.0
 */
@Getter
@Setter
public class P {

    private int x;
    private int y;

    public P(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof P)) {
            return false;
        }
        if (this.hashCode() != obj.hashCode()) {
            return false;
        }
        P other = (P) obj;
        return x == other.x && y == other.y;
    }
}

棋子类
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

/**
 * Description:棋子类
 *
 * @author jack
 * @version 1.0
 */
@Getter
@Setter
@Builder
public class Point {

    private Point() {}

    private Point(P p, short state) {
        this.p = p;
        this.state = state;
    }

    private P p;
    /***
     * <p>
     * 棋子的状态
     * 0-空白、1-黑棋、2-白棋
     * </p>
     */
    private short state;
}
字符串绘制类
import lombok.Data;

import java.awt.*;

/**
 * Description:字符串绘制类
 *
 * @author jack
 * @version 1.0
 */
@Data
public class StrBean {

    public StrBean(String str, int x, int y, Color textColor) {
        this.str = str;
        this.x = x;
        this.y = y;
        this.textColor = textColor;
    }

    private String str;
    private int x;
    private int y;
    private Color textColor;
}
五子棋辅助类
import com.jack.game.piece.bean.GoBangBoardConfig;

/**
 * Description:五子棋 辅助类
 *
 * @author jack
 * @version 1.0
 */
public class GoBangHelper {

    private static final int MIN_SUCCESS_COUNT = 5;

    private static final int MIN_SIDE_COUNT = 10;

    private static final int MIN_SIDE_LEN = 400;

    public static int getSuccessCount(GoBangBoardConfig config) {
        return Math.max(MIN_SUCCESS_COUNT, config.getSuccessCount());
    }

    public static int getSideCount(GoBangBoardConfig config) {
        return Math.max(MIN_SIDE_COUNT, config.getSideCount());
    }

    public static int getSideLen(GoBangBoardConfig config) {
        return Math.max(MIN_SIDE_LEN, config.getSideLen());
    }
}
启动逻辑主类
import com.jack.game.piece.bean.*;
import com.jack.game.piece.bean.Point;
import com.jack.game.piece.helper.GoBangHelper;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Description:五子棋
 *
 * @author jack
 * @version 1.0
 */
public class GoBang {

    private static final int TOP = 0;
    private static final int RIGHT_TOP = 1;
    private static final int RIGHT = 2;
    private static final int RIGHT_BOTTOM = 3;
    private static final int BOTTOM = 4;
    private static final int LEFT_BOTTOM = 5;
    private static final int LEFT = 6;
    private static final int LEFT_TOP = 7;
    private static final List<Integer> DIR_LIST;

    /***
     * <p>
     * 空白
     * </p>
     */
    private static final short BLANK_STATE = 0;
    /***
     * <p>
     * 黑棋
     * </p>
     */
    private static final short BLACK_STATE = 1;
    /***
     * <p>
     * 白棋
     * </p>
     */
    private static final short WHITE_STATE = 2;

    private static final short[] STATE_ARR;
    private static final String[] TEXT_ARR;
    private static final Color[] TEXT_COLOR_ARR;

    /***
     * <p>
     * 当前回合的状态
     * </p>
     */
    private int curStateStartOffset = 0;

    private static final Map<Short, String> SUCCESS_MSG_MAP;

    static {
        DIR_LIST = new ArrayList<>();
        DIR_LIST.add(TOP);
        DIR_LIST.add(RIGHT_TOP);
        DIR_LIST.add(RIGHT);
        DIR_LIST.add(RIGHT_BOTTOM);
        DIR_LIST.add(BOTTOM);
        DIR_LIST.add(LEFT_BOTTOM);
        DIR_LIST.add(LEFT);
        DIR_LIST.add(LEFT_TOP);

        SUCCESS_MSG_MAP = new HashMap<>();
        SUCCESS_MSG_MAP.put(BLACK_STATE, "恭喜黑棋方胜利!");
        SUCCESS_MSG_MAP.put(WHITE_STATE, "恭喜白棋方胜利!");

        STATE_ARR = new short[]{BLACK_STATE, WHITE_STATE};
        TEXT_ARR = new String[]{"●", "●"};
        TEXT_COLOR_ARR = new Color[] {Color.BLACK, Color.WHITE};
    }

    /***
     * <p>
     * 所有点
     * </p>
     */
    private Point[][] allPointArr;

    /***
     * <p>
     * 灵敏距离范围
     * </p>
     */
    private double allowLenRange;

    /***
     * <p>
     * 2个棋子之间的间隔
     * </p>
     */
    private double interval;

    private int sideCount;
    private int sideLen;
    private int successCount;

    private boolean isOver = false;

    public GoBang(GoBangBoardConfig boardConfig) {
        successCount = GoBangHelper.getSuccessCount(boardConfig);
        sideCount = GoBangHelper.getSideCount(boardConfig);
        allPointArr = new Point[sideCount][sideCount];
        sideLen = GoBangHelper.getSideLen(boardConfig);
        interval = sideLen * 1.0 / (sideCount - 1);
        allowLenRange = interval / 3;
        for (int i = 0; i < sideCount; i++) {
            int x = (int) (i * interval);
            for (int j = 0; j < sideCount; j++) {
                int y = (int) (j * interval);
                P p = new P(x + BORDER_MARGIN, y + BORDER_MARGIN + Y_BORDER_MARGIN);
                Point point = Point.builder()
                        .p(p)
                        .state(BLANK_STATE)
                        .build();
                allPointArr[i][j] = point;
            }
        }
    }

    private static final int BORDER_MARGIN = 30;
    private static final int Y_BORDER_MARGIN = 30;

    public void showGraph() {
        JFrame jFrame = new JFrame();
        List<LineBean> lineList = new ArrayList<>();
        for (int i = 0; i < sideCount; i++) {
            int x = (int) (i * interval);
            lineList.add(new LineBean(x, 0, x, sideLen).add(BORDER_MARGIN));
        }
        for (int i = 0; i < sideCount; i++) {
            int y = (int) (i * interval);
            lineList.add(new LineBean(0, y, sideLen, y).add(BORDER_MARGIN));
        }
        GoBangBoard goBangBoard = new GoBangBoard(lineList);
        jFrame.add(goBangBoard);

        jFrame.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (!isOver) {
                    clickPoint(e.getX(), e.getY(), goBangBoard);
                }
            }
        });
        jFrame.setSize(sideLen + BORDER_MARGIN * 2,
                sideLen + BORDER_MARGIN * 2 + Y_BORDER_MARGIN);
        jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        jFrame.setVisible(true);
    }

    private void clickPoint(int clickX, int clickY, GoBangBoard goBangBoard) {
        short state = STATE_ARR[curStateStartOffset];
        P p = getClickP(clickX, clickY);
        if (p == null) {
            // 点击的不在灵敏度范围内
            return;
        }
        int offsetX = transPosX(p.getX());
        int offsetY = transPosY(p.getY());
        Point curPoint = allPointArr[offsetX][offsetY];
        if (curPoint.getState() != BLANK_STATE) {
            // 该点已用
            return;
        }
        curPoint.setState(state);
        // 刷新渲染
        goBangBoard.drawString(TEXT_ARR[curStateStartOffset], p.getX(), p.getY(), TEXT_COLOR_ARR[curStateStartOffset]);
        // 检查是否成功
        if (checkCurSuccess(curPoint, offsetX, offsetY)) {
            isOver = true;
            System.out.println(SUCCESS_MSG_MAP.get(state));
            JOptionPane.showMessageDialog(goBangBoard, SUCCESS_MSG_MAP.get(state));
        }
        curStateStartOffset = (curStateStartOffset + 1) % STATE_ARR.length;
    }

    private boolean checkCurSuccess(Point curPoint, int offsetX, int offsetY) {
        short state = curPoint.getState();
        if (state == BLANK_STATE) {
            // 空白
            return false;
        }
        // 检查当前点周围是否满足
        int[] countArr = new int[DIR_LIST.size()];
        for (int dir : DIR_LIST) {
            // 得减去自身
            countArr[dir] = getAroundCount(offsetX, offsetY, state, dir) - 1;
        }
        if (countArr[TOP] + countArr[BOTTOM] == successCount - 1) {
            // 竖向成功
            return true;
        }
        if (countArr[LEFT] + countArr[RIGHT] == successCount - 1) {
            // 横向成功
            return true;
        }
        if (countArr[LEFT_TOP] + countArr[RIGHT_BOTTOM] == successCount - 1) {
            // 左上-右下向成功
            return true;
        }
        // 左下-右上向成功
        return countArr[LEFT_BOTTOM] + countArr[RIGHT_TOP] == successCount - 1;
    }

    private int getAroundCount(int x, int y, short state, int dir) {
        Point point = allPointArr[x][y];
        short curState = point.getState();
        if (curState == state) {
            // 同色棋子
            int offsetX;
            int offsetY;
            switch (dir) {
                case TOP:
                    // 上
                    offsetX = x;
                    offsetY = y - 1;
                    break;
                case RIGHT_TOP:
                    // 右上
                    offsetX = x + 1;
                    offsetY = y - 1;
                    break;
                case RIGHT:
                    // 右
                    offsetX = x + 1;
                    offsetY = y;
                    break;
                case RIGHT_BOTTOM:
                    // 右下
                    offsetX = x + 1;
                    offsetY = y + 1;
                    break;
                case BOTTOM:
                    // 下
                    offsetX = x;
                    offsetY = y + 1;
                    break;
                case LEFT_BOTTOM:
                    // 左下
                    offsetX = x - 1;
                    offsetY = y + 1;
                    break;
                case LEFT:
                    // 左
                    offsetX = x - 1;
                    offsetY = y;
                    break;
                case LEFT_TOP:
                    // 左上
                    offsetX = x - 1;
                    offsetY = y - 1;
                    break;
                default:
                    return 1;
            }
            if (isValidOffset(offsetX, offsetY)) {
                return getAroundCount(offsetX, offsetY, curState, dir) + 1;
            }
            return 1;
        } else {
            // 不同色
            return 0;
        }
    }

    private boolean isValidOffset(int offsetX, int offsetY) {
        int max = allPointArr.length;
        return offsetX >= 0 && offsetX < max && offsetY >= 0 && offsetY < max;
    }

    /***
     * <p>
     * 通过坐标找到最近的点
     * </p>
     * @author jack
     *
     * @param realX 点击的实际点 x
     * @param realY 点击的实际点 y
     * @return com.jack.game.piece.bean.P
     */
    private P getClickP(int realX, int realY) {
        double margin = Integer.MAX_VALUE;
        int resX = realX;
        int resY = realY;
        for (Point[] points : allPointArr) {
            for (Point point : points) {
                int x = point.getP().getX();
                int y = point.getP().getY();
                if (realX == x && realY == y) {
                    return new P(resX, resY);
                }
                int marginX = Math.abs(x - realX);
                int marginY = Math.abs(y - realY);
                double tmp = Math.sqrt(marginX * marginX + marginY * marginY);
                if (tmp < margin) {
                    margin = tmp;
                    resX = x;
                    resY = y;
                }
            }
        }
        if (margin > allowLenRange) {
            // 最接近的也不在灵敏范围内
            // 不识别为坐标点
            return null;
        }
        return new P(resX, resY);
    }

    private int transPosX(int realX) {
        return (int) (Math.ceil((realX - BORDER_MARGIN) / interval));
    }

    private int transPosY(int realY) {
        return (int) (Math.ceil((realY - BORDER_MARGIN - Y_BORDER_MARGIN) / interval));
    }
}
启动调用代码

简单一句即可

new GoBang(GoBangBoardConfig.builder().build()).showGraph();
结语

到此一个简单的五子棋程序便实现完成了,启动后,黑白双方交互下棋,有一人胜利即结束,程序为版本一,有诸多地方和功能能够更好的改进,欢迎留言交流!

如果您看到了这里,欢迎和我沟通交流!
             一个95后码农

个人博客:fy-blog

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值