0
点赞
收藏
分享

微信扫一扫

五子棋游戏的简单实现(Java入门小游戏手把手教学)

星巢文化 2022-03-30 阅读 64

##五子棋*
需求分析
完成一个简单的五子棋游戏

界面

  1. 窗体【带标题和背景】
  2. 棋盘【棋盘,棋子】
  3. 图标【白子,黑子,重来】

业务

  1. 页面展示
  2. 选择先走的棋子
  3. 落子开始下棋
  4. 黑白切换
  5. 判断输赢,如何判断赢了
  6. 重来

模型

  1. 棋子
  2. 棋盘
  3. 位置
  4. 状态数据

架构

  1. 视图(View):展示界面
  2. 控制器|处理器(Controller):处理请求,动作,处理数据
  3. 模型(Model):数据存储
  4. 常量(Constant):保存固定数据
  5. 测试(Test):每一步都应该测试,确保正确性

**
实现

  1. 新建包、准备资源、工具类、模型

资源

  1. 静态资源,图片,音频等

工具类

package com.example.constant
    public class Constant {
        //窗口宽高
        public static  final int WINDOW_W = 800;
        public static  final int WINDOW_H = 650;
        //窗口位置
        public static  final int WINDOW_X = 300;
        public static  final int WINDOW_Y = 200;
        
        //棋盘格子边长
        public static  final int NODE_W = 30;
        //棋子路径
        public static  final String WHITE_PATH = "images/白子.png";
        public static  final String BLACK_PATH = "images/黑子.png";
        //落子半径
        public static  final  int R = 12;
        
        //棋子边长
        public static final int PIECE_W = 24;
        
        //图标宽高
        public static  final int ICON_W = 120;
        public static  final int ICON_H = 60;
        
        //图标的位置
        public static  final int WHITE_ICON_X = WINDOW_X - 150;
        public static  final int WHITE_ICON_Y = 150;
        public static  final int BLACK_ICON_X = WINDOW_X - 150;
        public static  final int  BLACK_ICON_Y = 250;
        public static  final int START_ICONX = WINDOW_X - 150;
        public static  final int START_ICONy = 350;
        
        //图标路径
        public  static  final  String WHITE_ICON = "images/白子.png";
        public  static  final  String BLCK_ICON = "images/黑子.png";
        public  static  final  String RESTART_ICON = "images/重来png";
        
        
        public  static  final  int BLACK = -1;
        public  static  final  int WHITE = 1;
        public  static  final  int NONE = 0;
        
        
}

模型

  1. Postion:每一个棋子的位置【在二维数组中的行列】
  2. Node:棋盘中的每一个格子【同时也映射棋子】
  3. CheckerBoard:棋盘
  4. Stamp:状态类,游戏是否开始,该谁下,检查当前落子是否赢得比赛

视图和控制器

基本界面
只提供最基本的窗体和静态内容的展示【棋盘,图标】,后期可以有选择的重绘整个棋盘
在这里插入图片描述

BaseFrame

package view;

import controller.BaseFrameController;
import util.Constant;

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;

/*
* 基本窗体
*  显示初始内容
*  设置:位置,大小,标题,背景*/
public class BaseFrame extends JFrame {
    BaseFrameController baseFrameController = new BaseFrameController();

    //窗体初始化
    public  BaseFrame(){
        super.setLocation(Constant.WINDOW_X,Constant.WINDOW_Y);//位置
        super.setSize(Constant.WINDOW_W,Constant.WINDOW_H);//大小
        super.setTitle("五子棋");//标题
        super.setBackground(new Color(255,255,255)); //BG COLOR
        super.setResizable(false);
        super.setVisible(true);
        super.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0); //退出程序
            }
        });

    }
