Custom View Practice - A Simple Board Game

The original text was published on my personal blog: http://kahn.wang/a-practice-of-custom-view-a-simple-chess/

Recently, I watched a video on the MOOC online to realize the Gobang game by customizing the View . I remembered a chess game I used to play with my friends when I was a child, so I did it myself and followed the video to put my ideas into practice. Also an exercise as a custom View.

Rules Introduction

Here are some finished pictures:
       

The second picture has already introduced the rules very clearly. You can only take one step at a time. As long as your three pieces pass the midpoint and form a line, you will win. Of course, two people are required to play this game, but you can also play with yourself (the world of single dogs...). Another day I will see if I can write a robot to realize man-machine battle.

demand analysis

To implement such a game we need to solve the following problems:

  1. Draw a view based on the state at each point
  2. Pieces are draggable, and when dragged, the pieces are enlarged to mimic picking up
  3. How to judge winners and losers
  4. Judging whether the landing point conforms to the rules, for example, you can't walk two squares at a time, and you can't take a path outside the regulations
  5. Determine which side is the turn to go, and the other side cannot move the view.
  6. Ability to start over, reset the board

how to draw

There is no more to say about the drawing of the chessboard and the drawing of the chess pieces. Students who are not clear can check the source code at the end of the article or watch the video link given at the beginning of the article. Only the core logic is mentioned here. First look at the drawing method:
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制棋盘
        drawBoard(canvas);
        //绘制棋子
        drawPieces(canvas);
        if (isMoving){
            drawMovingPices(canvas);
        }
    }
It's very simple, there are only three methods, the first is to draw the chessboard, which is very simple and I won't say more, and then the chess piece is drawn according to the state of each point, this is the next step, and then judge whether it is moving, if it is moving, Draw the moving pieces.

draw static pieces

Because the chessboard is a 3*3 grid with nine points in total, here I use a 3*3 two-dimensional array to represent the state of each point, and each element in the array corresponds to each point. When the element value is 0, it means that the corresponding point has no chess pieces, when the element value is 1, it means that the corresponding point is white, and when the element point is 2, it means black chess. code show as below:
    public static final int NO_PIECES=0;
    public static final int WHITE_PIECES=1;
    public static final int BLACK_PIECES=2;
    //是否是选中状态
    public static final int SELECT_WHITE_PIECES=3;
    public static final int SELECT_BLACK_PIECES=4;
    private int[][] positionCondition={
            {WHITE_PIECES,WHITE_PIECES,WHITE_PIECES},
            {NO_PIECES,NO_PIECES,NO_PIECES},
            {BLACK_PIECES,BLACK_PIECES,BLACK_PIECES}
    };

There are also 3 and 4 above, which represent the white and black pieces when they are selected, and make them draw enlarged pieces when they are drawn.

Then you can draw chess pieces according to the situation of each point. Here is the method of drawing chess pieces:

private void drawPieces(Canvas canvas) {
        float lineHeight=mLineHeight; //棋盘每格的高度

        //开始绘制
        //通过判断每个点是否有棋子
        for (int i=0;i<=Max_LINE;i++) {
            for (int j=0;j<=Max_LINE;j++){
                int x=(int)(lineHeight/4);
                int halfPiecesWidth= (int) (lineHeight*ratioPiecesOfLineHeight/2);
                int selectedHalfPiecesWidth= (int) (lineHeight*ratioSelectedPiecesOfLineheight/2);
                if (positionCondition[i][j]==WHITE_PIECES){
                    canvas.drawBitmap(mWhitePieces,x+j*lineHeight-halfPiecesWidth,x+i*lineHeight-halfPiecesWidth,null);
                }else if (positionCondition[i][j]==BLACK_PIECES){
                    canvas.drawBitmap(mBlackPieces,x+j*lineHeight-halfPiecesWidth,x+i*lineHeight-halfPiecesWidth,null);
                }else if (positionCondition[i][j]==SELECT_WHITE_PIECES){
                    canvas.drawBitmap(mSelectedWhitePieces,x+j*lineHeight-selectedHalfPiecesWidth,x+i*lineHeight-selectedHalfPiecesWidth,null);
                }else if (positionCondition[i][j]==SELECT_BLACK_PIECES){
                    canvas.drawBitmap(mSelectedBlackPieces,x+j*lineHeight-selectedHalfPiecesWidth,x+i*lineHeight-selectedHalfPiecesWidth,null);
                }
            }
        }
    }

draw moving pieces

Decide whether to draw a moving piece by determining whether this global variable is moving:
    private void drawMovingPices(Canvas canvas) {
        float selectedHalfPiecesWidth= mLineHeight*ratioSelectedPiecesOfLineheight/2;
        if (movingPieces==WHITE_PIECES){
            canvas.drawBitmap(mSelectedWhitePieces,mPointF.x-selectedHalfPiecesWidth,mPointF.y-selectedHalfPiecesWidth,null);
        }else if (movingPieces==BLACK_PIECES){
            canvas.drawBitmap(mSelectedBlackPieces,mPointF.x-selectedHalfPiecesWidth,mPointF.y-selectedHalfPiecesWidth,null);
        }
    }

