android开发——数独游戏

时间:2024-01-11 22:31:38

最近研究了一下android,写了一个数独游戏,具体如下:

游戏界面需要重写一个ShuduView继承View,

然后自定义一个Dialog:

1.需要继承 Dialog 类,

2.并要定义一个有参构造函数(因为父类里面没有无参构造函数)

3.重写 onCreate方法,一切操作将在此方法进行

流程:

为每个按钮添加监听事件,

刷新九宫格里的数字,也就是重新绘制画面(在view类中调用 invalidate();),

更新备选数字数组 ( 每次修改之后都得 进行重新计算 不可用的值   calculateAllUsedTiles() ; )

下面介绍主要代码:

ShuduView:

 package com.soccer.shudu;

 import android.content.Context;
import android.graphics.*;
import android.graphics.Paint.FontMetrics; import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager; public class ShuduView extends View{ public ShuduView(Context context) {
super(context);
// TODO Auto-generated constructor stub
} private float width;
private float height; private Game game = new Game(); @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
//计算当前单元格宽度和高度
this.height = h / 9f;
this.width = w / 9f;
super.onSizeChanged(w, h, oldw, oldh);
} //当android的系统需要绘制一个view对象时,就需要调用该对象的onDraw方法
@Override
protected void onDraw(Canvas canvas) {
//生成用户绘制背景色的画笔
Paint backgroundPaint = new Paint();
//设置画笔颜色
backgroundPaint.setColor(getResources().getColor(R.color.shudu_background));
//绘制背景色
canvas.drawRect(0, 0, getWidth(), getHeight(), backgroundPaint); Paint darkPaint = new Paint();
darkPaint.setColor(getResources().getColor(R.color.shudu_dark)); Paint hilitePaint = new Paint();
hilitePaint.setColor(getResources().getColor(R.color.shudu_hilite)); Paint lightPaint = new Paint();
lightPaint.setColor(getResources().getColor(R.color.shudu_light)); for(int i = 0;i < 9;i++){
//绘制横向的线
canvas.drawLine(0, i * height,getWidth(), i * height, lightPaint);
canvas.drawLine(0, i * height + 1,getWidth(), i * height + 1, hilitePaint);
//绘制纵向的线
canvas.drawLine(i * width, 0, i * width, getHeight(), lightPaint);
canvas.drawLine(i * width + 1, 0, i * width + 1, getHeight(), hilitePaint);
} for(int i = 0;i < 3;i++){
//绘制横向的线
canvas.drawLine(0, i * 3 * height, getWidth(), i * 3 * height, darkPaint);
canvas.drawLine(0, i * 3 * height + 1, getWidth(), i * 3 * height + 1, darkPaint);
//绘制纵向的线
canvas.drawLine(i * 3 * width, 0, i * 3 * width, getHeight(), darkPaint);
canvas.drawLine(i * 3 * width + 1, 0, i * 3 * width + 1, getHeight(), darkPaint);
}
//绘制数字
Paint numberPaint = new Paint();
numberPaint.setColor(Color.BLACK);
//numberPaint.setStyle(Paint.Style.STROKE);
numberPaint.setTextSize( height * 0.75f);
numberPaint.setTextAlign(Paint.Align.CENTER);
//将数字加到格子中
FontMetrics fm = numberPaint.getFontMetrics();
float x = width / 2;
float y = height / 2 - (fm.ascent + fm.descent) / 2;
//canvas.drawText("1", 3 * width + x, height + y , numberPaint);
for(int i = 0;i < 9;i++){
for(int j = 0;j < 9;j++){
canvas.drawText(game.getTileString(i, j), i * width+x, j * height + y, numberPaint);
}
} super.onDraw(canvas);
} int selectedX;
int selectedY; @Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() != MotionEvent.ACTION_DOWN){
return super.onTouchEvent(event);
} selectedX = (int)(event.getX() / width);
selectedY = (int)(event.getY() / height); int used[] = game.getUsedTileByCoor(selectedX, selectedY);
StringBuffer sb = new StringBuffer();
for(int i = 0; i < used.length;i++){
System.out.println(used[i] );
//sb.append(used[i]);
} //生成一个LayoutInflater对象
//LayoutInflater layoutInflater = LayoutInflater.from(this.getContext());
//View layoutView = layoutInflater.inflate(R.layout.dialog, null);
//从生成好的textView中 取出相应的控件
//TextView textView =(TextView)layoutView.findViewById(R.id.usedTextId); //textView.setText(sb.toString()); //AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext());
//builder.setView(layoutView); //AlertDialog dialog = builder.create();
//dialog.show();
//dialog.getWindow().setLayout(300, 200);
KeyDialog keyDialog = new KeyDialog(getContext(), used,this);
//透明度
WindowManager.LayoutParams lp=keyDialog.getWindow().getAttributes();
lp.alpha=0.9f;
keyDialog.getWindow().setAttributes(lp); keyDialog.show();
return true;
} public void setSelectedTile(int tile){ if(game.setTileIfValid(selectedX,selectedY,tile)){
invalidate();
}
} }

KeyDialog:

 package com.soccer.shudu;

 import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Button; //该类用于实现dialog自定义对话框功能
