最近看了鸿洋大牛的五子棋教程,受益匪浅,讲的非常好,关于五子棋的游戏原理非常清楚,并且学到了不少知识,在这里感谢鸿洋大神的分享。我觉得我的源码注释写的非常清楚了,希望能给你带来不少的收获。点击获取源码下载地址
布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"android:paddingTop="80dp"android:orientation="vertical"tools:context="com.yaodan.fivechessdemo.MainActivity"><com.yaodan.fivechessdemo.view.ChessViewandroid:id="@+id/custon_chess_main"android:layout_width="match_parent"android:layout_height="match_parent" /><Buttonandroid:id="@+id/bt_restart"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="再来一局"/>
</LinearLayout>

自定义View的工具类

package com.yaodan.fivechessdemo.view;import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;import com.yaodan.fivechessdemo.R;
import com.yaodan.fivechessdemo.contral.IsChessWin;import java.util.ArrayList;/*** Created by swk on 2016/12/5.*/
public class ChessView extends View {private int mPanelWith; //棋盘的宽度(棋盘使方形的)private float mLineHeigth;  //棋盘每一个空格的高度private int MAX_LINE = 10;    //棋盘的行数private Paint mPint = new Paint();    //创建画笔private Bitmap wPieces;     //白棋private Bitmap bPieces;     //黑棋private ArrayList<Point> wPoints = new ArrayList<>();   //白棋坐标的集合private ArrayList<Point> bPoints = new ArrayList<>();   //黑棋坐标的集合private float radioPoeces = 1.0f * 3 / 4;    //棋子与棋格的大小比例private boolean mIsWitch = true;  //判断是否白子画在棋盘上private boolean isGameOver = false;  //判读是否游戏结束private Context mContext;private IsChessWin isChessWin;  //一个用来处理胜利与否的逻辑private String TAG = "CHESSVIEW";public ChessView(Context context) {super(context);mContext = context;init();}public ChessView(Context context, AttributeSet attrs) {super(context, attrs);mContext = context;init();}public ChessView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);mContext = context;init();}/*** 再来一局方法*/public void myreStart() {wPoints.clear();bPoints.clear();isGameOver = false;Log.i(TAG, "myreStart: " + wPoints.size() + ":::" + bPoints.size());invalidate();}/*** 初始化*/public void init() {//设置画笔的颜色mPint.setColor(Color.BLACK);//设置抗锯齿功能(图像边缘相对清晰一点,锯齿痕迹不那么明显)mPint.setAntiAlias(true);//设置防抖动功能(使图像更柔和一点)mPint.setDither(true);//设置画笔的风格为空心mPint.setStyle(Paint.Style.STROKE);//获取棋子的资源文件wPieces = BitmapFactory.decodeResource(getResources(), R.drawable.stone_w2);bPieces = BitmapFactory.decodeResource(getResources(), R.drawable.stone_b1);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);/*** 获取view的宽度和mode* mode分为:* EXACTLY:EXACTLY是精确尺寸,当我们将控件的layout_width或layout_height指定为具体数值时如andorid:layout_width="50dip",或者为FILL_PARENT是,都是控件大小已经确定的情况,都是精确尺寸。* AT_MOST:最大尺寸,当控件的layout_width或layout_height指定为WRAP_CONTENT时,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。* UNSPECIFIED:未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式*/int widthSize = MeasureSpec.getSize(widthMeasureSpec);int widthMode = MeasureSpec.getMode(widthMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);//由于棋盘是正方形,所以要从长和宽选取最短的int width = Math.min(widthSize, heightSize);//如果上方有一个是UNSPECIFIED,相对应的有一个尺寸是0,如果有一个是0,那么width就是0显示不出来if (widthMode == MeasureSpec.UNSPECIFIED) {width = heightSize;} else if (heightMode == MeasureSpec.UNSPECIFIED) {width = widthSize;}//设置实际的长和宽设置上去setMeasuredDimension(width, width);}/*** 当view的尺寸改变时,会回掉这个方法** @param w* @param h* @param oldw* @param oldh*/@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);mPanelWith = w;mLineHeigth = mPanelWith * 1.0f / MAX_LINE;int piecesWidth = (int) (mLineHeigth * radioPoeces);//按照以前存在的位图按照一定的比例构建一个新的位图wPieces = Bitmap.createScaledBitmap(wPieces, piecesWidth, piecesWidth, true);bPieces = Bitmap.createScaledBitmap(bPieces, piecesWidth, piecesWidth, true);}/*** 获取坐标的集合** @param event* @return*/@Overridepublic boolean onTouchEvent(MotionEvent event) {isGameOver = isChessWin.isGameOverMethod(wPoints, bPoints);if (isGameOver) {showDialog();return false;}int action = event.getAction();if (action == MotionEvent.ACTION_UP) {int x = (int) event.getX();int y = (int) event.getY();Point point = getSimulatePoint(x, y);//如果黑棋的集合或者白棋的集合包含这个坐标,那么返回false//contains和eequals比较的不是内存空间的地址,而是x,y值是否一致if (wPoints.contains(point) || bPoints.contains(point)) {return false;}if (mIsWitch) {wPoints.add(point);} else {bPoints.add(point);}mIsWitch = !mIsWitch;//刷新Viewinvalidate();return true;}return true;}/*** 根据真实的坐标模拟出绝对值坐标** @param x* @param y* @return*/public Point getSimulatePoint(int x, int y) {return new Point((int) (x / mLineHeigth), (int) (y / mLineHeigth));}/*** 显示白棋或者黑棋获胜的提示的对话框*/public void showDialog() {String successText = isChessWin.isWhiteWinFlag() ? "白棋获胜!" : "黑棋获胜!";new AlertDialog.Builder(mContext).setMessage("恭喜" + successText + ",是否再来一局?").setCancelable(false).setPositiveButton("确定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {myreStart();}}).setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {}}).show();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);drawBoard(canvas);drawPieces(canvas);//下面的实例用来判断是否胜利isChessWin = new IsChessWin(mContext);isGameOver = isChessWin.isGameOverMethod(wPoints, bPoints);//判断是否结束游戏if(isGameOver){showDialog();}}/*** 画棋盘的线** @param canvas*/public void drawBoard(Canvas canvas) {int w = mPanelWith;float lineHeight = mLineHeigth;//画十条线for (int i = 0; i < MAX_LINE; i++) {//设置起点横坐标为半个棋盘空格的宽度int startX = (int) (lineHeight / 2);//设置终点X横坐标为宽度减去半个lineHeight(棋盘空格宽度)int endX = (int) (w - lineHeight / 2);int y = (int) ((0.5 + i) * lineHeight);//画横线canvas.drawLine(startX, y, endX, y, mPint);//画纵线,坐标反过来canvas.drawLine(y, startX, y, endX, mPint);}}/*** 画棋子*/public void drawPieces(Canvas canvas) {Log.i(TAG, "drawPieces: " + wPoints.size() + ":::" + bPoints.size());for (int i = 0; i < wPoints.size(); i++) {Point point = wPoints.get(i);//drawBitmap是将图片的右下角为坐标canvas.drawBitmap(wPieces, ((point.x + (1 - radioPoeces) / 2) * mLineHeigth), (point.y + (1 - radioPoeces) / 2) * mLineHeigth, null);}for (int i = 0; i < bPoints.size(); i++) {Point point = bPoints.get(i);canvas.drawBitmap(bPieces, ((point.x + (1 - radioPoeces) / 2) * mLineHeigth), (point.y + (1 - radioPoeces) / 2) * mLineHeigth, null);}}private static final String INSTANCE = "instance";private static final String INSTANCE_GAMEOVER = "instance_gameover";private static final String INSTANCE_WHITEARRAY = "instance_whitearray";private static final String INSTANCE_BLACKARRAY = "instance_blackarray";/*** 当view因为某种原因(比如系统回收)销毁时,保存状态** @return*/@Overrideprotected Parcelable onSaveInstanceState() {Bundle bundle = new Bundle();//保存系统默认状态bundle.putParcelable(INSTANCE, super.onSaveInstanceState());//保存是否游戏结束的值bundle.putBoolean(INSTANCE_GAMEOVER, isGameOver);//保存白棋的子数bundle.putParcelableArrayList(INSTANCE_WHITEARRAY, wPoints);//保存黑棋的子数bundle.putParcelableArrayList(INSTANCE_BLACKARRAY, bPoints);return bundle;}/*** 取出保存的值** @param state*/@Overrideprotected void onRestoreInstanceState(Parcelable state) {if (state instanceof Bundle) {Bundle bundle = (Bundle) state;isGameOver = bundle.getBoolean(INSTANCE_GAMEOVER);wPoints = bundle.getParcelableArrayList(INSTANCE_WHITEARRAY);bPoints = bundle.getParcelableArrayList(INSTANCE_BLACKARRAY);super.onRestoreInstanceState(bundle.getParcelable(INSTANCE));return;}super.onRestoreInstanceState(state);}
}

判断是否胜利的类

package com.yaodan.fivechessdemo.contral;import android.content.Context;
import android.graphics.Point;import java.util.List;/*** Created by swk on 2016/12/5.* 判断是否胜利类*/
public class IsChessWin {private boolean isGameOver = false;   //判断是否游戏结束private boolean isWhiteWin;     //判断是否白棋胜private int MAX_NUMWIN = 5;  //设置5子连在一起胜利private int CURRENT_NUM = 0;private Context mContext;private boolean isRestart=false;public IsChessWin(Context context) {super();mContext = context;}/*** 判断是否胜利* @param whitePoints* @param blackPoints* @return*/public boolean isGameOverMethod(List<Point> whitePoints, List<Point> blackPoints) {boolean whiteWin = isWhiteWin(whitePoints);boolean blackWin = isBlackWin(blackPoints);if (whiteWin || blackWin) {isGameOver = true;isWhiteWin = whiteWin;}return isGameOver;}/*** 返回是否白棋取胜* @return*/public boolean isWhiteWinFlag(){return isWhiteWin;}/*** 判断是否白棋取胜* @param points* @return*/private boolean isWhiteWin(List<Point> points) {if (isFiveConnect(points)) {return true;}return false;}/*** 判断是否黑棋取胜* @param points* @return*/private boolean isBlackWin(List<Point> points) {if (isFiveConnect(points)) {return true;}return false;}/*** 判断是否五子连珠* @param points* @return*/private boolean isFiveConnect(List<Point> points) {for (Point p : points) {int x = p.x;int y = p.y;if (isHorizontalFive(x, y, points)) {return true;} else if (isVerticalFive(x, y, points)) {return true;} else if (isSkewFive(x, y, points)) {return true;}}return false;}/*** 判断是否横向五子连珠* @param x* @param y* @param points* @return*/private boolean isHorizontalFive(int x, int y, List<Point> points) {//判断横向向右是否练成5子,points里面存的值为int类型,所以可以进行加一或者减一的运算for (int i = 0; i < MAX_NUMWIN; i++) {if (points.contains(new Point(x + i, y))) {CURRENT_NUM++;} else {break;}}if (MAX_NUMWIN == CURRENT_NUM) {return true;} else {CURRENT_NUM = 0;}//判断横向向左是否连成5子for (int i = 0; i < MAX_NUMWIN; i++) {if (points.contains(new Point(x - i, y))) {CURRENT_NUM++;} else {break;}}if (MAX_NUMWIN == CURRENT_NUM) {return true;} else {CURRENT_NUM = 0;}return false;}/*** 判断是否竖直五子连珠* @param x* @param y* @param points* @return*/private boolean isVerticalFive(int x, int y, List<Point> points) {for (int i = 0; i < MAX_NUMWIN; i++) {//判断向下是否5子连珠if (points.contains(new Point(x, y + i))) {CURRENT_NUM++;} else {break;}}if (MAX_NUMWIN == CURRENT_NUM) {return true;} else {CURRENT_NUM = 0;}//判断向上是否5子连珠for (int i = 0; i < MAX_NUMWIN; i++) {if (points.contains(new Point(x, y - i))) {CURRENT_NUM++;if (5 == CURRENT_NUM) {return true;}} else {CURRENT_NUM = 0;break;}}if (MAX_NUMWIN == CURRENT_NUM) {return true;} else {CURRENT_NUM = 0;}return false;}/*** 判断斜着是否五子连珠* @param x* @param y* @param points* @return*/private boolean isSkewFive(int x, int y, List<Point> points) {//判断左斜下是否5子连珠for (int i = 0; i < MAX_NUMWIN; i++) {if (points.contains(new Point(x - i, y + i))) {CURRENT_NUM++;} else {break;}}if (MAX_NUMWIN == CURRENT_NUM) {return true;} else {CURRENT_NUM = 0;}//判断左上是否5子连珠for (int i = 0; i < MAX_NUMWIN; i++) {if (points.contains(new Point(x - i, y - i))) {CURRENT_NUM++;} else {break;}}if (MAX_NUMWIN == CURRENT_NUM) {return true;} else {CURRENT_NUM = 0;}//判断右上是否5子连珠for (int i = 0; i < MAX_NUMWIN; i++) {if (points.contains(new Point(x + i, y - i))) {CURRENT_NUM++;} else {break;}}if (MAX_NUMWIN == CURRENT_NUM) {return true;} else {CURRENT_NUM = 0;}//判断右斜上是否5子连珠for (int i = 0; i < MAX_NUMWIN; i++) {if (points.contains(new Point(x + i, y - i))) {CURRENT_NUM++;} else {break;}}if(MAX_NUMWIN==CURRENT_NUM){return true;}else{CURRENT_NUM=0;}//判断右斜下是否5子连珠for (int i = 0; i < MAX_NUMWIN; i++) {if (points.contains(new Point(x + i, y + i))) {CURRENT_NUM++;} else {break;}}if(MAX_NUMWIN==CURRENT_NUM){return true;}else{CURRENT_NUM=0;}return false;}
}

主方法的调用

package com.yaodan.fivechessdemo;import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;import com.yaodan.fivechessdemo.view.ChessView;public class MainActivity extends AppCompatActivity implements View.OnClickListener {private Button btn_reatart;private ChessView chessView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btn_reatart = (Button) findViewById(R.id.bt_restart);chessView= (ChessView) findViewById(R.id.custon_chess_main);btn_reatart.setOnClickListener(this);}@Overridepublic void onClick(View view) {switch (view.getId()) {case R.id.bt_restart:chessView.myreStart();break;}}
}

Android五子棋游戏源码详解相关推荐

  1. android五子棋源代码,Android五子棋游戏源码详解

    最近看了鸿洋大牛的五子棋教程,受益匪浅,讲的非常好,关于五子棋的游戏原理非常清楚,并且学到了不少知识,在这里感谢鸿洋大神的分享.我觉得我的源码注释写的非常清楚了,希望能给你带来不少的收获. 布局< ...

  2. Android 事件分发机制分析及源码详解

    Android 事件分发机制分析及源码详解 文章目录 Android 事件分发机制分析及源码详解 事件的定义 事件分发序列模型 分发序列 分发模型 事件分发对象及相关方法 源码分析 事件分发总结 一般 ...

  3. Android AR开发实践之七:OpenGLES相机预览背景绘制源码详解

    Android AR开发实践之七:OpenGLES相机预览背景绘制源码详解 目录 Android AR开发实践之七:OpenGLES相机预览背景绘制源码详解 一.OpenGL ES渲染管线 1.基本处 ...

  4. Extreme Drift赛车游戏C#源码详解(1)

    Extreme Drift赛车游戏C#源码详解(1) C#我只是一个萌新,由于搞过Java,还是可以看懂C#的 偶然间得到赛车游戏Extreme Drift的源码 接下来我会花一段时间来解读,这是一个 ...

  5. 源码详解Android 9.0(P) 系统启动流程之SystemServer

    源码详解Android 9.0(P) 系统启动流程目录: 源码详解Android 9.0(P)系统启动流程之init进程(第一阶段) 源码详解Android 9.0(P)系统启动流程之init进程(第 ...

  6. Android编程之Intent源码详解

    Intent源码详解,直接开始入题: Intent源码6700多行代码,但真正核心代码 就那么几百行,大部分都用来定义常量字符串了 先来看一下 public class Intent implemen ...

  7. cocos android-1,Cocos2D-Android-1之源码详解:5.Box2dTest

    Cocos2D-Android-1之源码详解:5.Box2dTest 发布时间:2020-08-06 06:19:28 来源:51CTO 阅读:398 作者:abab99 package org.co ...

  8. Integer源码详解

    尊重原创,转载请标明出处    http://blog.csdn.net/abcdef314159 对于Integer这个类估计大家也都非常熟悉了,以前看过他的源码,但也只是粗略的看了一下,最近有时间 ...

  9. OkHttp3源码详解

    前言:为什么有些人宁愿吃生活的苦也不愿吃学习的苦,大概是因为懒惰吧,学习的苦是需要自己主动去吃的,而生活的苦,你躺着不动它就会来找你了. 一.概述 OKHttp是一个非常优秀的网络请求框架,已经被谷歌 ...

  10. 【Live555】live555源码详解(九):ServerMediaSession、ServerMediaSubsession、live555MediaServer

    [Live555]live555源码详解系列笔记 继承协作关系图 下面红色表示本博客将要介绍的三个类所在的位置: ServerMediaSession.ServerMediaSubsession.Dy ...

最新文章

  1. Oracle VM VirtualBox安裝Windows 2000失败
  2. python 访问网页 重定向_Python数据网络采集5--处理Javascript和重定向
  3. 关于JAVA匿名内部类,回调,事件模式的一点讨论
  4. java api apk_java-如何在APK文件中保护此API
  5. 谈如何边做事,边提高
  6. 微软说:麻将AI系统终获突破,人工智能商学院来啦!
  7. Android APK实现WIFI协议包抓取(上)-实现思路
  8. html扫雷源码js,js实现扫雷源代码.pdf
  9. php实现ts流切片,HLS-m3u8播放列表和ts切片(2)
  10. 高速公路ETC自由流收费技术
  11. 打开IDEA遇到:The license has been cancelled
  12. linux 家用路由器,饱受折磨的家用路由器 | 在研究的127个家用路由器中,没有一个路由器幸免...
  13. 2022-03-25 Python作业3
  14. 计算器ajax实现代码,jQuery实现计算器功能
  15. zarchiver解压提示出错_zarchiver解压操作出错怎么办 zarchiver解压操作出错解决办法...
  16. python网球比赛模拟主持稿_主持人大赛模拟主持环节情景
  17. zbb20170216_spring_aop
  18. 手机号码归属地查询,免费API
  19. 在Windows下架设FTP服务器
  20. android:ellipsize=end在ConstraintLayout中无效的问题

热门文章

  1. Android项目开发实战——简单备忘录
  2. java实现账号登陆界面_java用户登录界面的代码
  3. 文华软件怎样测试交易系统的收益,交易系统的测试与评估报告
  4. java生成excel图表
  5. Java毕业设计-学生选课管理系统
  6. 软件jmeter压力测试实例,jmeter压力测试案例实战
  7. 记工软件 包工头记工软件 建筑记工软件 工程记工软件
  8. SQL常用语句(普通查询+条件查询)
  9. JAVA编程练习50题超详细
  10. 64java下载_java软件下载|java64 v8.0 官方版-520下载站