Java实现中国象棋游戏

目录
  • 一、界面
  • 二、按钮
  • 三、加棋子
  • 四、实现棋子的移动
  • 五、判断胜负
  • 六、按钮“开始游戏”和“重新开始”的实现
  • 七、加规则
  • 八、轮次
  • 九、悔棋
  • 十、背景 及 提示

本文实例为大家分享了Java实现中国象棋游戏的具体代码,供大家参考,具体内容如下

实现一个小游戏需要知道从哪里下手,一步步实现和完善,对于一个中国象棋的小游戏,我们可以按这样的顺序展开:

一、界面

下棋的棋盘首先要准备好,这就是一个合适大小合适比例合适位置的界面,然后在窗体上画上(没错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<type.length;i++){
            Button btn = new Button(type[i]);
            btn.setPreferredSize(new Dimension(150,50));
            anniu.add(btn);
        }

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

三、加棋子

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

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

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

将Image与棋子图片对应:

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

遍历画图:

//根据棋盘布局
        for(int i=0;i<place.length;i++){
            for(int j=0;j<place[0].length;j++){
                if(place[i][j] >0){
                    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<place.length; i++){
              
              for(int j=0; j<place[0].length; j++){
                  
                  place[i][j] = 0;
              }
         }
    }

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

加动作监听器

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<place.length;i++){
                
            for(int j=0;j<place[0].length;j++){
                            
                place[i][j] = 0;
            }
        }
            place[0][0] = 10;    place[9][0] = 3;
            place[0][1] = 11;    place[9][1] = 4;
            place[0][2] = 12;    place[9][2] = 5;
            place[0][3] = 13;    place[9][3] = 6;
            place[0][4] = 14;    place[9][4] = 7;
            place[0][5] = 13;    place[9][5] = 6;
            place[0][6] = 12;    place[9][6] = 5;
            place[0][7] = 11;    place[9][7] = 4;
            place[0][8] = 10;    place[9][8] = 3;
            place[2][1] = 9;    place[7][1] = 2;
            place[2][7] = 9;    place[7][7] = 2;
            place[3][0] = 8;    place[6][0] = 1;
            place[3][2] = 8;    place[6][2] = 1;
            place[3][4] = 8;    place[6][4] = 1;
            place[3][6] = 8;    place[6][6] = 1;
            place[3][8] = 8;    place[6][8] = 1;
            
    }    

这里的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<shuaii; i++){
                if(place[i][shuaij] != 0)    temp++;
            }
        }
        else return false;//没会面
        if(temp != 0)    return false;//没会面
        else return true;//会面了
    }

八、轮次

红黑轮流下棋
我单独写了一个方法判断将是否会面,因为导致将会面的不仅是将自身的移动导致,还可能是其他棋子的移动,所以也是一个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),以此标记是哪一方并画图。

附一张成果图:

最后导出到电脑上,这样就完成了一个中国象棋的小游戏。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java实现中国象棋的示例代码

    目录 前言 主要设计 功能截图 代码实现 总结 前言 中国象棋是起源于中国的一种棋,属于二人对抗性游戏的一种,在中国有着悠久的历史.由于用具简单,趣味性强,成为流行极为广泛的棋艺活动. 中国象棋使用方形格状棋盘,圆形棋子共有32个,红黑二色各有16个棋子,摆放和活动在交叉点上.双方交替行棋,先把对方的将(帅)“将死”的一方获胜. 中国象棋是一款具有浓郁中国特色的益智游戏,新增的联网对战,趣味多多,聚会可以约小朋友一起来挑战.精彩的对弈让你感受中国象棋的博大精深. <中国象棋>游戏是用java语

  • Java+Swing实现中国象棋游戏

    目录 一.系统介绍 1.开发环境 2.技术选型 3.系统功能 二.系统展示 三.部分代码 一.系统介绍 1.开发环境 开发工具:Eclipse2021 JDK版本:jdk1.8 Mysql版本:8.0.13 2.技术选型 Java+Swing 3.系统功能 实现中国象棋游戏,开始游戏,悔棋,退出功能. 二.系统展示 1.首页 2.红旗走 3.黑棋走 三.部分代码 ChineseCheseRule.java package com.sjsq; import java.awt.event.Mouse

  • java实现简单中国象棋

    本文实例为大家分享了java实现简单中国象棋的具体代码,供大家参考,具体内容如下 可以实现简单的人机对战功能,棋子移动会插入关键帧,可以悔棋等功能 运行效果 代码 import java.awt.Canvas; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener;

  • Java棋类游戏实践之中国象棋

    本文实例讲述了java实现的中国象棋游戏代码,分享给大家供大家参考,具体代码如下 一.实践目的: 1.鼠标点击.拖动等事件的应用与区别 2.棋谱文件的保存与读取 3.完善象棋的规则. 二.实践内容: 中国象棋历史悠久,吸引了无数的人研究,现对中国象棋的对战和实现棋谱的制作做如下的设计和说明,供大家参考学习. 1.机机对弈,红方先手.在符合规则的情况下拖动棋子到目的地,松鼠标落子. 人人对弈图 2.制作棋谱,选择制作棋谱菜单后,对弈开始,并记录了下棋过程. 选择"制作棋谱"菜单 棋谱制作

  • java绘制国际象棋与中国象棋棋盘

    JAVA API 中的绘制图形类的paint()方法,我们可以轻松绘制中国象棋与国际象棋的棋盘.详见代码:  一.中国象棋棋盘代码 import java.awt.Font; import java.awt.Frame; import java.awt.Graphics; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; public class ChineseChese extends Frame{

  • Java实现中国象棋游戏

    目录 一.界面 二.按钮 三.加棋子 四.实现棋子的移动 五.判断胜负 六.按钮“开始游戏”和“重新开始”的实现 七.加规则 八.轮次 九.悔棋 十.背景 及 提示 本文实例为大家分享了Java实现中国象棋游戏的具体代码,供大家参考,具体内容如下 实现一个小游戏需要知道从哪里下手,一步步实现和完善,对于一个中国象棋的小游戏,我们可以按这样的顺序展开: 一.界面 下棋的棋盘首先要准备好,这就是一个合适大小合适比例合适位置的界面,然后在窗体上画上(没错drawLine的那种画上)n条直线和斜线,具体

  • Android实现中国象棋游戏(局域网版)

    本文实例为大家分享了Android实现中国象棋游戏的具体代码,供大家参考,具体内容如下 实现环境:  android studio 3.2.1, 手机分辨率为: 1920 * 1080 局域网 UDP 连接分主活动类,棋类,主机类 代码如下: 清单文件要添加的权限: <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name=

  • Python实现人机中国象棋游戏

    目录 导语 1.游戏规则&基本玩法 1.1 基本玩法 1.2 行棋规则 2.素材文件 3.主要代码 3.1 Chinachess.py 为主文件 3.2 Constants.py 数据常量 3.3 Pieces.py 棋子类,走法 3.4 Computer.py 电脑走法计算 3.5 Button.py按钮定义 4.游戏效果 总结 导语 哈喽!哈喽!我是木木子!今日游戏更新——中国象棋上线啦! 中国象棋是一种古老的棋类游戏,大约有两千年的历史. 是中华文明非物质文化经典产物,艺术价值泛属于整个人

  • js实现中国象棋游戏

    本文实例为大家分享了js实现中国象棋游戏的具体代码,供大家参考,具体内容如下 使用table元素作表格,div元素作象棋. 效果如下: 代码如下: <html> <head> <title>中国象棋</title> <meta charset="UTF-8"> <style> table{     margin:10px;     border-collapse:collapse; } table.board{  

  • 基于c++的中国象棋游戏设计与实现

    目录 1.文档 2.游戏操作逻辑 3.UI框架 4.网络通信 1.文档 文档分为两部分,一部分在代码中,然后通过doxygen生成HTML.解压本目录下的html.zip后打开index.html即可查看:第二部分在此说明文档内,在这里会介绍一些架构方面的信息. 2.游戏操作逻辑 相关的命名空间有: Chess:这是包含中国象棋的操作逻辑的命名空间 主要操作是possibleMove(int x, int y),通过整个棋盘每个位置上的信息.中国象棋的规则来获得位置(x, y)这个棋子可以移动到

  • java实现简单网络象棋游戏

    本文实例为大家分享了java实现网络象棋游戏的具体代码,供大家参考,具体内容如下 游戏规则: 1.将/帅:不能出田字格,不能走斜线,只能前进后退向左向右,每次只走一格: 2.士/仕:不能出田字格,只能走斜线,每次只走一格: 3.象/相:只能走田字格,中间防止蹩脚,不能有棋: 4.马:只能走日,(这个比较麻烦,且看下图标识) 5.车:车只能走直线,这个很好理解,不细说了: 6.炮: 情况一:纯走路-->中间和目的地都不能有棋 情况二:吃棋-–>中间要有一颗棋,目标也有棋,且是敌方的棋,毕竟不能自

随机推荐