您的位置:首页 > 移动开发 > Android开发

Android自定义View的数独游戏

2016-12-14 12:40 381 查看

Android自定义View的数独游戏

先说一下数独游戏的规则

在整个横坐标和纵坐标的9个格子上只能填土1-9的数字且不重复
在当前3*3 的格子上填入1-9数字且不重复


先给大家看效果图



项目思路

1、UI呈现:这个放在 GameView 类里面
显示原始数据
显示当然用户填写的数据
显示用户当前点击的位置
显示候选区数据

2、逻辑处理:这个是放在Matrix类里面的
原始数据:游戏开始的时候就要创建出来的,
当前数据:用户填写上去的实时数据
数据判断:判断这个位置可以修改数据吗? 比如,原始数据就是不可以修改的
判断这个位置可以填入的数据,比如,原始数据这个位置有8了,就不能填8了。


代码 GameView 类

public class GameView extends View {

private int PhoneWidth; // 手机屏幕的宽度
private int mGridWidth; // 当前格子的宽度

private int[] mFalseNumber; // 候选区不能填写的数字

private Paint mLinePaint; // 白线
private Paint mDarkPaint; // 浅蓝色的 方格子
private Paint mOptDarkPaint; // 用户点击 浅绿色的格子
private Paint numberPaint; // 原始数据 数字
private Paint changePaint; // 用户填写的数字
private Paint mOptPaint; // 候选区数字

private Matrix M; // 用户计算类

private float tCX;
private float tCY;
private int mOptBoard;
private int mOptNumber;

public GameView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}

public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}

public GameView(Context context) {
super(context);

initView();
}

private void initView() {

PhoneWidth = getResources().getDisplayMetrics().widthPixels;
mGridWidth = (PhoneWidth - 40) / 9;

tCX = mGridWidth / 2;
tCY = tCX - tCX / 2;

mFalseNumber = new int[9];

for (int i = 0; i < 9; i++) {
mFalseNumber[i] = i;
}

M = new Matrix();
initPaint();

invalidate();
}

private void initPaint() {
mLinePaint = new Paint();
mLinePaint.setColor(Color.WHITE);
mLinePaint.setStyle(Paint.Style.STROKE);
mLinePaint.setStrokeWidth(2f);

mDarkPaint = new Paint();
mDarkPaint.setColor(Color.parseColor("#52E7CD"));
mDarkPaint.setStyle(Paint.Style.FILL);

numberPaint = new Paint();
numberPaint.setColor(Color.WHITE);
numberPaint.setTextSize(mGridWidth * 0.65f);
numberPaint.setTextAlign(Paint.Align.CENTER);
numberPaint.setShadowLayer(10F, -5F, 8F, Color.parseColor("#999999"));
numberPaint.setAntiAlias(true);

mOptPaint = new Paint();
mOptPaint.setColor(Color.WHITE);
mOptPaint.setTextSize(mGridWidth * 0.65f+15);
mOptPaint.setTextAlign(Paint.Align.CENTER);
mOptPaint.setShadowLayer(10F, -5F, 8F, Color.parseColor("#999999"));
mOptPaint.setAntiAlias(true);

changePaint = new Paint();
changePaint.setColor(Color.parseColor("#FCA454"));
changePaint.setTextSize(mGridWidth * 0.65f);
changePaint.setTextAlign(Paint.Align.CENTER);
changePaint.setShadowLayer(10F, -5F, 8F, Color.parseColor("#999999"));
changePaint.setAntiAlias(true);

mOptDarkPaint = new Paint();
mOptDarkPaint.setColor(Color.parseColor("#52E76E"));
mOptDarkPaint.setStyle(Paint.Style.FILL);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(PhoneWidth, PhoneWidth + mGridWidth+20);
}

