展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > 怎么用Java实现中国象棋游戏

怎么用Java实现中国象棋游戏

一、界面下棋的棋盘首先要准备好,这就是一个合适大小合适比例合适位置的界面,然后在窗体上画上(没错drawLine的那种画上)n条直线和斜线,具体数值根据你的界面大小设置。这样画出的界面整齐好看~publicvoidpaint(Graphicsg){super.paint(g);//重写画图函数Fontf=newFont("微软雅黑",Font.BOLD,30);g.setFont(f);g.drawRect(60,50,500,560);//外圈g.drawRect(70,60,480,540);//内圈

本文目录

    一、界面

    下棋的棋盘首先要准备好,这就是一个合适大小合适比例合适位置的界面,然后在窗体上画上(没错drawLine的那种画上)n条直线和斜线,具体数值根据你的界面大小设置。这样画出的界面整齐好看~

    public void paint(Graphics g){
            
            super.paint(g);//重写画图函数
            Font f=new Font("微软雅黑",Font.BOLD,30);
            g.setFont(f);
            
            g.drawRect(60, 50, 500, 560);//外圈
            g.drawRect(70, 60, 480, 540);//内圈
            //横线部分
            int length=60;
            for(int i=0;i<9;i++){
                g.drawLine(70, length, 550, length);
                length+=60;
            }
            //中间汉字
            g.drawString("楚河", 160, 340);
            g.drawString("汉界", 400, 340);
            //竖线部分
            length=130;
            for(int i=0;i<7;i++){
                //上半部分竖线
                g.drawLine( length,60, length,300);
                //下半部分竖线
                g.drawLine( length,360, length,600);
                length+=60;
            }
            //上半部分九宫格斜线
            g.drawLine(250, 60, 370, 180);
             g.drawLine(370, 60, 250, 180);
             //下半部分九宫格斜线
             g.drawLine(250, 480, 370, 600);
             g.drawLine(250, 600, 370, 480);
         
        }

    二、按钮

    画好棋盘之后加上功能按钮,这个时候的功能暂时不考虑实现,可以根据喜好随意添加。这里推荐将按钮类型设置成数组,便于及时增删。

    //添加到面板上
            String[] type = {"开始游戏","重新开始","认 输","悔 棋"};
            for(int i=0;i

    怎么用Java实现中国象棋游戏

    这个时候你会发现在加按钮的地方贴的十分紧凑,我的解决办法是在这一块面板上再加一个面板设置为白色覆盖在上面,这样根据面板的流式布局按钮就会下移,调整空白面板的宽度可以改变按钮的位置。

    三、加棋子

    将找到的棋子图片加到棋盘交叉的位置上才是给棋盘注入灵魂,将所有的十四类图片加到package中以便程序之后可以在其他电脑上运行(这里推荐png格式,jpg格式会有方形边框)。
    接下来分三步走

    1.创建一个10行9列的整数数组,用来存储每个位置的数据;
    2.创建一个长度为14的Image数组,用来与棋子类型对应;
    3.遍历整数数组画出对应的棋子;

    这是棋盘的直观图,也就是我们的整数数组的初始值:

    怎么用Java实现中国象棋游戏

    将Image与棋子图片对应:

    //初始化给每个chess定义
            for(int k=0; k<14; k++){
                chess[k] = new ImageIcon(this.getClass().getResource((k+1)+".png")).getImage();
            }

    遍历画图:

    //根据棋盘布局
            for(int i=0;i0){
                        bg.drawImage(chess[place[i][j]-1], chessX+60*j, chessY+60*i, 50, 50, null); 
                    }
                }
            }

    四、实现棋子的移动

    通过函数获得鼠标拖动前后两个点所代表的棋盘上的位置,并将这两个位置的二维数组的值交换,然后重新绘图实现棋子的移动。

    int x1, y1, x2, y2;
    public void mousePressed(MouseEvent e) {
            
                x1 = e.getX();
                y1 = e.getY();
                x1 = getj(x1);
                y1 = geti(y1);
        }
        public void mouseReleased(MouseEvent e) {
            
                x2 = e.getX();
                y2 = e.getY();
                x2 = getj(x2);
                y2 = geti(y2);
        }
        //根据点的坐标得到其代表的位置,具体参数可以微调,我的格子是60x60大小
        public int getj(int x){
            return (x-50)/60;
        }
        public int geti(int y){
            return (y-40)/60;
        }

    这个时候遇到的状况就是你每次移动一次之后,整个界面都要重绘一次,而画面是直接画在窗体上的,数据会直接传到电脑硬件,这样一来画图速度就慢了,所以会出现每走一步界面就闪烁一次的情况,这种情况下,我们可以将画面先存在缓存中,就不经过硬件直接画出来,这样效率就可以明显提高。

    BufferedImage buffer = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB);
    Graphics bg = buffer.getGraphics();
    
    //这个中间写的是你画界面的方法,也就是上面提到的paint方法内部
    //......
    
    //绘制缓存到窗体上
    g.drawImage(buffer, 0, 0, null);

    五、判断胜负

    率先吃掉对方帥或将的队伍获胜,写一个函数判断谁胜谁负显示胜局,同时将数据初始化为0,准备再来一局:
    (showMessageDialog方法可以直接跳出一个框)

    //判断游戏结束并显示胜局
    public void isWine() {
            
            System.out.println(place[y1][x1]+" "+place[y2][x2]);
            if (place[y2][x2]==7&&place[y1][x1]!=0) {
                place[y2][x2] = place[y1][x1];
                place[y1][x1] = 0;
                UI.repaint();
                JOptionPane.showMessageDialog(null, "黑方  胜利!");
                again();
            } else if(place[y2][x2]==14&&place[y1][x1]!=0) {
                place[y2][x2] = place[y1][x1];
                place[y1][x1] = 0;
                UI.repaint();
                JOptionPane.showMessageDialog(null, "红方  胜利!");
                again();
            }
        }
        //游戏结束时要重绘
        public void again(){
              for(int i=0; i

    六、按钮“开始游戏”和“重新开始”的实现

    加动作监听器

    public void actionPerformed(ActionEvent e) {
            
            type = e.getActionCommand();
            if("开始游戏".equals(type)||"重新开始".equals(type)){
                x=0;
                count = 1;//这里要把每次的走棋方刷新,认输时也需要刷新
                init();
                UI.repaint();
            }
        }
        //初始化place坐标
        public void init(){
    
            /*红兵 1.png
             *红炮 2.png
             *红車 3.png
             *红马 4.png
             *红相 5.png
             *红仕 6.png
             *红帥 7.png
             *黑卒 8.png
             *黑炮 9.png
             *黑車 10.png
             *黑马 11.png
             *黑象 12.png
             *黑士 13.png
             *黑将 14.png
             */
            
                
            for(int i=0;i

    这里的init函数是给整数二维数组初始化为开局后遍历可以加上棋子的状态。

    七、加规则

    //规定各个棋子的移动规则
    public boolean rule(int gi, int gj,int si, int sj){
            int x = place[gi][gj];
            int y = place[si][sj];
            int start, end;
            
            //判断为何种棋子
            //車:只能走直线
            if(x == 3||x == 10){
                
                if(gi != si&&gj != sj)    return false;
                else if(gi == si){
                    start = Math.min(gj, sj);
                    end = Math.max(gj, sj);
                    for(int m = 1; m < end - start; m++){
                        if(place[gi][start+m] != 0)    return false;
                    }
                    return true;
                }
                else if(gj == sj){
                    start = Math.min(gi, si);
                    end = Math.max(gi, si);
                    for(int m = 1; m < end - start; m++){
                        if(place[start+m][gj] != 0)    return false;
                    }
                    return true; 
                }
                else return true;
            }
            //马:走日,且某个位置不可以有棋子
            else if(x == 4||x == 11){
                //下
                if(si - gi == 2&&Math.abs(gj-sj) == 1&&place[gi+1][gj] == 0)    return true;
                //上
                else if(gi - si == 2&&Math.abs(gj-sj) == 1&&place[gi-1][gj] == 0)    return true;
                //右
                else if(sj - gj == 2&&Math.abs(gi-si) == 1&&place[gi][gj+1] == 0)    return true;
                //左
                else if(gj - sj == 2&&Math.abs(gi-si) == 1&&place[gi][gj-1] == 0)    return true;
                //否则不可以走
                else return false;
            }
            //相:走田,且不能过河
            else if(x == 5||x == 12){
                //左上
                if(gi - si == 2&&gj - sj == 2&&place[gi-1][gj-1] == 0){
                    
                    if((x == 5&&si >= 5)||(x == 12&&si < 5))    return true;
                    else return false;
                }
                //右上
                else if(gi - si == 2&&sj - gj == 2&&place[gi-1][gj+1] == 0){
                    
                    if((x == 5&&si >= 5)||(x == 12&&si < 5))    return true;
                    else return false;
                }
                //左下
                else if(si - gi == 2&&gj - sj == 2&&place[gi+1][gj-1] == 0){
                    
                    if((x == 5&&si >= 5)||(x == 12&&si < 5))    return true;
                    else return false;
                }
                //右下
                else if(si - gi == 2&&sj - gj == 2&&place[gi+1][gj+1] == 0){
                    
                    if((x == 5&&si >= 5)||(x == 12&&si < 5))    return true;
                    else return false;
                }
                else return false;
            }
            //士:斜着走不能出田字格
            else if(x == 6||x == 13){
                
                if(Math.abs(gj-sj)==1&&Math.abs(gi-si)==1){
                    
                    if(x == 6&&si >= 7&&sj >= 3&&sj <= 5)    return true;
                    else if(x == 13&&si <= 2&&sj >= 3&&sj <= 5)    return true;
                    else return false;
                }
                else return false;
            }
            //将:不能出田字格且不能会面
            else if(x == 7||x == 14){
                
                if((Math.abs(gj-sj)==1&&gi - si ==0)||(gj - sj ==0&&Math.abs(gi-si)==1)){
                    
                    if(x == 7&&si >= 7&&sj >= 3&&sj <= 5)    return true;
                    else if(x == 14&&si <= 2&&sj >= 3&&sj <= 5)    return true;
                    else return false;
                }
                else return false;
                
            }
            //炮:隔一个
            else if(x == 2||x == 9){
                
                //若要吃棋子,必须中间有且只有一枚棋子
                if(x*y!=0){
                    int t = 0;
                    if(gi == si){
                        for(int m = Math.min(gj, sj); m <= Math.max(gj, sj); m++){
                            if(place[gi][m] != 0)    t++;
                        }
                    }
                    else if(gj == sj){
                        for(int m = Math.min(gi, si); m <= Math.max(gi, si); m++){
                            if(place[m][gj] != 0)    t++;
                        }
                    }
                    if(t == 3)    return true;
                    
                }    
                    
                //若为不吃棋子的情况,中间不可以有其他棋子,且只能走直线
                else {
                    int t = 0;
                    if(gi == si){
                        for(int m = Math.min(gj, sj); m <= Math.max(gj, sj); m++){
                            if(place[gi][m] != 0)    t++;
                        }
                    }
                    else if(gj == sj){
                        for(int m = Math.min(gi, si); m <= Math.max(gi, si); m++){
                            if(place[m][gj] != 0)    t++;
                        }
                    }
                    if(t == 1) return true;
                    else return false;
                }
            }
            //兵:不能后退,且过了河才可以左右移动
            else if(x == 1||x == 8){
                //判断是否过河
                if(x == 1){
                    if(gi >=5){
                        if(gi - si == 1&&gj == sj)    return true;
                        else return false;
                    }
                    else if((gi - si == 1&&sj - gj == 0)||(gi - si == 0&&Math.abs(sj-gj) == 1))    return true;
                    else return false;
                }
                else if(x == 8){
                    if(gi <5){
                        if(si - gi == 1&&gj == sj)    return true;
                        else return false;
                    }
                    else if(((si - gi == 1&&sj - gj == 0))||(gi - si == 0&&Math.abs(sj-gj) == 1))    return true;
                    else return false;
                }
                else return false;
            }
            
            return false;
        }

    长长的一大串,这里对于炮和将需单独考虑,炮有直行和隔一个两种走法,需分开考虑,而将就更是麻烦

    //判断将是否会面
    public boolean meet(){
            int jiangi=0, jiangj=0, shuaii=0, shuaij=0, temp=0;
            for(int i=0; i<10; i++){
                for(int j=0; j<9; j++){
                    if(place[i][j]==7){
                        shuaii = i;
                        shuaij = j;
                    }
                    else if(place[i][j]==14){
                        jiangi = i;
                        jiangj = j;
                    }
                }
            }
            if(shuaij == jiangj){
                for(int i=jiangi+1; i

    八、轮次

    红黑轮流下棋
    我单独写了一个方法判断将是否会面,因为导致将会面的不仅是将自身的移动导致,还可能是其他棋子的移动,所以也是一个boolean函数,只有同时满足前一个函数以及这个函数返回的是不会面,才可以移动,移动时我定义了一个参数x记录局数,根据他的奇偶判断轮到哪一方走。这样就实现了象棋的规则。

    九、悔棋

    难免会有失误,加上悔棋功能更合适。
    我们在交换两个点的值时(或者吃子的情况)需记录下之前的值,然后当动作监听器监听到点击悔棋时又交换回来。
    一次只能悔棋一次,且刚开始时棋子没有移动不能悔棋。

    十、背景 及 提示

    加上自己挑的背景,并为了方便下棋,标注轮到哪一方。
    加背景可以用到画棋子同样的方法,所以要画在棋盘前面,防止被覆盖住。
    这样加上去又有一个很明显的问题,就是你每操作一次右边的按钮都会消失,被你的背景图覆盖了,这怎么办呢?
    于是乎,又总结出了三种方法:

    1.重写按钮的paint方法;
    2.将按钮以菜单的形式加在左上角;
    3.将按钮直接p在背景图上(截图),再画就可以了;

    此外你还可以在背景图上加上“当前下棋方”的字样,在边上显示当前下棋方将领的图片。
    这里借用了count参数并将其传到了监听器中,重写了构造函数。

    int count=1;
    
    if(listener.count==1){
                //画帥
            bg.drawImage(chess[6], 708, 322, 50, 50, null); 
        }else if(listener.count==-1){
                //画将
            bg.drawImage(chess[13], 708, 322, 50, 50, null); 
    }

    每下一子,count×(-1),以此标记是哪一方并画图。

    附一张成果图:

    怎么用Java实现中国象棋游戏

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Java
    相关文章 更多
    精品专题 更多
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    IOS软件

    正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

    AI

    正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw macOS版
    AionClaw macOS版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy macOS版
    Loomy macOS版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirBuddy 3 macOS版
    AirBuddy 3 macOS版

    AirBuddy 3 是面向 macOS 的蓝牙外设增强工具,可集中查看 AirPods、Beats 与苹果设备电量,提供快速连接、播放控制、电量提醒、桌面小组件和多台 Mac 外设接力等功能。

    AirServer macOS版
    AirServer macOS版

    AirServer macOS版可把 Mac 转换为无线投屏接收端,通过 AirPlay 或 Google Cast 接收手机、平板和电脑画面,并支持多设备同时连接、高清镜像及会话录制,适合家庭娱乐、课堂教学、会议演示和应用展示。

    AnyDesk macOS版
    AnyDesk macOS版

    AnyDesk macOS版是一款适用于远程办公、设备维护和客户支持的远程桌面工具,可连接并操作异地计算机,支持文件传输、无人值守访问、会话权限控制及跨平台协作。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。

    讯飞绘文 网页版
    讯飞绘文 网页版

    讯飞绘文网页版是科大讯飞推出的AI图文创作与内容运营工具,覆盖热点选题、文章生成、稿件校对、智能配图、排版发布和数据复盘等环节,适合自媒体创作者及内容团队在线使用。

    Maya(Autodesk Maya) Windows版
    Maya(Autodesk Maya) Windows版

    Autodesk Maya 是面向影视、电视、动画和游戏行业的专业三维制作软件,集多边形与 NURBS 建模、角色绑定、关键帧和动作捕捉动画、Bifrost 特效模拟、材质开发及 Arnold 渲染于一体,

    Aperty Windows版
    Aperty Windows版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw Windows版
    AionClaw Windows版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy Windows版
    Loomy Windows版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。