Where mPointF.x and mPointF.y are the coordinates obtained when the touch event is MOVE.

In this way requirements 1 and 2 are solved.

Win or lose judgment

Because a two-dimensional matrix was used to correspond to each point, when judging whether to win or lose, you only need to judge whether the four lines in the center correspond to the elements in the array. The code is as follows:
private void checkIsGameOver() {
    boolean a=positionCondition[1][1]==positionCondition[0][0]
            &&positionCondition[1][1]==positionCondition[2][2];
    boolean b=positionCondition[1][1]==positionCondition[0][1]
            &&positionCondition[1][1]==positionCondition[2][1];
    boolean c=positionCondition[1][1]==positionCondition[0][2]
            &&positionCondition[1][1]==positionCondition[2][0];
    boolean d=positionCondition[1][1]==positionCondition[1][0]
            &&positionCondition[1][1]==positionCondition[1][2];
    if (a||b||c||d){
        if (positionCondition[1][1]==WHITE_PIECES){
            Toast.makeText(getContext(),R.string.white_goal,Toast.LENGTH_LONG).show();
        }else if (positionCondition[1][1]==BLACK_PIECES){
            Toast.makeText(getContext(),R.string.black_goal,Toast.LENGTH_LONG).show();
        }
    }
}

Among them, a, b, c, and d represent the four positions at the time of victory, and when any one occurs, the game ends. Because no matter which position passes through the midpoint, it is only necessary to determine which side the midpoint is to determine which side wins.

In this way, requirement 3 can be satisfied

Judgment outside the rules

If the path taken does not conform to the rules, the pawn will return to its original position. The main judgment code is as follows:
                boolean judge=(upi+upj)%2!=0&&(downi+downj)%2!=0;  //不能走在规定外的斜线
                if (positionCondition[upj][upi]==NO_PIECES  //落点必须没有棋子
                        &&Math.abs(upi-downi)<=1   //不能走两格以上
                        &&Math.abs(upj-downj)<=1
                        &&!judge  //不能走规定外的斜线
                        &&Math.abs(upi-downi)+Math.abs(upj-downj)!=0 //不能原地不动
                        &&isMoving  //确定移动了
                        ){
                    positionCondition[upj][upi]=movingPieces;
                    mCounts=mCounts+1;
                    //判断是哪个棋子先走
                    if (mCounts==1){
                        mFirst=movingPieces;
                    }
                }else {
                    //棋子回到原位
                    positionCondition[downj][downi]=movingPieces;
                }

Among them, upi and upj represent the position of the drop point, and downi and downj represent the position of the starting point, because they correspond to the DOWN and UP in the touch event.

Among them, for the judgment of which chess piece it is the turn to move, two variables are introduced here, an mFirst, which is used to record which chess piece moves first, and an mCounts, which is used to record the number of steps. Both initial values ​​are 0. When done, set mCounts plus 1. There is this judgment in the above code. If mCounts=1, that is, when the first step is completed, assign the piece moved in the first step to mFirst.

So how to judge whether it's your turn? It's very simple. We found that if the number of steps taken is an even number, then it is the first party's turn to move the piece. If it is an odd number, it is the other party's turn. Specifically code show as below:

                //正在移动
                if (mFirst==0
                        ||(mFirst==movingPieces&&mCounts%2==0)     //是否轮到的条件,如果没轮到则不移动
                        ||(mFirst!=movingPieces&&mCounts%2==1)){
                    isMoving=true;
                }else {
                    //如果不轮到走的话之前的要放大显示
                    positionCondition[downj][downi] =movingPieces+ 2;
                }

This judgment is written in the MOVE event of the touch event. If it is not your turn and you click, the pawn will be enlarged accordingly but not moved (isMoving is false).

So far, requirements 4 and 5 have been met, and the game is basically developed.

restart

To restart the game after the game is over, you only need to restore the initial two-dimensional array to the initial value, and set mFirst and mCounts to 0.

Write a public method here to respond to a restart operation on the actionBar:

    //重新开始游戏
    public void restartGame(){
        for (int i=0;i<=Max_LINE;i++){
            positionCondition[0][i]=WHITE_PIECES;
        }
        for (int i=0;i<=Max_LINE;i++){
            positionCondition[1][i]=NO_PIECES;
        }
        for (int i=0;i<=Max_LINE;i++){
            positionCondition[2][i]=BLACK_PIECES;
        }
        mFirst=0;
        mCounts=0;
        invalidate();
    }


The source code is on GitHub, and you are welcome to star: https://github.com/w-kahn/SimpleChess









Guess you like

Origin blog.csdn.net/w_kahn/article/details/51485527