@Override
protected void onDraw(Canvas canvas) {

drawBoard(canvas);

int x = mOptBoard / 9;
int y = mOptBoard % 9;
// 画出棋盘选择框
canvas.drawRect(x * mGridWidth+22, y * mGridWidth+22, x * mGridWidth+20 + mGridWidth, y * mGridWidth+20 + mGridWidth, mOptDarkPaint);

// 当前棋盘数据
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
int cutData = M.getCutData(i, j);
if (M.getOnClicked(i,j) && cutData>0) {
canvas.drawText(Integer.toString(cutData), i * mGridWidth + tCX+20, j*mGridWidth + mGridWidth - tCY+20, changePaint);
}
}
}

// 候选区文字

drawTrueText(canvas);

}

private void drawTrueText(Canvas canvas) {
float startY = PhoneWidth + 30;

// 画平行四边形
canvas.drawLine(50, startY, PhoneWidth-50, startY, mLinePaint);
canvas.drawLine(10, startY + mGridWidth - 40, PhoneWidth-10, startY + mGridWidth-40, mLinePaint);
canvas.drawLine(50, startY, 10, startY + mGridWidth - 40, mLinePaint);
canvas.drawLine(PhoneWidth-50, startY, PhoneWidth-10, startY + mGridWidth-40, mLinePaint);

float y = (mGridWidth - 30)/2.0f;

for (int i = 0; i < 9; i++) {
if (mFalseNumber[i] == 0) {
canvas.drawText(Integer.toString(i+1), i * mGridWidth + tCX+ 20, startY + (mGridWidth - tCY) - y, mOptPaint);
}
}
}

private void drawBoard(Canvas canvas) {

// 画底色
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
int x = i / 3;
int y = j / 3;
if ((x == 0 || x == 2) && (y == 0 || y == 2)) {
canvas.drawRect(mGridWidth * j + 20, 20 + mGridWidth * i,
mGridWidth * j + 20 + mGridWidth, 20 + mGridWidth
* i + mGridWidth, mDarkPaint);
} else if (y == 1 && x == 1) {
canvas.drawRect(mGridWidth * j + 20, 20 + mGridWidth * i,
mGridWidth * j + 20 + mGridWidth, 20 + mGridWidth
* i + mGridWidth, mDarkPaint);
}

}
}

// 画白线
for (int i = 0; i < 10; i++) {
canvas.drawLine(20, mGridWidth * i + 1 + 20, 9 * mGridWidth + 20,
mGridWidth * i + 1 + 20, mLinePaint);
canvas.drawLine(mGridWidth * i + 1 + 20, 0 + 20, mGridWidth * i + 1
+ 20, 9 * mGridWidth + 20, mLinePaint);
}

//画初始数字
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (!M.getOnClicked(i, j)) {
canvas.drawText(M.getText(i, j), i * mGridWidth +20+tCX, mGridWidth * j + 20+mGridWidth-tCY, numberPaint);

}
}
}
}

@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_DOWN) {
return super.onTouchEvent(event);
}

if (event.getX()<20 || event.getY()<20 || event.getX()>PhoneWidth-20) {
Log.e("123", "点到边了");
return super.onTouchEvent(event);
}

int choX = (int) ((event.getX()-20) / mGridWidth);
int choY = (int) ((event.getY()-20) / mGridWidth);

Log.i("game  ", "optX "+choX+"  optY  "+choY);

if (event.getY() < PhoneWidth-20) { // 棋盘的点击

if (M.getOnClicked(choX, choY)) {
mFalseNumber = new int[9];
int[] trueData = M.getFalseData(choY, choX);
mOptBoard = choX * 9 + choY;
for (int i : trueData) {
mFalseNumber[i - 1] = 1;
}

}

} else { // 候选区点击
Log.e("game  ","opt Number " + choX + 1);

System.out.println(Arrays.toString(mFalseNumber));

if (mFalseNumber[choX] == 0) {
mOptNumber = choX;
int x = mOptBoard / 9;
int y = mOptBoard % 9;
M.setCutData(x, y, mOptNumber+1);
}

}
invalidate();

return true;
}

