package com.example.administrator.viewapp;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
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 android.widget.Toast;
import java.util.ArrayList;
/**
* Created by Zyh on 2016/11/18.
*/
public class WuZiPanel extends View {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//系统传递的参数widthMeasureSpec和heightMeasureSpec,我们可以根据这两个参数获取当前控件的宽高
//首先获取当前的大小
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
//我们画正方形需要去宽和高中的最小值
int width = Math.min(widthSize, heightSize);
//然后将测量的结果设置给系统,这个方法是最终设置自定义view大小的方法
setMeasuredDimension(width, width);
// Log.d("系统给我们的宽度-------------->", "" + width);
// Log.d("系统给我们的宽度(转换后)---->", widthSize+"----" + heightSize);
//初始化棋盘宽度和线的间距,需要在setMeasureDimsion之后进行
}
//在onMeasure中调用setMeasuredDimension方法之后,接下来系统会执行onSizeChanged方法
//所以初始化棋盘宽度和线的间距要在onSizeChanged中进行
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
Log.d("new-----------",w+"----"+h);
Log.d("old-----------",oldw+"---"+oldh);
mPanelWidth = w;
mLineHeight = w * 1.0f / MAX_LIME;//首先将宽度转换成float类型
//规定旗子的宽高
int width = (int) (mLineHeight * 3 / 4);
//按比例重新设置宽高
mWhitePiece = Bitmap.createScaledBitmap(mWhitePiece, width, width, false);
mBlackPiece = Bitmap.createScaledBitmap(mBlackPiece, width, width, false);
}
//初始化画笔,
private Paint mPaint = new Paint();
//横线竖线的数量,
private static final int MAX_LIME = 12;
//棋盘的宽度,和高度
private int mPanelWidth;
//线和线之间的间距
private float mLineHeight;
//记录白棋和黑棋的落子位置
private ArrayList<Point> mWhiteArry = new ArrayList<>();
private ArrayList<Point> mBlackArray = new ArrayList<>();
private boolean mIsWhite = true;//判断目前谁走
//系统会默认调用两个参数的构造方法
public WuZiPanel(Context context, AttributeSet attrs) {
super(context, attrs);
// 0X--代表16进制的数值的写法前缀
setBackgroundColor(0x66ff0000);
mPaint.setStrokeWidth(2);//设置画笔的宽度
mPaint.setTextSize(18);
inte();
}
private void inte() {
mPaint.setColor(0xaa000000);
mPaint.setStyle(Paint.Style.STROKE); //设置划一条线
mWhitePiece = BitmapFactory.decodeResource(getResources(), R.mipmap.baizi);
mBlackPiece = BitmapFactory.decodeResource(getResources(), R.mipmap.heizi);
}
/**
* onTouchEvent内有四个返回值:true,false,和super.onTouchEvent(event)
* true:表示拦截此次事件,不再交给其他方法使用
* false:表示对此次事件不感兴趣,让系统分发给其他的方法
*
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
//游戏已结束那么点击事件就不关心了
if (misGameOver){
return false;
}
//MotionEvent.ACTION_DOWN--指鼠标点下的事件
//MotionEvent.ACTION_UP---指鼠标抬起的事件
if (event.getAction() == MotionEvent.ACTION_UP) {
// Toast.makeText(getContext(), "鼠标抬起事件", Toast.LENGTH_SHORT).show();
int x = (int) event.getX();
int y = (int) event.getY();
Point p = new Point((int) (x / mLineHeight), (int) (y / mLineHeight));
//表示不能重复落子,那么此次的点击事件我们交给系统,我们不做任何的处理
if (mWhiteArry.contains(p) || mBlackArray.contains(p)) {
return false;
}
//如果正确落子,记录当前的落子的位置,并将它加入黑白集合当中
mCurPoint=p;
// Toast.makeText(getContext(), (int) (y / mLineHeight) + "当前交叉点的坐标" + (int) (x / mLineHeight), Toast.LENGTH_SHORT).show();
//判断该谁走
if (mIsWhite) {
mWhiteArry.add(new Point((int) (x / mLineHeight), (int) (y / mLineHeight)));
mIsWhite = false;
} else {
mBlackArray.add(new Point((int) (x / mLineHeight), (int) (y / mLineHeight)));
mIsWhite = true;
}
// Toast.makeText(getContext(), x + "---" + y, Toast.LENGTH_SHORT).show();
//记录下点击的位置,请求重新绘制界面,重新调用onDraw方法
invalidate();//作用重新调用onDraw
postInvalidate();//请求在非UI线程中重绘
return true;//这里代表我们已经处理过点击事件不需要去返回给系统
}
//我们必须首先将点击下的动作拦截下来才能接下来拦截抬起的动作
else if (event.getAction() == MotionEvent.ACTION_DOWN) {
// Toast.makeText(getContext(), "鼠标抬起事件", Toast.LENGTH_SHORT).show();
return true;
}
return super.onTouchEvent(event);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/**canvas---画布,系统提供
canvas.drawLine(0,0,300,300,mPaint);//画一条线:参数起始的坐标和终止的坐标以及画笔
canvas.drawCircle(150,150,40,mPaint);//画圆,起始坐标指定的是圆心的坐标
canvas.drawText("我的世界",150,150,mPaint);//写字,参数说明:字体,起始坐标,画笔
canvas.drawRect(10,10,200,200,mPaint);//画矩形
画Bitmap,
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher),0,0,mPaint);
*/
drawBoard(canvas);
drawPiece(canvas);
//每一次落子之后都要进行胜负判断
checkGameIsOver();
}
private boolean misGameOver=false;
private boolean misWhiteWinner=false;
private void checkGameIsOver() {
boolean isBlackWin=false;
boolean isWhiteWin=false;
if (mIsWhite){
isBlackWin=checkFiveInLine(mBlackArray);
}else {
isWhiteWin=checkFiveInLine(mWhiteArry);
}
if (isBlackWin||isWhiteWin){
//只要有一个胜利,那么游戏就结束
misGameOver=true;
misWhiteWinner=isWhiteWin;
//写一个监听的接口,将胜负发送到对应的activity中处理
//问号在这里表示判断的
String str=misWhiteWinner?"白棋胜利":"黑棋胜利";
Toast.makeText(getContext(),str, Toast.LENGTH_SHORT).show();
}
}
private Point mCurPoint;
private boolean checkFiveInLine(ArrayList<Point> mArry) {
//如果落下的是白子,mIsWhite是false,如果落下的是黑子,那么mIsWhite是true
// if ((!mIsWhite&&isWhite)||(mIsWhite&&!isWhite)){
// //mCurPoint白棋+白棋mArray或者mCurPoint黑棋+黑棋mArray
// //符合这两种情况接下来往下判断,否则跳出
// }else {
// return false;
// }
//如果当前位置旗子的位置不为空,判断他的四个方向是否满足胜利条件
if (mCurPoint!=null){
// Toast.makeText(getContext(),x+""+y, Toast.LENGTH_SHORT).show();
if (checkHorIsFive(mArry,mCurPoint))
return true;
if (checkVerIsFive(mArry,mCurPoint)){
return true;
}
if (checkRightAngileIsFive(mArry,mCurPoint)){
return true;
}
if (checkLelfeAngileIsFive(mArry,mCurPoint)){
return true;
}
}
return false;
}
private boolean checkHorIsFive(ArrayList<Point> mArry,Point mPoint) {
//首先判断横向是否凑齐五个子 第二次遍历向右判断
int x=mCurPoint.x;
int y=mCurPoint.y;
int count=1;
boolean isFirstBreak=true;
boolean isSecondBreak=true;
for (int i=1;i<5;i++){
if (isFirstBreak){
if (mArry.contains(new Point(x-i,y))){
count++;
}else {
//向右判断
isFirstBreak=false;
}
}
//如果是true的话,就代表当前位置旗子右边有相同的子,count加1
if (isSecondBreak){
if (mArry.contains(new Point(x+i,y))){
count++;
}else {
//向右判断
isSecondBreak=false;
}
}
//如果已经达到5颗子,跳出循环
}
if(count==5){
return true;
}else {
return false;
}
}
private boolean checkVerIsFive(ArrayList<Point> mArry,Point mPoint) {
//首先判断横向是否凑齐五个子 第二次遍历向右判断
int x=mCurPoint.x;
int y=mCurPoint.y;
int count=1;
boolean isFirstBreak=true;
boolean isSecondBreak=true;
for (int i=1;i<5;i++){
if (isFirstBreak){
if (mArry.contains(new Point(x,y-i))){
count++;
}else {
//向右判断
isFirstBreak=false;
}
}
//如果是true的话,就代表当前位置旗子右边有相同的子,count加1
if (isSecondBreak){
if (mArry.contains(new Point(x,y+i))){
count++;
}else {
//向右判断
isSecondBreak=false;
}
}
//如果已经达到5颗子,跳出循环
}
if(count==5){
return true;
}else {
return false;
}
}
private boolean checkRightAngileIsFive(ArrayList<Point> mArry,Point mPoint) {
//首先判断横向是否凑齐五个子 第二次遍历向右判断
int x=mCurPoint.x;
int y=mCurPoint.y;
int count=1;
boolean isFirstBreak=true;
boolean isSecondBreak=true;
for (int i=1;i<5;i++){
if (isFirstBreak){
if (mArry.contains(new Point(x-i,y-i))){
count++;
}else {
//向右判断
isFirstBreak=false;
}
}
//如果是true的话,就代表当前位置旗子右边有相同的子,count加1
if (isSecondBreak){
if (mArry.contains(new Point(x+i,y+i))){
count++;
}else {
//向右判断
isSecondBreak=false;
}
}
//如果已经达到5颗子,跳出循环
}
if(count==5){
return true;
}else {
return false;
}
}
private boolean checkLelfeAngileIsFive(ArrayList<Point> mArry,Point mPoint) {
//首先判断横向是否凑齐五个子 第二次遍历向右判断
int x=mCurPoint.x;
int y=mCurPoint.y;
int count=1;
boolean isFirstBreak=true;
boolean isSecondBreak=true;
for (int i=1;i<5;i++){
if (isFirstBreak){
if (mArry.contains(new Point(x-i,y+i))){
count++;
}else {
//向右判断
isFirstBreak=false;
}
}
//如果是true的话,就代表当前位置旗子右边有相同的子,count加1
if (isSecondBreak){
if (mArry.contains(new Point(x+i,y-i))){
count++;
}else {
//向右判断
isSecondBreak=false;
}
}
//如果已经达到5颗子,跳出循环
}
if(count==5){
return true;
}else {
return false;
}
}
private void drawPiece(Canvas canvas) {
//画旗子的方法
for (int i = 0; i < mWhiteArry.size(); i++) {
Point point = mWhiteArry.get(i);
float x = (float) ((point.x + 1.0 / 8) * mLineHeight);
float y = (float) ((point.y + 1.0 / 8) * mLineHeight);
canvas.drawBitmap(mWhitePiece, x, y, null);
}
for (int i = 0; i < mBlackArray.size(); i++) {
Point point = mBlackArray.get(i);
float x = (float) ((point.x + 1.0 / 8) * mLineHeight);
float y = (float) ((point.y + 1.0 / 8) * mLineHeight);
canvas.drawBitmap(mBlackPiece, x, y, null);
}
}
private Bitmap mWhitePiece;
private Bitmap mBlackPiece;
private void drawBoard(Canvas canvas) {
int w = mPanelWidth;
float lineHeight = mLineHeight;
for (int i = 0; i < MAX_LIME; i++) {
int startX = (int) (lineHeight / 2);
int endX = w - startX;
int Y = (int) ((0.5 + i) * lineHeight);
canvas.drawLine(startX, Y, endX, Y, mPaint);
}
for (int i = 0; i < MAX_LIME; i++) {
int starY = (int) (lineHeight / 2);
int X = (int) ((int) (lineHeight / 2) + i * lineHeight);
int endY = (int) (w - lineHeight / 2);
canvas.drawLine(X, starY, X, endY, mPaint);
}
}
/**
* 状态的保存和恢复,
* @return
*/
private static final String INSTANCE="INSTANCE";
private static final String INSTANCE_mWhiteArry="mWhiteArry";
private static final String INSTANCE_mBlackArray="mBlackArray";
private static final String INSTANCE_misGameOver="misGameOver";
private static final String INSTANCE_mIsWhite="mIsWhite";
@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle=new Bundle();
bundle.putParcelableArrayList(INSTANCE_mWhiteArry,mWhiteArry);
bundle.putParcelableArrayList(INSTANCE_mBlackArray,mBlackArray);
bundle.putBoolean(INSTANCE_misGameOver,misGameOver);
bundle.putBoolean(INSTANCE_mIsWhite,mIsWhite);
bundle.putParcelable(INSTANCE,super.onSaveInstanceState());
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
//如果是bundle类型就表明我们传递的有值,屏幕发生旋转或者activity强制被杀死,保存过信息
if (state instanceof Bundle){
Bundle bundle= (Bundle) state;
mIsWhite=bundle.getBoolean(INSTANCE_mIsWhite,false);
misGameOver=bundle.getBoolean(INSTANCE_misGameOver,false);
mBlackArray=bundle.getParcelableArrayList(INSTANCE_mBlackArray);
mWhiteArry=bundle.getParcelableArrayList(INSTANCE_mWhiteArry);
super.onRestoreInstanceState(bundle.getParcelable(INSTANCE));
return;
}
super.onRestoreInstanceState(state);
}
}