public class KeyDialog extends Dialog{
private final View keys [] = new View[9];
private final int used[]; private ShuduView shuduView = null; public KeyDialog(Context context,int [] used,ShuduView shuduView){
super(context);
this.used = used;
this.shuduView = shuduView;
}
//当一个dialog第一次显示的时候,会调用其onCreate方法
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle("可选数字");
setContentView(R.layout.keypad);
findViews();
for(int i = 0;i < used.length;i++){
if(used[i] != 0){
keys[used[i] - 1].setVisibility(View.INVISIBLE);
}
}
//为每个键设置监听器
setListeners(); //为返回按钮设置监听器
Button back_Button = (Button)findViewById(R.id.back_1);
back_Button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss(); }
});
} private void findViews(){
keys[0] = findViewById(R.id.keypad_1);
keys[1] = findViewById(R.id.keypad_2);
keys[2] = findViewById(R.id.keypad_3);
keys[3] = findViewById(R.id.keypad_4);
keys[4] = findViewById(R.id.keypad_5);
keys[5] = findViewById(R.id.keypad_6);
keys[6] = findViewById(R.id.keypad_7);
keys[7] = findViewById(R.id.keypad_8);
keys[8] = findViewById(R.id.keypad_9);
} //通知ShuduView对象,刷新整个九宫格显示的数据
private void returnResult(int tile){
shuduView.setSelectedTile(tile);
dismiss();
} private void setListeners(){
for(int i = 0; i < keys.length; i++){
final int t = i + 1;
keys[i].setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View v) {
returnResult(t); }
});
}
} }

keypad.xml:

 <?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/keypad"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:stretchColumns="*" > <TableRow>
<Button android:id="@+id/keypad_1"
android:text="1">
</Button>
<Button android:id="@+id/keypad_2"
android:text="2">
</Button>
<Button android:id="@+id/keypad_3"
android:text="3">
</Button>
</TableRow> <TableRow>
<Button android:id="@+id/keypad_4"
android:text="4">
</Button>
<Button android:id="@+id/keypad_5"
android:text="5">
</Button>
<Button android:id="@+id/keypad_6"
android:text="6">
</Button>
</TableRow> <TableRow>
<Button android:id="@+id/keypad_7"
android:text="7">
</Button>
<Button android:id="@+id/keypad_8"
android:text="8">
</Button>
<Button android:id="@+id/keypad_9"
android:text="9">
</Button>
</TableRow> <TableRow>
<Button android:text="">
</Button>
<Button android:id="@+id/back_1"
android:text="@string/back_1">
</Button>
<Button android:text="">
</Button>
</TableRow> </TableLayout>

Game.java:

 package com.soccer.shudu;

 public class Game {
//数独初始化数据
private final String str = "360000000004230800000004200"
+"070460003820000014500013020"
+"001900000007048300000000045";
private int sudoku [] = new int[9*9];
//用于存储每个单元格已经不可用的数据
private int used[][][] = new int[9][9][]; public Game(){
sudoku = fromPuzzleString(str);
calculateAllUsedTile();
}
//根据九宫格当中的坐标,返回该坐标对应的数字
private int getTile(int x,int y){
return sudoku[y*9 + x];
}
private void setTile(int x,int y,int value){
sudoku[y * 9 + x] = value;
} public String getTileString(int x, int y){
int v = getTile(x,y);
if(v == 0){ //0就不显示
return "";
}
else
return String.valueOf(v);
}
protected boolean setTileIfValid(int x,int y,int value){
int tiles[] = getUsedTileByCoor(x,y);
if(value != 0){
for(int tile : tiles){
if(tile == value)
return false;
}
}
setTile(x,y,value);
calculateAllUsedTile();
return true;
} //根据一个字符串数据生成一个整形数组,作为数独游戏的初始化数据
protected int[] fromPuzzleString(String src){
int []sudo = new int[src.length()];
for(int i = 0;i < sudo.length;i++)
{
sudo[i] = src.charAt(i) - '0';
}
return sudo;
} //计算所有单元格对应的不可用数据
public void calculateAllUsedTile(){
for(int x = 0;x < 9;x++){
for(int y = 0;y < 9;y++){
used[x][y] = calculateUsedTiles(x, y);
}
}
} //取出某一单元格当中已经不可用的数据
public int[] getUsedTileByCoor(int x,int y){
return used[x][y];
} //计算某一单元格当中已经不可用的数据
public int[] calculateUsedTiles(int x,int y){
int c[] = new int[9]; for(int i = 0;i < 9;i++){
if(i == y)
continue;
int t = getTile(x, i);
if(t != 0)
c[t - 1] = t;
} for(int i = 0;i < 9;i++){
if(i == x)
continue;
int t = getTile(i, y);
if(t != 0)
c[t - 1] = t;
} int startx = (x / 3) * 3;
int starty = (y / 3) * 3;
for(int i = startx; i < startx + 3; i++){
for(int j = starty;j < starty + 3; j++){
if(i == x && j == y)
continue;
int t = getTile(i,j);
if(t!=0)
c[t-1] = t;
}
}
//compress
int nused = 0;
for(int t:c){
if(t!=0)
nused++;
}
int c1[] = new int[nused];
nused = 0;
for(int t:c){
if(t!=0)
c1[nused++] = t;
}
return c1;
}
}

界面效果如下:

android开发——数独游戏