Home  >  Article  >  Java  >  How to implement Chinese chess game using Java

How to implement Chinese chess game using Java

PHPz
PHPzforward
2023-05-12 18:58:041387browse

1. Interface

The chessboard for playing chess must first be prepared. This is an interface with the right size, proportion and position, and then draw it on the form (yes, drawLine) n straight lines and slashes, the specific values ​​are set according to the size of your interface. The interface drawn in this way is neat and beautiful~

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);
     
    }

2. Buttons

After drawing the chessboard, add function buttons. The functions at this time are not considered to be implemented for the time being. You can add them at will according to your preference. It is recommended here to set the button type to an array to facilitate timely additions and deletions.

//添加到面板上
        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);
        }

How to implement Chinese chess game using Java

At this time you will find that the button is very compact. My solution is to add another panel to this panel and set it to white. Above, the button will move down according to the fluid layout of the panel. Adjusting the width of the blank panel can change the button's position.

3. Add chess pieces

Add the found chess piece pictures to the intersection positions of the chessboard to inject soul into the chessboard. Add all fourteen types of pictures to the package so that the program can Run on other computers (png format is recommended here, jpg format will have square borders).
The next step is to take three steps

1. Create an integer array with 10 rows and 9 columns to store the data at each position;
2. Create an Image array with a length of 14, Used to correspond to the chess piece type;
3. Traverse the integer array to draw the corresponding chess piece;

This is an intuitive diagram of the chessboard, which is the initial value of our integer array:

How to implement Chinese chess game using Java

Correspond the Image to the chess piece picture:

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

Traverse the drawing:

//根据棋盘布局
        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); 
                }
            }
        }

4. Realize the movement of the chess piece

Get the mouse drag through the function Move the positions on the chessboard represented by the two points before and after, exchange the values ​​​​of the two-dimensional arrays of these two positions, and then redraw to realize the movement of the chess piece.

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;
    }

The situation you encounter at this time is that every time you move, the entire interface must be redrawn, and the picture is drawn directly on the form, and the data will be directly transmitted to the computer hardware. In this way The speed of drawing is slow, so the interface will flicker every time you take a step. In this case, we can store the picture in the cache first and draw it directly without going through the hardware, so the efficiency can be significantly improved.

BufferedImage buffer = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics bg = buffer.getGraphics();

//这个中间写的是你画界面的方法,也就是上面提到的paint方法内部
//......

//绘制缓存到窗体上
g.drawImage(buffer, 0, 0, null);

5. Determine the outcome

The team that takes the lead to defeat the opponent's general or general wins. Write a function to determine who wins and who loses to display the victory. At the same time, initialize the data to 0 and prepare for another round. Game:
(the showMessageDialog method can jump out of a box directly)

//判断游戏结束并显示胜局
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;
              }
         }
    }

6. Implementation of the buttons "Start Game" and "Restart"

Add action listener

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;
            
    }

The init function here is to initialize the integer two-dimensional array to a state where chess pieces can be added after the start of the traversal.

7. Add rules

//规定各个棋子的移动规则
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;
    }

It’s a long list. Here, the cannon and generals need to be considered separately. The cannons have two ways of moving: straight and at intervals, which need to be considered separately. It’s even more troublesome

//判断将是否会面
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;//会面了
    }

8. Rounds

Red and black take turns playing chess
I wrote a separate method to determine whether the generals will meet, because what causes the generals to meet is not only the movement of the generals themselves. As a result, it may also be the movement of other chess pieces, so it is also a boolean function. It can only be moved if it satisfies the previous function and the function returns no face. When moving, I defined a parameter x to record the number of games. According to his Odd and even determine which side's turn it is to go. In this way, the rules of chess are implemented.

9. Regret chess

It is inevitable that there will be mistakes, and it is more appropriate to add the regret chess function.
When we exchange the values ​​​​of two points (or in the case of capturing a piece), we need to record the previous value, and then exchange it back when the action listener listens to the click of regret.
You can only regret the move once, and you cannot regret the move if the chess piece has not moved at the beginning.

10. Background and Tips

Add the background of your choice, and for the convenience of playing chess, mark which side's turn it is.
To add a background, you can use the same method as drawing chess pieces, so it should be drawn in front of the chessboard to prevent it from being covered.
There is another obvious problem with adding this, that is, every time you operate the button on the right, it will disappear and be covered by your background image. What should I do?
Since then, three methods have been summarized:

1. Rewrite the paint method of the button;
2. Add the button in the upper left corner in the form of a menu;
3. Just p the button directly on the background image (take a screenshot) and then draw it;

In addition, you can also add the words "current chess player" on the background image to display the current chess player on the side Picture of General Fang.
The count parameter is borrowed here and passed to the listener, and the constructor is rewritten.

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); 
}

Every time a piece is made, count×(-1), mark which side it is and draw a picture.

Attached is a picture of the results:

How to implement Chinese chess game using Java

The above is the detailed content of How to implement Chinese chess game using Java. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete