Android program ----> Implementation of android wuziqi, android wuziqi
I learned the wuziqi course on MOOC online. It feels good. Then I wrote an android program about Wuzi, from which I can still learn a lot. Now let's start the compilation of today's wuziqi program. For the program source code, see the link:
Directory navigation
Now, let's build a project step by step. The first is the following project structure:
Running:
Some code for preparation
I. Main activity MainActivity, which includes the following functions in the menu:
Public class MainActivity extends AppCompatActivity {private ChessBoardView chessBoardView; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); chessBoardView = (ChessBoardView) findViewById (R. id. boardView) ;}@ Override public boolean onOptionsItemSelected (MenuItem item) {int id = item. getItemId (); // if (id = R. id. action_setting) {chessBoardView. start (); return true;} return super. onOptionsItemSelected (item) ;}@ Override public boolean onCreateOptionsMenu (Menu menu) {getMenuInflater (). inflate (R. menu. menu_main, menu); return true ;}}
Ii. Convenient Maintenance and Management of Constants: Constants
Public class Constants {// five sub-links public final static int MAX_COUNT_IN_LINE = 5; // The number of rows on the board final static int MAX_LINE = 15; // check the direction of final static int HORIZONTAL = 0; final static int VERTICAL = 1; final static int LEFT_DIAGONAL = 2; final static int RIGHT_DIAGONAL = 4 ;}
3. added the View of the custom board in activity_main.xml:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@mipmap/bg" tools:context="com.example.linux.mygobang.MainActivity"> <com.example.linux.mygobang.ChessBoardView android:id="@+id/boardView" android:layout_centerInParent="true" android:layout_width="match_parent" android:layout_height="match_parent" /></RelativeLayout>
4. Define the next menu in menu_main.xml:
<? Xml version = "1.0" encoding = "UTF-8"?> <Menu xmlns: tools = "http://schemas.android.com/tools" xmlns: android = "http://schemas.android.com/apk/res/android"> <item android: id = "@ + id/action_setting" android: title = "Next game" android: orderInCategory = "100" android: showAsAction = "never" tools: ignore = "AppCompatResource"/> </menu>
View of the custom board
The ChessBoardView class is the core of the entire program.
I. Initialization. the variables used in the program are also included in the following code:
// The width of the Board, which is also the length of private int mViewWidth; // The length of each cell of the Board private float maxLineHeight; private Paint paint = new Paint (); // define Bitmapprivate Bitmap mwhitePiece, mblackPiece; private float ratioPieceOfLineHeight = 3 * 1.0f/4; // determine whether the current falling piece is a white private boolean mIsWhite = true; // record the list of black and white pawns. private ArrayList <Point> mwhiteArray = new ArrayList <> (); private ArrayList <Point> mblackArray = new ArrayList <> (); // whether the game ends. private boolean mIsGameOver; // whether the game ends. Whether the game is a white-side victory. private boolean mIsWhiteWinner; public ChessBoardView (Context context, AttributeSet attrs) {super (context, attrs ); init ();} private void init () {paint. setColor (0x88000000); paint. setAntiAlias (true); paint. setDither (true); paint. setStyle (Paint. style. STROKE); mwhitePiece = BitmapFactory. decodeResource (getResources (), R. mipmap. stone_w2); mblackPiece = BitmapFactory. decodeResource (getResources (), R. mipmap. stone_b1 );}
2. The onMeasure method is used to measure the size of the View so that the length and width of the View are consistent.
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthSize = MeasureSpec.getSize(widthMeasureSpec); int widthModel = MeasureSpec.getMode(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int heightModel = MeasureSpec.getMode(heightMeasureSpec); int width = Math.min(widthSize, heightSize); if (widthModel == MeasureSpec.UNSPECIFIED) { width = heightSize; } else if (heightModel == MeasureSpec.UNSPECIFIED) { width = widthSize; } setMeasuredDimension(width, width);}
3. The onSizeChanged method is in the layout stage. If the View Size changes, this method is called.
@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mViewWidth = w; maxLineHeight = mViewWidth * 1.0f / Constants.MAX_LINE; int pieceWidth = (int) (maxLineHeight * ratioPieceOfLineHeight); mwhitePiece = Bitmap.createScaledBitmap(mwhitePiece, pieceWidth, pieceWidth, false); mblackPiece = Bitmap.createScaledBitmap(mblackPiece, pieceWidth, pieceWidth, false);}
4. The onTouchEvent method processes the position of the pawns:
@Overridepublic boolean onTouchEvent(MotionEvent event) { if (mIsGameOver) { return false; } int action = event.getAction(); if (action == MotionEvent.ACTION_UP) { int x = (int) event.getX(); int y = (int) event.getY(); Point point = getValidPoint(x, y); if (mwhiteArray.contains(point) || mblackArray.contains(point)) { return false; } if (mIsWhite) { mwhiteArray.add(point); } else { mblackArray.add(point); } invalidate(); mIsWhite = !mIsWhite; } return true;}
5. Draw the board in the onDraw method:
@ Overrideprotected void onDraw (Canvas canvas) {super. onDraw (canvas); // draw the canvas's grid drawBoard (canvas); // draw the canvas's black-and-white pawns drawPieces (canvas); // check whether the game is over checkGameOver ();}
6. Next, we will explain the process in detail one by one:
Draw the grid of the Board:
// Draw the private void drawBoard (Canvas canvas) {int w = mViewWidth; float lineHeight = maxLineHeight; for (int I = 0; I <Constants. MAX_LINE; I ++) {int startX = (int) (lineHeight/2); int endX = (int) (w-lineHeight/2); int y = (int) (0.5 + I) * lineHeight); canvas. drawLine (startX, y, endX, y, paint); canvas. drawLine (y, startX, y, endX, paint );}}
Draw the black and white chess pieces of the Board:
// Draw the private void drawPieces (Canvas canvas) {for (int I = 0, n = mwhiteArray. size (); I <n; I ++) {Point whitePoint = mwhiteArray. get (I); float left = (whitePoint. x + (1-ratioPieceOfLineHeight)/2) * maxLineHeight; float top = (whitePoint. y + (1-ratioPieceOfLineHeight)/2) * maxLineHeight; canvas. drawBitmap (mwhitePiece, left, top, null);} for (int I = 0, n = mblackArray. size (); I <n; I ++) {Point blackPoint = mblackArray. get (I); float left = (blackPoint. x + (1-ratioPieceOfLineHeight)/2) * maxLineHeight; float top = (blackPoint. y + (1-ratioPieceOfLineHeight)/2) * maxLineHeight; canvas. drawBitmap (mblackPiece, left, top, null );}}
Check whether the game is over:
// Check whether the game ends private void checkGameOver () {CheckWinner checkWinner = new CheckWinner (); boolean whiteWin = checkWinner. checkFiveInLineWinner (mwhiteArray); boolean blackWin = checkWinner. checkFiveInLineWinner (mblackArray); if (whiteWin | blackWin) {mIsGameOver = true; mIsWhiteWinner = whiteWin; String text = mIsWhiteWinner? "" ":" "; Toast. makeText (getContext (), text, Toast. LENGTH_SHORT). show ();}}
Save the mess and restore the Board
1. Save the residual State, for example, when switching the landscape:
private static final String INSTANCE = "instance";private static final String INSTANCE_GAME_OVER = "instance_game_over";private static final String INSTANCE_WHITE_ARRAY = "instance_white_array";private static final String INSTANCE_BLACK_ARRAY = "instance_black_array";@Overrideprotected Parcelable onSaveInstanceState() { Bundle bundle = new Bundle(); bundle.putParcelable(INSTANCE, super.onSaveInstanceState()); bundle.putBoolean(INSTANCE_GAME_OVER, mIsGameOver); bundle.putParcelableArrayList(INSTANCE_BLACK_ARRAY, mblackArray); bundle.putParcelableArrayList(INSTANCE_WHITE_ARRAY, mwhiteArray); return bundle;}
2. Restore the game from bundle:
@Overrideprotected void onRestoreInstanceState(Parcelable state) { if (state instanceof Bundle) { Bundle bundle = (Bundle) state; mIsGameOver = bundle.getBoolean(INSTANCE_GAME_OVER); mwhiteArray = bundle.getParcelableArrayList(INSTANCE_WHITE_ARRAY); mblackArray = bundle.getParcelableArrayList(INSTANCE_BLACK_ARRAY); super.onRestoreInstanceState(bundle.getParcelable(INSTANCE)); return; } super.onRestoreInstanceState(state);}
3. added the logic for the next game:
// Public void start () {mwhiteArray. clear (); mblackArray. clear (); mIsGameOver = false; mIsWhiteWinner = false; invalidate ();}
Algorithms used to determine whether a game is over
In CheckWinner, check whether the "meters" font of the pawns in the checker are even five sub-beads:
I. In the check method, make judgments for different directions:
private boolean check(int x, int y, List<Point> points, int checkOri) { int count = 1; for (int i = 1; i < Constants.MAX_COUNT_IN_LINE; i++) { switch (checkOri) { case Constants.HORIZONTAL: point1 = new Point(x - i, y); break; case Constants.VERTICAL: point1 = new Point(x, y - i); break; case Constants.LEFT_DIAGONAL: point1 = new Point(x - i, y + i); break; case Constants.RIGHT_DIAGONAL: point1 = new Point(x + i, y + i); break; } if (points.contains(point1)) { count++; } else { break; } } for (int i = 1; i < Constants.MAX_COUNT_IN_LINE; i++) { switch (checkOri) { case Constants.HORIZONTAL: point2 = new Point(x + i, y); break; case Constants.VERTICAL: point2 = new Point(x, y + i); break; case Constants.LEFT_DIAGONAL: point2 = new Point(x + i, y - i); break; case Constants.RIGHT_DIAGONAL: point2 = new Point(x - i, y - i); break; } if (points.contains(point2)) { count++; } else { break; } } if (count == Constants.MAX_COUNT_IN_LINE) { return true; } return false;}
2. Perform four direction checks:
// Lateral judgment private boolean checkHorizontal (int x, int y, List <Point> points) {checkModel = Constants. HORIZONTAL; return check (x, y, points, checkModel);} // vertical judgment private boolean checkVertical (int x, int y, List <Point> points) {checkModel = Constants. VERTICAL; return check (x, y, points, checkModel);} // determines the left oblique private boolean checkLeftDiagonal (int x, int y, List <Point> points) {checkModel = Constants. LEFT_DIAGONAL; return check (x, y, points, checkModel);} // right oblique judgment private boolean checkRighttDiagonal (int x, int y, List <Point> points) {checkModel = Constants. RIGHT_DIAGONAL; return check (x, y, points, checkModel );}
Iii. Determine whether the game is over:
private Point point1, point2;private int checkModel = -1;public boolean checkFiveInLineWinner(List<Point> points) { for (Point point : points) { int x = point.x; int y = point.y; if (checkHorizontal(x, y, points)) { return true; } else if (checkVertical(x, y, points)) { return true; } else if (checkLeftDiagonal(x, y, points)) { return true; } else if (checkRighttDiagonal(x, y, points)) { return true; } } return false;}
Links
- Download wuziqi source code