// 再来一局
public void play() {
initView();
}
// 重头开始
public void repeat(){
M.initCutData();
invalidate();
}


代码 Matrix类

public class Matrix {

private int [][]mData ; // 原始数据
private int [][]mCutData; // 当前数据

public Matrix() {

int i = (int)(Math.random()*5);

switch (i) {
case 1:
mData = GAMEDATA1;
break;
case 2:
mData = GAMEDATA2;
break;
case 3:
mData = GAMEDATA3;
break;
case 4:
mData = GAMEDATA4;
break;
case 0:
mData = GAMEDATA2;
break;

}
initCutData();
Log.e("Matrix", "random  :"+i);

}

/** 得到当前坐标上的文字 */
public String getText(int x, int y){

String index = mData[x][y]+"";

if ("0".equals(index)) {
index = "";
}

return index;

}

/** 判断该坐标是否可以点击 */
public boolean getOnClicked(int x, int y){

if (mData[x][y] == 0) {
return true;
}
return false;

}

/** 判断该坐标有哪些数不可用 */
public int[] getFalseData(int x, int y){
Set<Integer> set = new TreeSet<Integer>();

// 检查X 轴有哪些不能点

for (int i = 0; i < 9; i++) {
int d = mData[y][i];

if (d!=0) {
set.add(d);
//              LogUtils.e("x: "+d);
}
}
// 检查 y 轴有哪些不能点
for (int i = 0; i < 9; i++) {
int d = mData[i][x];
if (d!=0) {
set.add(d);
//              LogUtils.e("Y: "+d);
}
}

// 检查 3*3 方格哪些不能点

x = x/3*3;
y = y/3*3;

//      LogUtils.e(" x "+x+"  Y  "+y);

for (int i = x; i < x+3; i++) {
for (int j = y; j < y+3; j++) {
int d = mData[j][i];
if (d!=0) {
set.add(d);
//                  LogUtils.e("i "+i+"j "+j+" xy: "+d);
}
}
}

Integer[] arr2 = set.toArray(new Integer[0]);
// 数组的包装类型不能转 只能自己转;吧Integer转为为int数组;
int[] result = new int[arr2.length];
for (int i = 0; i < result.length; i++) {
result[i] = arr2[i];
}
System.out.
bb12
println("false Number : "+Arrays.toString(result));

return result;
}

/** 当前棋盘数据 */
public void initCutData(){

mCutData = new int[9][9];

for (int i = 0; i < mData.length; i++) {
for (int j = 0; j < mData[i].length; j++) {
mCutData[i][j] = mData[i][j];
}
}

for (int i = 0; i < mCutData.length; i++) {
System.out.println(Arrays.toString(mCutData[i]));
}

}

public void setCutData(int x, int y, int data){
if (getOnClicked(x, y)) {
mCutData[x][y] = data;
}

}

public int getCutData(int x, int y){
return mCutData[x][y];
}
}


代码 MainActivity 类

public class MainActivity extends Activity {

private GameView gV;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

gV = (GameView) findViewById(R.id.game);
}

public void rePay(View v){
gV.repeat();
}
public void newPay(View v){
gV.play();

}


acitivity_main.xml 文件

<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="#0EC5A5"
android:orientation="vertical" >

<TextView
android:layout_width="match_parent"
android:layout_height="52dp"
android:layout_marginTop="10dp"
android:gravity="center"
android:text="SUDOKU"
android:textColor="@android:color/white"
android:textSize="30sp" />

<com.xuan.sudokugame.GameView
android:id="@+id/game"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:padding="10dp"
android:orientation="horizontal" >

<Button
android:layout_width="0dp"
android:onClick="rePay"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginRight="10dp"
android:text="重新开始"
android:textColor="@android:color/white"
android:background="@drawable/radius_border_gray"/>
<Button
android:onClick="newPay"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="再来一局"
android:textColor="@android:color/white"
android:background="@drawable/radius_border_gray"/>
</LinearLayout>

</LinearLayout>


然后运行起来就是这个样子的了

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息