/*绘制窗体内容
* 图标*/

    @Override
    public void paint(Graphics g) {
        baseFrameController.paintCheckerBoarad(g);
        try {
            baseFrameController.paintIcon(g);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
基本控制器Basectroller

```java
package controller;
/*
* 基本界面的处理
* 绘制棋盘
* 绘制图表*/

import model.CheckerBoard;
import model.Node;
import util.Constant;

import javax.imageio.ImageIO;
import java.awt.*;
import java.io.File;
import java.io.IOException;

public class BaseFrameController {
    //绘制棋盘
    //遍历棋盘 利用棋子自身的绘制工能将自己展示
    public void  paintCheckerBoarad (Graphics g){
        for (Node[] nodes : CheckerBoard.checkerboard) {
            for (Node node:nodes){
                node.drawNode(g);
            }

        }

    }
    /*画图标
    * 白子
    * 黑子
    * 重来
    * 数据在常量类中【路径】【大小】【位置】*/
    public void  paintIcon(Graphics g) throws IOException {
        //白子 黑子 重来图标
        Image whiteImage = ImageIO.read(new File(Constant.WHITE_ICON));
        Image blackImage = ImageIO.read(new File(Constant.BLCK_ICON));
        Image start = ImageIO.read((new File(Constant.RESTART_ICON)));

        g.drawImage(whiteImage,Constant.WHITE_ICON_X,Constant.WHITE_ICON_Y,Constant.ICON_W,Constant.ICON_H,null);
        g.drawImage(blackImage,Constant.BLACK_ICON_X,Constant.BLACK_ICON_Y,Constant.ICON_W,Constant.ICON_H,null);
        g.drawImage(start,Constant.START_ICONX,Constant.START_ICONy,Constant.ICON_W,Constant.ICON_H,null);



    }


}

``主界面和处理

  1. 在主界面中增加接收用户的点击操作【选先手开始游戏】
    在这里插入图片描述
    2.落子操作
    遍历数组
    在落子之后去确定前后的距离是否有连续5颗棋子
    在这里插入图片描述
    4.是否胜利
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    遍历check 4个方向
private boolean isWin(Node node){
        if(horizon()){
            System.out.println("水平方向胜利");
            return true;
        }

        if(vertical()){
            System.out.println("垂直方向胜利");
            return true;
        }
        if(lurd()){
            System.out.println("左上方向胜利");
            return true;
        }
        if(ldru()){
            System.out.println("左上方向胜利");
            return true;
        }
        return false;


    }
    /*水平方向判断
    * 找到起始位置
    * 找到终止点*/
    private boolean horizon(){
        Node node = Stamp.getCurrent();
        //当前点的位置信息
        Postion postion = Stamp.getCurrent().getPostionl();
        int fd = frontDistance(postion.getCol());
        int bd = backDistance(postion.getCol());
        //起始列
        int start = postion.getCol() - fd;
        //终止列
        int end = postion.getCol() + bd;
        //同一行
        int row = postion.getRow();
        int count  = 0;
        for(int i = start;i<=end;i++){
            if(node.getValue() != CheckerBoard.checkerboard[row][i].getValue()){
                count = 0;
            }else {
                //如果有5可连续棋子 ,赢了
                count++;
                if(count == 5){
                    return  true;
                }
            }
        }
        return  false;
    }
    /*垂直方向是否胜利*/
    private  boolean vertical(){
        Node node = Stamp.getCurrent();
        //当前点的位置信息
        Postion postion = Stamp.getCurrent().getPostionl();
        int fd = frontDistance(postion.getRow());
        int bd = backDistance(postion.getRow());
        //起始行
        int start = postion.getRow() - fd;
        //中支行
        int end = postion.getRow() + bd;
        //相同列
        int col =postion.getCol();
        int count = 0;
        for (int i = start; i <= end ; i++) {
           if(node.getValue()!=CheckerBoard.checkerboard[i][col].getValue()){
               count =  0;

           }else {
               count++;
               if(count == 5){
                   return true;

               }

           }

        }
        return  false;
    }

    /*
    * 左上右下的胜利判断
    * 1.前面的距离【x小,y小】取小距离
    * 2.后面的距离【x打,y大】取小距离*/
    private boolean lurd(){
        Node node = Stamp.getCurrent();
        //当前点的位置信息
        Postion postion = Stamp.getCurrent().getPostionl();
        //行前边距离
        int fdRow = frontDistance(postion.getRow());
        //行的后边距离
        int bdRow = backDistance(postion.getRow());
        //列的前后距离
        int fdCol = frontDistance(postion.getCol());
        int bdCol = backDistance(postion.getCol());
        //以行作为标准
        //行向前 列向后
        int fd = Math.min(fdRow,bdCol);
        //行向后 列向前
        int bd = Math.min(bdRow,fdCol);



        //行的起始位置

        int startrow = postion.getRow() - fd;
        //行的截止位置
        int endrow = postion.getRow() + bd;
        //列的起始位置
        int startcol = postion.getCol() + fd;
        //列的截止为止
        int endcol = postion.getCol() - bd;

        int count = 0;
        for(int row =startrow,col =startcol;row<=endrow && col<=endcol;row++,col++){
            if(node.getValue() != CheckerBoard.checkerboard[row][col].getValue()){
                count = 0;
            }else {
                count++;
                if(count == 5){
                    return true;
                }
            }

        }
        return false;
    }
    /*
     * 左下右上的胜利判断
     * 1.前面的距离【x小,y小】取小距离
     * 2.后面的距离【x打,y大】取小距离*/

    private boolean ldru(){
        Node node = Stamp.getCurrent();
        //当前点的位置信息
        Postion postion = Stamp.getCurrent().getPostionl();
        //行前边距离
        int fdRow = frontDistance(postion.getRow());
        //行的后边距离
        int bdRow = backDistance(postion.getRow());
        //列的前后距离
        int fdCol = frontDistance(postion.getCol());
        int bdCol = backDistance(postion.getCol());
        //取前边小值
        int fd = Math.min(fdRow,bdCol);
        int bd = Math.min(bdRow,fdCol);

        //行的起始位置

        int startrow = postion.getRow() - fd;
        //行的截止位置
        int endrow = postion.getRow() + bd;
        //列的起始位置
        int startcol = postion.getCol() + fd;
        //列的截止为止
        int endcol = postion.getCol() - bd;

        int count = 0;
        for(int row =startrow,col =startcol;row<=endrow && col>=endcol;row++,col--){
            if(node.getValue() != CheckerBoard.checkerboard[row][col].getValue()){
               count = 0;
            }else {
                count++;
                if(count == 5){
                    return true;
                }
            }

        }
        return false;
    }
    /*通过中间值去找起始值
    * mid
    * */
    private int frontDistance(int mid){
        return mid>4?mid -1:mid;
    }
    private int backDistance(int mid){
        int len = CheckerBoard.checkerboard.length;
        return mid + 4 <len?4:len - mid -1;
    }

5.胜利了
设置状态标记 , 此时赢了
该落子落子

落子后检查是否有赢得标记,如果有,则将状态回到最初【游戏初始化】,赢了标记留着没有开始,又是有人赢,必须要点击start才能选先手
重来

mainFrame

package view;

import controller.MainFrameController;
import model.Stamp;
import util.Constant;

import javax.swing.plaf.synth.SynthOptionPaneUI;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;

/*
* 直接继承窗体
* 主界面
* 1.监听用户点击事件*/
public class MainFrame extends BaseFrame{
    //创建处理器
    MainFrameController mainFrameController = new MainFrameController();

    public MainFrame(){
       //添加鼠标事件监听
        super.addMouseListener(new MouseAdapter() {
            //单机事件的处理
            @Override
            public void mouseClicked(MouseEvent e) {
                //获取点击位置
                Point point = e.getPoint();

                if(!Stamp.isGamestart()){
                    if(!Stamp.isWin()) {


                        //选先手,开始游戏
                        mainFrameController.chooseStart(point);
                    }else {
                        if (mainFrameController.reply(point)) {
                            repaint();
                        }
                    }

                }else{
                    //游戏开始 落子操作
                   boolean  flag =  mainFrameController.palcing(point);

                    repaint();
                }
            }
        });
    }

    @Override
    public void paint(Graphics g) {
        if(!Stamp.isGamestart()) {
            //清空窗口
            g.clearRect(0,0,Constant.WINDOW_W,Constant.WINDOW_H);
            System.out.println("清空");
            super.paint(g);
        }


        if(Stamp.isGamestart() && Stamp.getCurrent()!= null) {
            //绘制落子
            try {
                Stamp.getCurrent().playNode(g);
                if(Stamp.isWin()){
                    mainFrameController.mesg(g);

                    //所有状态初始化
                    mainFrameController.init();
                    System.out.println("重来");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

MainFrameController

package controller;

import model.CheckerBoard;
import model.Node;
import model.Postion;
import model.Stamp;
import util.Constant;

import java.awt.*;



/*
* 主界面操作处理
* */
public class MainFrameController extends  BaseFrameController {
    //用来选先手方法 开始游戏
    //根据坐标 判断点击的是那个一个图标【白,黑】
    //修改状态开始游戏
    public void chooseStart(Point point) {
        //选择白子 白色先手
        if (Constant.WHITE_ICON_X <= point.x && point.x <= Constant.WHITE_ICON_X + Constant.ICON_W &&
                Constant.WHITE_ICON_Y <= point.y && point.y <= Constant.WHITE_ICON_Y + Constant.ICON_H) {
            Stamp.setGamestart(true);
            Stamp.setWhich(1);
            return;
        }
        //选择黑色 黑子先手
        if (Constant.BLACK_ICON_X <= point.x && point.x <= Constant.BLACK_ICON_X + Constant.ICON_W &&
                Constant.BLACK_ICON_Y <= point.y && point.y <= Constant.BLACK_ICON_Y + Constant.ICON_H) {
            Stamp.setGamestart(true);
            Stamp.setWhich(-1);
            return;
        }
    }

    /*
     * 落子操作
     * 1.能否落子
     * 2.更改状态*/
    public boolean palcing(Point point) {
        Node node = findNode(point);
        //如果有有合适的就更改状态
        if (node != null) {
            node.setValue(Stamp.getWhich());
            if (node.getValue() == Constant.WHITE) {
                node.setPath(Constant.WHITE_PATH);
                System.out.println("白色");

            } else if (node.getValue() == Constant.BLACK) {
                node.setPath(Constant.BLACK_PATH);
                System.out.println("黑色");
            }
            Stamp.setCurrent(node);
            //落子结束
            //判断是否胜利
            if(isWin(node)){
                Stamp.setWin(true);//设置赢了的标记
                String str;
                if(node.getValue() == Constant.WHITE){
                    str = "白色";
                }else{
                     str = "黑色";
                }
                System.out.println(str +"赢了");
            }else {
                Stamp.setWhich(Stamp.getWhich() * -1);
            }


            return true;
        }
        return false;
    }
    /*判断是否胜利
    * 横向
    * 竖向
    * 左上
    * 右上*/
    private boolean isWin(Node node){
        if(horizon()){
            System.out.println("水平方向胜利");
            return true;
        }

        if(vertical()){
            System.out.println("垂直方向胜利");
            return true;
        }
        if(lurd()){
            System.out.println("左上方向胜利");
            return true;
        }
        if(ldru()){
            System.out.println("左上方向胜利");
            return true;
        }
        return false;


    }
    /*水平方向判断
    * 找到起始位置
    * 找到终止点*/
    private boolean horizon(){
        Node node = Stamp.getCurrent();
        //当前点的位置信息
        Postion postion = Stamp.getCurrent().getPostionl();
        int fd = frontDistance(postion.getCol());
        int bd = backDistance(postion.getCol());
        //起始列
        int start = postion.getCol() - fd;
        //终止列
        int end = postion.getCol() + bd;
        //同一行
        int row = postion.getRow();
        int count  = 0;
        for(int i = start;i<=end;i++){
            if(node.getValue() != CheckerBoard.checkerboard[row][i].getValue()){
                count = 0;
            }else {
                //如果有5可连续棋子 ,赢了
                count++;
                if(count == 5){
                    return  true;
                }
            }
        }
        return  false;
    }
    /*垂直方向是否胜利*/
    private  boolean vertical(){
        Node node = Stamp.getCurrent();
        //当前点的位置信息
        Postion postion = Stamp.getCurrent().getPostionl();
        int fd = frontDistance(postion.getRow());
        int bd = backDistance(postion.getRow());
        //起始行
        int start = postion.getRow() - fd;
        //中支行
        int end = postion.getRow() + bd;
        //相同列
        int col =postion.getCol();
        int count = 0;
        for (int i = start; i <= end ; i++) {
           if(node.getValue()!=CheckerBoard.checkerboard[i][col].getValue()){
               count =  0;

           }else {
               count++;
               if(count == 5){
                   return true;

               }

           }

        }
        return  false;
    }

    /*
    * 左上右下的胜利判断
    * 1.前面的距离【x小,y小】取小距离
    * 2.后面的距离【x打,y大】取小距离*/
    private boolean lurd(){
        Node node = Stamp.getCurrent();
        //当前点的位置信息
        Postion postion = Stamp.getCurrent().getPostionl();
        //行前边距离
        int fdRow = frontDistance(postion.getRow());
        //行的后边距离
        int bdRow = backDistance(postion.getRow());
        //列的前后距离
        int fdCol = frontDistance(postion.getCol());
        int bdCol = backDistance(postion.getCol());
        //以行作为标准
        //行向前 列向后
        int fd = Math.min(fdRow,fdCol);
        //行向后 列向前
        int bd = Math.min(bdRow,bdCol);



        //行的起始位置

        int startrow = postion.getRow() - fd;
        //行的截止位置
        int endrow = postion.getRow() + bd;
        //列的起始位置
        int startcol = postion.getCol() - fd;
        //列的截止为止
        int endcol = postion.getCol() + bd;

        int count = 0;
        for(int row =startrow,col =startcol;row<=endrow && col<=endcol;row++,col++){
            if(node.getValue() != CheckerBoard.checkerboard[row][col].getValue()){
                count = 0;
            }else {
                count++;
                if(count == 5){
                    return true;
                }
            }

        }
        return false;
    }
    /*
     * 左下右上的胜利判断
     * 1.前面的距离【x小,y小】取小距离
     * 2.后面的距离【x打,y大】取小距离*/

    private boolean ldru(){
        Node node = Stamp.getCurrent();
        //当前点的位置信息
        Postion postion = Stamp.getCurrent().getPostionl();
        //行前边距离
        int fdRow = frontDistance(postion.getRow());
        //行的后边距离
        int bdRow = backDistance(postion.getRow());
        //列的前后距离
        int fdCol = frontDistance(postion.getCol());
        int bdCol = backDistance(postion.getCol());
        //取前边小值
        int fd = Math.min(fdRow,bdCol);
        int bd = Math.min(bdRow,fdCol);

        //行的起始位置

        int startrow = postion.getRow() - fd;
        //行的截止位置
        int endrow = postion.getRow() + bd;
        //列的起始位置
        int startcol = postion.getCol() + fd;
        //列的截止为止
        int endcol = postion.getCol() - bd;

        int count = 0;
        for(int row =startrow,col =startcol;row<=endrow && col>=endcol;row++,col--){
            if(node.getValue() != CheckerBoard.checkerboard[row][col].getValue()){
               count = 0;
            }else {
                count++;
                if(count == 5){
                    return true;
                }
            }

        }
        return false;
    }
    /*通过中间值去找起始值
    * mid
    * */
    private int frontDistance(int mid){
        return mid>4?mid -1:mid;
    }
    private int backDistance(int mid){
        int len = CheckerBoard.checkerboard.length;
        return mid + 4 <len?4:len - mid -1;
    }






    /*找合适落子的位置
     * 遍历整个棋盘
     * */
    private Node findNode(Point point) {
        for (Node[] nodes : CheckerBoard.checkerboard) {
            for (Node node : nodes) {
                if (node.clickNode(point.x, point.y) && node.getValue() == Constant.NONE) {
                    return node;
                }
            }
        }
        return null;

    }

    /*将所有标记重置*/
    public void init() {
        Stamp.setWhich(Constant.NONE);
        Stamp.setGamestart(false);

        for (Node[] nodes : CheckerBoard.checkerboard) {
            for (Node node : nodes) {
                node.setPath(null);
                node.setValue(0);


            }

        }
    }

    public boolean reply(Point point) {
        if(Constant.START_ICONX <= point.x && point.x <= Constant.START_ICONX+ Constant.ICON_W &&
           Constant.START_ICONy <= point.y && point.y <= Constant.START_ICONy + Constant.ICON_H){
           Stamp.setWin(false);
            return  true;

        }
        return  false;
    }

    /*
    * 给出提示
    * */

    public void mesg(Graphics g) {

        String msg;
        if(Stamp.getWhich() == 1){
            msg = "白方获胜,大笨蛋";
        }else {
            msg = "黑色赢了,大白痴";
        }

        g.setFont(new Font("微软雅黑",Font.BOLD,45));
        g.drawString(msg,150,400);
    }
}

游戏效果
在这里插入图片描述

需要源码留邮箱。。。

举报

相关推荐

0 条评论