android游戏开发项目实战——数独 .
2014-01-27 08:39
736 查看
二、代码实现
1、main.xml
[html]
view plaincopyprint?
<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:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> </RelativeLayout>
2、dialog.xml
[html]
view plaincopyprint?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/usedTextId"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello_world"
/>
</LinearLayout>
3、keypad1.xml
[html]
view plaincopyprint?
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/keypad"
android:orientation="vertical"
>
<TableRow >
<Button android:id="@+id/keypad_1"
android:text="1"
/>
<Button android:id="@+id/keypad_2"
android:text="2"
/>
<Button android:id="@+id/keypad_3"
android:text="3"
/>
</TableRow>
<TableRow >
<Button android:id="@+id/keypad_4"
android:text="4"
/>
<Button android:id="@+id/keypad_5"
android:text="5"
/>
<Button android:id="@+id/keypad_6"
android:text="6"
/>
</TableRow>
<TableRow >
<Button android:id="@+id/keypad_7"
android:text="7"
/>
<Button android:id="@+id/keypad_8"
android:text="8"
/>
<Button android:id="@+id/keypad_9"
android:text="9"
/>
</TableRow>
</TableLayout>
4、MainActivity
[java]
view plaincopyprint?
package com.njupt.shudu;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new ShuduView(this));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
5、ShuduView
[java]
view plaincopyprint?
package com.njupt.shudu;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.FontMetrics;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
public class ShuduView extends View{
//单元格的宽度和高度
private float width;
private float height;
private Game game = new Game();
private int selectedX;
private int selectedY;
public ShuduView(Context context) {
super(context);
}
/**
* w:当前view的宽度
* h:当前view的高度
*
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
//计算当前单元格的宽度和高度
this.width = w / 9f;
this.height = h / 9f;
super.onSizeChanged(w, h, oldw, oldh);
}
@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));
/**
* 绘制用于分割小九宫格的线(即将屏幕分成81个格子)
*/
for(int i = 0 ; i < 9 ; ++i){
/**
* canvas.drawLine(0, i*height, getWidth(),i*height, lightPaint)
* 第1、2个参数: 起点的坐标
* 第3、4个参数: 终点的坐标
* 第5个参数: 所使用的画笔
*/
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);
}
/**
* 绘制用于将屏幕分成9个大九宫格的线
*/
for(int i = 0 ; i < 9 ; ++i){
if(i % 3 == 0){
continue;
}
canvas.drawLine(0, i*height, getWidth(),i*height, darkPaint);//划横线
canvas.drawLine(0, i*height + 1, getWidth(), i*height + 1, hilitePaint);//也是划横线,为了对比突出那种"刻出来"的效果
canvas.drawLine(i*width, 0, i*width, getHeight(), darkPaint);
canvas.drawLine(i*width + 1, 0, i*width + 1, getHeight() , hilitePaint);
}
//绘制数字
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;
//生成数独的初始化数据
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);
}
@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.getUsedTilesByCoor(selectedX, selectedY);
StringBuffer sb = new StringBuffer();
for(int i = 0 ; i < used.length ; ++i){//用来验证一下看对不对
sb.append(used[i]);
}
// //生成一个LayoutInflater对象
// LayoutInflater layoutInflater = LayoutInflater.from(this.getContext());
// //使用LayoutInflater对象根据一个布局文件,生成一个View
// View layoutView = layoutInflater.inflate(R.layout.dialog, null);
// //从生成好的TextView中,取出相应的控件
// TextView textView = (TextView)layoutView.findViewById(R.id.usedTextId);
// //设置TextView的内容
// textView.setText(sb.toString());
// //生成一个对话框的Builder对象
// AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext());
// //设置对话框索要显示的内容
// builder.setView(layoutView);
// //生成对话框对象,并将其显示出来
// AlertDialog dialog = builder.create();
// dialog.show();
//
KeyDialog keyDialog = new KeyDialog(getContext(),used,this);
keyDialog.show();
return true;
}
public void setSelectedTile(int tile) {
if(game.setTileIfValid(selectedX,selectedY,tile)){
invalidate();
}
}
}
7、Game
[java]
view plaincopyprint?
package com.njupt.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);
calculateAllUsedTiles();
}
/**
* 根据九宫格当中的坐标,返回该坐标所应该填写的数字
* @param x
* @param y
* @return
*/
private int getTile(int x, int y){
return sudoku[y*9 + x];
}
/**
* 根据x轴坐标和y轴坐标得到这一单元格不可用的数据
* @param x
* @param y
* @return
*/
public String getTileString(int x, int y){
int v = getTile(x,y);
if(v == 0){
return "";
}else{
return String.valueOf(v);
}
}
/**
* 根据一个字符串数据,生成一个整型数组,所谓数独游戏的初始化数据
* @param src
* @return
*/
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 calculateAllUsedTiles(){
for(int x = 0 ; x < 9 ; ++x){
for(int y = 0 ; y < 9 ; ++y){
used[x][y] = calculateUsedTiles(x, y);
}
}
}
/**
* 取出某一单元格中已经不可用的数据
* @param x
* @param y
* @return
*/
public int[] getUsedTilesByCoor(int x, int y){
return used[x][y];
}
/**
* 计算某一单元格之中已经不可用的数据
* @param x
* @param y
*/
public int[] calculateUsedTiles(int x,int y) {
int c[] = new int[9];
/**
* 计算在y轴(列)方向上那些数字不可用...
*/
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;
}
}
}
/**
* 把c中的0给去掉
*/
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;
}
public boolean setTileIfValid(int x, int y, int value) {
int tiles[] = getUesdTiles(x,y);
if(value != 0){
for(int tile : tiles){
if(tile == value){
return false;
}
}
}
setTile(x,y,value);//把用户输入的数字添加到九宫格中
calculateAllUsedTiles();//更新该单元格可以使用的数字
return true;
}
protected int[] getUesdTiles(int x, int y) {
return used[x][y];
}
private void setTile(int x, int y, int value){
sudoku[y*9 + x] = value;
}
}
8、KeyDialog
[java]
view plaincopyprint?
package com.njupt.shudu;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
/**
* 该类用于实现Dialog,实现自定义的对话框功能...
* @author Administrator
*
*/
public class KeyDialog extends Dialog{
//用来存放代表对话框当中按钮的对象
private final View keys[] = new View[9];
private final int used[];
private ShuduView shuduView;
/**
*
* 构造函数的第二个参数中保存着当前单元格已经使用过的数字
* @param context
* @param used
*/
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("KeyDialog");
//用于为该Dialog设置布局文件
setContentView(R.layout.keypad1);
findViews();
//显示某一单元格中可用的数字
for(int i = 0 ; i < used.length ; ++i){
if(used[i] != 0){
keys[used[i] - 1].setVisibility(View.INVISIBLE);
}
}
//为对话框当中所有按钮设置监听器
setListeners();
}
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对象,刷新挣个九宫格显示的数据
* @param tile
*/
private void returnResult(int tile){
System.out.println("shuduView: " + shuduView);
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);
}
});
}
}
}
装载原文:/article/1338903.html
本项目源码下载:http://download.csdn.net/detail/caihongshijie6/6883785
1、main.xml
[html]
view plaincopyprint?
<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:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> </RelativeLayout>
<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:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> </RelativeLayout>
2、dialog.xml
[html]
view plaincopyprint?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/usedTextId"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello_world"
/>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/usedTextId" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello_world" /> </LinearLayout>
3、keypad1.xml
[html]
view plaincopyprint?
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/keypad"
android:orientation="vertical"
>
<TableRow >
<Button android:id="@+id/keypad_1"
android:text="1"
/>
<Button android:id="@+id/keypad_2"
android:text="2"
/>
<Button android:id="@+id/keypad_3"
android:text="3"
/>
</TableRow>
<TableRow >
<Button android:id="@+id/keypad_4"
android:text="4"
/>
<Button android:id="@+id/keypad_5"
android:text="5"
/>
<Button android:id="@+id/keypad_6"
android:text="6"
/>
</TableRow>
<TableRow >
<Button android:id="@+id/keypad_7"
android:text="7"
/>
<Button android:id="@+id/keypad_8"
android:text="8"
/>
<Button android:id="@+id/keypad_9"
android:text="9"
/>
</TableRow>
</TableLayout>
<?xml version="1.0" encoding="utf-8"?> <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/keypad" android:orientation="vertical" > <TableRow > <Button android:id="@+id/keypad_1" android:text="1" /> <Button android:id="@+id/keypad_2" android:text="2" /> <Button android:id="@+id/keypad_3" android:text="3" /> </TableRow> <TableRow > <Button android:id="@+id/keypad_4" android:text="4" /> <Button android:id="@+id/keypad_5" android:text="5" /> <Button android:id="@+id/keypad_6" android:text="6" /> </TableRow> <TableRow > <Button android:id="@+id/keypad_7" android:text="7" /> <Button android:id="@+id/keypad_8" android:text="8" /> <Button android:id="@+id/keypad_9" android:text="9" /> </TableRow> </TableLayout>
4、MainActivity
[java]
view plaincopyprint?
package com.njupt.shudu;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new ShuduView(this));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
package com.njupt.shudu; import android.os.Bundle; import android.app.Activity; import android.view.Menu; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new ShuduView(this)); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
5、ShuduView
[java]
view plaincopyprint?
package com.njupt.shudu;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.FontMetrics;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
public class ShuduView extends View{
//单元格的宽度和高度
private float width;
private float height;
private Game game = new Game();
private int selectedX;
private int selectedY;
public ShuduView(Context context) {
super(context);
}
/**
* w:当前view的宽度
* h:当前view的高度
*
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
//计算当前单元格的宽度和高度
this.width = w / 9f;
this.height = h / 9f;
super.onSizeChanged(w, h, oldw, oldh);
}
@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));
/**
* 绘制用于分割小九宫格的线(即将屏幕分成81个格子)
*/
for(int i = 0 ; i < 9 ; ++i){
/**
* canvas.drawLine(0, i*height, getWidth(),i*height, lightPaint)
* 第1、2个参数: 起点的坐标
* 第3、4个参数: 终点的坐标
* 第5个参数: 所使用的画笔
*/
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);
}
/**
* 绘制用于将屏幕分成9个大九宫格的线
*/
for(int i = 0 ; i < 9 ; ++i){
if(i % 3 == 0){
continue;
}
canvas.drawLine(0, i*height, getWidth(),i*height, darkPaint);//划横线
canvas.drawLine(0, i*height + 1, getWidth(), i*height + 1, hilitePaint);//也是划横线,为了对比突出那种"刻出来"的效果
canvas.drawLine(i*width, 0, i*width, getHeight(), darkPaint);
canvas.drawLine(i*width + 1, 0, i*width + 1, getHeight() , hilitePaint);
}
//绘制数字
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;
//生成数独的初始化数据
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);
}
@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.getUsedTilesByCoor(selectedX, selectedY);
StringBuffer sb = new StringBuffer();
for(int i = 0 ; i < used.length ; ++i){//用来验证一下看对不对
sb.append(used[i]);
}
// //生成一个LayoutInflater对象
// LayoutInflater layoutInflater = LayoutInflater.from(this.getContext());
// //使用LayoutInflater对象根据一个布局文件,生成一个View
// View layoutView = layoutInflater.inflate(R.layout.dialog, null);
// //从生成好的TextView中,取出相应的控件
// TextView textView = (TextView)layoutView.findViewById(R.id.usedTextId);
// //设置TextView的内容
// textView.setText(sb.toString());
// //生成一个对话框的Builder对象
// AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext());
// //设置对话框索要显示的内容
// builder.setView(layoutView);
// //生成对话框对象,并将其显示出来
// AlertDialog dialog = builder.create();
// dialog.show();
//
KeyDialog keyDialog = new KeyDialog(getContext(),used,this);
keyDialog.show();
return true;
}
public void setSelectedTile(int tile) {
if(game.setTileIfValid(selectedX,selectedY,tile)){
invalidate();
}
}
}
package com.njupt.shudu; import android.app.AlertDialog; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.FontMetrics; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.widget.TextView; public class ShuduView extends View{ //单元格的宽度和高度 private float width; private float height; private Game game = new Game(); private int selectedX; private int selectedY; public ShuduView(Context context) { super(context); } /** * w:当前view的宽度 * h:当前view的高度 * */ @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { //计算当前单元格的宽度和高度 this.width = w / 9f; this.height = h / 9f; super.onSizeChanged(w, h, oldw, oldh); } @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)); /** * 绘制用于分割小九宫格的线(即将屏幕分成81个格子) */ for(int i = 0 ; i < 9 ; ++i){ /** * canvas.drawLine(0, i*height, getWidth(),i*height, lightPaint) * 第1、2个参数: 起点的坐标 * 第3、4个参数: 终点的坐标 * 第5个参数: 所使用的画笔 */ 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); } /** * 绘制用于将屏幕分成9个大九宫格的线 */ for(int i = 0 ; i < 9 ; ++i){ if(i % 3 == 0){ continue; } canvas.drawLine(0, i*height, getWidth(),i*height, darkPaint);//划横线 canvas.drawLine(0, i*height + 1, getWidth(), i*height + 1, hilitePaint);//也是划横线,为了对比突出那种"刻出来"的效果 canvas.drawLine(i*width, 0, i*width, getHeight(), darkPaint); canvas.drawLine(i*width + 1, 0, i*width + 1, getHeight() , hilitePaint); } //绘制数字 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; //生成数独的初始化数据 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); } @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.getUsedTilesByCoor(selectedX, selectedY); StringBuffer sb = new StringBuffer(); for(int i = 0 ; i < used.length ; ++i){//用来验证一下看对不对 sb.append(used[i]); } // //生成一个LayoutInflater对象 // LayoutInflater layoutInflater = LayoutInflater.from(this.getContext()); // //使用LayoutInflater对象根据一个布局文件,生成一个View // View layoutView = layoutInflater.inflate(R.layout.dialog, null); // //从生成好的TextView中,取出相应的控件 // TextView textView = (TextView)layoutView.findViewById(R.id.usedTextId); // //设置TextView的内容 // textView.setText(sb.toString()); // //生成一个对话框的Builder对象 // AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext()); // //设置对话框索要显示的内容 // builder.setView(layoutView); // //生成对话框对象,并将其显示出来 // AlertDialog dialog = builder.create(); // dialog.show(); // KeyDialog keyDialog = new KeyDialog(getContext(),used,this); keyDialog.show(); return true; } public void setSelectedTile(int tile) { if(game.setTileIfValid(selectedX,selectedY,tile)){ invalidate(); } } }
7、Game
[java]
view plaincopyprint?
package com.njupt.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);
calculateAllUsedTiles();
}
/**
* 根据九宫格当中的坐标,返回该坐标所应该填写的数字
* @param x
* @param y
* @return
*/
private int getTile(int x, int y){
return sudoku[y*9 + x];
}
/**
* 根据x轴坐标和y轴坐标得到这一单元格不可用的数据
* @param x
* @param y
* @return
*/
public String getTileString(int x, int y){
int v = getTile(x,y);
if(v == 0){
return "";
}else{
return String.valueOf(v);
}
}
/**
* 根据一个字符串数据,生成一个整型数组,所谓数独游戏的初始化数据
* @param src
* @return
*/
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 calculateAllUsedTiles(){
for(int x = 0 ; x < 9 ; ++x){
for(int y = 0 ; y < 9 ; ++y){
used[x][y] = calculateUsedTiles(x, y);
}
}
}
/**
* 取出某一单元格中已经不可用的数据
* @param x
* @param y
* @return
*/
public int[] getUsedTilesByCoor(int x, int y){
return used[x][y];
}
/**
* 计算某一单元格之中已经不可用的数据
* @param x
* @param y
*/
public int[] calculateUsedTiles(int x,int y) {
int c[] = new int[9];
/**
* 计算在y轴(列)方向上那些数字不可用...
*/
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;
}
}
}
/**
* 把c中的0给去掉
*/
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;
}
public boolean setTileIfValid(int x, int y, int value) {
int tiles[] = getUesdTiles(x,y);
if(value != 0){
for(int tile : tiles){
if(tile == value){
return false;
}
}
}
setTile(x,y,value);//把用户输入的数字添加到九宫格中
calculateAllUsedTiles();//更新该单元格可以使用的数字
return true;
}
protected int[] getUesdTiles(int x, int y) {
return used[x][y];
}
private void setTile(int x, int y, int value){
sudoku[y*9 + x] = value;
}
}
package com.njupt.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); calculateAllUsedTiles(); } /** * 根据九宫格当中的坐标,返回该坐标所应该填写的数字 * @param x * @param y * @return */ private int getTile(int x, int y){ return sudoku[y*9 + x]; } /** * 根据x轴坐标和y轴坐标得到这一单元格不可用的数据 * @param x * @param y * @return */ public String getTileString(int x, int y){ int v = getTile(x,y); if(v == 0){ return ""; }else{ return String.valueOf(v); } } /** * 根据一个字符串数据,生成一个整型数组,所谓数独游戏的初始化数据 * @param src * @return */ 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 calculateAllUsedTiles(){ for(int x = 0 ; x < 9 ; ++x){ for(int y = 0 ; y < 9 ; ++y){ used[x][y] = calculateUsedTiles(x, y); } } } /** * 取出某一单元格中已经不可用的数据 * @param x * @param y * @return */ public int[] getUsedTilesByCoor(int x, int y){ return used[x][y]; } /** * 计算某一单元格之中已经不可用的数据 * @param x * @param y */ public int[] calculateUsedTiles(int x,int y) { int c[] = new int[9]; /** * 计算在y轴(列)方向上那些数字不可用... */ 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; } } } /** * 把c中的0给去掉 */ 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; } public boolean setTileIfValid(int x, int y, int value) { int tiles[] = getUesdTiles(x,y); if(value != 0){ for(int tile : tiles){ if(tile == value){ return false; } } } setTile(x,y,value);//把用户输入的数字添加到九宫格中 calculateAllUsedTiles();//更新该单元格可以使用的数字 return true; } protected int[] getUesdTiles(int x, int y) { return used[x][y]; } private void setTile(int x, int y, int value){ sudoku[y*9 + x] = value; } }
8、KeyDialog
[java]
view plaincopyprint?
package com.njupt.shudu;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
/**
* 该类用于实现Dialog,实现自定义的对话框功能...
* @author Administrator
*
*/
public class KeyDialog extends Dialog{
//用来存放代表对话框当中按钮的对象
private final View keys[] = new View[9];
private final int used[];
private ShuduView shuduView;
/**
*
* 构造函数的第二个参数中保存着当前单元格已经使用过的数字
* @param context
* @param used
*/
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("KeyDialog");
//用于为该Dialog设置布局文件
setContentView(R.layout.keypad1);
findViews();
//显示某一单元格中可用的数字
for(int i = 0 ; i < used.length ; ++i){
if(used[i] != 0){
keys[used[i] - 1].setVisibility(View.INVISIBLE);
}
}
//为对话框当中所有按钮设置监听器
setListeners();
}
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对象,刷新挣个九宫格显示的数据
* @param tile
*/
private void returnResult(int tile){
System.out.println("shuduView: " + shuduView);
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);
}
});
}
}
}
package com.njupt.shudu; import android.app.Dialog; import android.content.Context; import android.os.Bundle; import android.view.View; /** * 该类用于实现Dialog,实现自定义的对话框功能... * @author Administrator * */ public class KeyDialog extends Dialog{ //用来存放代表对话框当中按钮的对象 private final View keys[] = new View[9]; private final int used[]; private ShuduView shuduView; /** * * 构造函数的第二个参数中保存着当前单元格已经使用过的数字 * @param context * @param used */ 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("KeyDialog"); //用于为该Dialog设置布局文件 setContentView(R.layout.keypad1); findViews(); //显示某一单元格中可用的数字 for(int i = 0 ; i < used.length ; ++i){ if(used[i] != 0){ keys[used[i] - 1].setVisibility(View.INVISIBLE); } } //为对话框当中所有按钮设置监听器 setListeners(); } 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对象,刷新挣个九宫格显示的数据 * @param tile */ private void returnResult(int tile){ System.out.println("shuduView: " + shuduView); 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); } }); } } }
装载原文:/article/1338903.html
本项目源码下载:http://download.csdn.net/detail/caihongshijie6/6883785
相关文章推荐
- android游戏开发项目实战——数独
- Android快乐贪吃蛇游戏实战项目开发教程-02虚拟方向键(一)自定义控件概述
- Android快乐贪吃蛇游戏实战项目开发教程-05虚拟方向键(四)四个三角形按钮
- Android快乐贪吃蛇游戏实战项目开发教程-03虚拟方向键(二)绘制一个三角形
- Android快乐贪吃蛇游戏实战项目开发教程-06虚拟方向键(五)绘制方向键箭头
- Android快乐贪吃蛇游戏实战项目开发教程-04虚拟方向键(三)三角形按钮效果
- Android快乐贪吃蛇游戏实战项目开发教程-01项目概述与目录
- 【Android游戏开发二十七】讲解游戏开发与项目下的hdpi 、mdpi与ldpi资源文件夹以及游戏高清版本的设置
- Android网络游戏之神农诀项目开发--视频
- Android网络游戏之神农诀项目开发--视频
- Android应用开发项目实战视频教程
- Android开发入门——推箱子游戏开发实战(十一)
- Android项目实战视频教程_快递轨迹查询应用开发
- Android开发入门——推箱子游戏开发实战(六)
- Snake on a phone——Android开源项目实战,贪吃蛇游戏
- Android开发入门——推箱子游戏开发实战(八)
- Cocos2d-x手机游戏开发与项目实战详解
- Android 项目开发实战:答题系统
- 【iOS-cocos2d-X 游戏开发之七】整合Cocos2dX的Android项目到Xcode项目中,Android导入打包运行即可!
- Android项目开发实战—自定义左右菜单