android开发——数独游戏

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

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

然后自定义一个Dialog:

1.需要继承 Dialog 类,

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

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

流程:

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

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

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

下面介绍主要代码:

ShuduView:

  1 package com.soccer.shudu;
  2 
  3 import android.content.Context;
  4 import android.graphics.*;
  5 import android.graphics.Paint.FontMetrics;
  6 
  7 
  8 import android.view.MotionEvent;
  9 import android.view.View;
 10 import android.view.WindowManager;
 11 
 12 
 13 public class ShuduView extends View{
 14     
 15     public ShuduView(Context context) {
 16         super(context);
 17         // TODO Auto-generated constructor stub
 18     }
 19     
 20     private float width;
 21     private float height;
 22      
 23 
 24     private Game game = new Game();
 25     
 26     @Override
 27     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
 28         //计算当前单元格宽度和高度
 29         this.height = h / 9f;
 30         this.width = w / 9f;
 31         super.onSizeChanged(w, h, oldw, oldh);
 32     }
 33 
 34 
 35 
 36     //当android的系统需要绘制一个view对象时,就需要调用该对象的onDraw方法
 37     @Override
 38     protected void onDraw(Canvas canvas) {
 39         //生成用户绘制背景色的画笔
 40         Paint backgroundPaint = new Paint();
 41         //设置画笔颜色
 42         backgroundPaint.setColor(getResources().getColor(R.color.shudu_background));
 43         //绘制背景色
 44         canvas.drawRect(0, 0, getWidth(), getHeight(), backgroundPaint);
 45         
 46         Paint darkPaint = new Paint();
 47         darkPaint.setColor(getResources().getColor(R.color.shudu_dark));
 48         
 49         Paint hilitePaint = new Paint();
 50         hilitePaint.setColor(getResources().getColor(R.color.shudu_hilite));
 51         
 52         Paint lightPaint = new Paint();
 53         lightPaint.setColor(getResources().getColor(R.color.shudu_light));
 54         
 55         for(int i = 0;i < 9;i++){
 56             //绘制横向的线
 57             canvas.drawLine(0, i * height,getWidth(),  i * height, lightPaint);
 58             canvas.drawLine(0, i * height + 1,getWidth(),  i * height + 1, hilitePaint);
 59             //绘制纵向的线
 60             canvas.drawLine(i * width, 0, i * width, getHeight(), lightPaint);
 61             canvas.drawLine(i * width + 1, 0, i * width + 1, getHeight(), hilitePaint);
 62         }
 63         
 64         for(int i = 0;i < 3;i++){
 65             //绘制横向的线
 66             canvas.drawLine(0, i * 3 * height, getWidth(),  i * 3 * height, darkPaint);
 67             canvas.drawLine(0, i * 3 * height + 1, getWidth(),  i * 3 * height + 1, darkPaint);
 68             //绘制纵向的线
 69             canvas.drawLine(i * 3 * width, 0, i * 3 * width, getHeight(), darkPaint);
 70             canvas.drawLine(i * 3 * width + 1, 0, i * 3 * width + 1, getHeight(), darkPaint);
 71         }
 72         //绘制数字
 73         Paint numberPaint = new Paint();
 74         numberPaint.setColor(Color.BLACK);
 75         //numberPaint.setStyle(Paint.Style.STROKE);
 76         numberPaint.setTextSize( height * 0.75f); 
 77         numberPaint.setTextAlign(Paint.Align.CENTER);
 78         //将数字加到格子中
 79         FontMetrics fm = numberPaint.getFontMetrics();
 80         float x = width / 2;
 81         float y = height / 2 - (fm.ascent + fm.descent) / 2;
 82         //canvas.drawText("1", 3 * width + x, height + y , numberPaint);
 83         for(int i = 0;i < 9;i++){
 84             for(int j = 0;j < 9;j++){
 85                 canvas.drawText(game.getTileString(i, j), i * width+x, j * height + y, numberPaint);
 86             }
 87         }
 88         
 89         
 90         super.onDraw(canvas); 
 91     }
 92     
 93     int selectedX;
 94     int selectedY;
 95 
 96 
 97 
 98     @Override
 99     public boolean onTouchEvent(MotionEvent event) {
100         if(event.getAction() != MotionEvent.ACTION_DOWN){
101         return super.onTouchEvent(event);
102         }
103         
104         selectedX = (int)(event.getX() / width);
105         selectedY = (int)(event.getY() / height); 
106         
107         int used[] = game.getUsedTileByCoor(selectedX, selectedY);
108         StringBuffer sb = new StringBuffer();
109         for(int i = 0; i < used.length;i++){
110             System.out.println(used[i] );
111             //sb.append(used[i]);
112         }
113         
114         //生成一个LayoutInflater对象
115         //LayoutInflater layoutInflater = LayoutInflater.from(this.getContext());
116         //View layoutView = layoutInflater.inflate(R.layout.dialog, null);
117         //从生成好的textView中 取出相应的控件
118         //TextView textView =(TextView)layoutView.findViewById(R.id.usedTextId); 
119         
120         //textView.setText(sb.toString());
121         
122         //AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext());
123         //builder.setView(layoutView);
124         
125         //AlertDialog dialog = builder.create();
126         //dialog.show();
127         //dialog.getWindow().setLayout(300, 200);
128         KeyDialog keyDialog = new KeyDialog(getContext(), used,this);
129         //透明度
130         WindowManager.LayoutParams lp=keyDialog.getWindow().getAttributes();
131         lp.alpha=0.9f;
132         keyDialog.getWindow().setAttributes(lp);
133         
134         keyDialog.show();
135         return true;    
136     }
137     
138     public  void setSelectedTile(int tile){
139     
140         if(game.setTileIfValid(selectedX,selectedY,tile)){
141             invalidate();
142         }
143     }
144     
145 }

KeyDialog:

 1 package com.soccer.shudu;
 2 
 3 import android.app.Dialog;
 4 import android.content.Context;
 5 import android.os.Bundle;
 6 import android.view.View;
 7 import android.widget.Button;
 8 
 9 
10 //该类用于实现dialog自定义对话框功能
11 public class KeyDialog extends Dialog{
12     private final View keys [] = new View[9];
13     private final int used[];
14     
15     private ShuduView shuduView = null;
16     
17     public KeyDialog(Context context,int [] used,ShuduView shuduView){
18         super(context);
19         this.used = used;
20         this.shuduView = shuduView;
21     }
22     //当一个dialog第一次显示的时候,会调用其onCreate方法
23     @Override
24     protected void onCreate(Bundle savedInstanceState) {
25         super.onCreate(savedInstanceState);
26         setTitle("可选数字");
27         setContentView(R.layout.keypad);
28         findViews();
29         for(int i = 0;i < used.length;i++){
30             if(used[i] != 0){
31                 keys[used[i] - 1].setVisibility(View.INVISIBLE);
32             }
33         }
34         //为每个键设置监听器
35         setListeners();
36         
37         //为返回按钮设置监听器
38         Button back_Button = (Button)findViewById(R.id.back_1);
39         back_Button.setOnClickListener(new View.OnClickListener() {
40             @Override
41             public void onClick(View v) {
42                 dismiss();
43                 
44             }
45         });
46     }
47     
48     
49     
50     
51     private void findViews(){
52         keys[0] = findViewById(R.id.keypad_1);
53         keys[1] = findViewById(R.id.keypad_2);
54         keys[2] = findViewById(R.id.keypad_3);
55         keys[3] = findViewById(R.id.keypad_4);
56         keys[4] = findViewById(R.id.keypad_5);
57         keys[5] = findViewById(R.id.keypad_6);
58         keys[6] = findViewById(R.id.keypad_7);
59         keys[7] = findViewById(R.id.keypad_8);
60         keys[8] = findViewById(R.id.keypad_9);
61     }
62     
63     //通知ShuduView对象,刷新整个九宫格显示的数据
64     private void returnResult(int tile){
65         shuduView.setSelectedTile(tile);
66         dismiss();
67     }
68     
69     private void setListeners(){
70         for(int i = 0; i < keys.length; i++){
71             final int t = i + 1;
72             keys[i].setOnClickListener(new View.OnClickListener() {
73                 
74                 @Override
75                 public void onClick(View v) {
76                     returnResult(t);
77                     
78                 }
79             });
80         }
81     }
82     
83 }

keypad.xml:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:id="@+id/keypad"
 4     android:orientation="vertical"
 5     android:layout_width="wrap_content"
 6     android:layout_height="wrap_content"
 7     android:stretchColumns="*" >
 8 
 9     <TableRow>
10             <Button android:id="@+id/keypad_1"
11                 android:text="1">
12             </Button>
13             <Button android:id="@+id/keypad_2"
14                 android:text="2">
15             </Button>
16             <Button android:id="@+id/keypad_3"
17                 android:text="3">
18             </Button>
19     </TableRow>
20 
21     <TableRow>
22             <Button android:id="@+id/keypad_4"
23                 android:text="4">
24             </Button>
25             <Button android:id="@+id/keypad_5"
26                 android:text="5">
27             </Button>
28             <Button android:id="@+id/keypad_6"
29                 android:text="6">
30             </Button>
31     </TableRow>
32     
33     <TableRow>
34             <Button android:id="@+id/keypad_7"
35                 android:text="7">
36             </Button>
37             <Button android:id="@+id/keypad_8"
38                 android:text="8">
39             </Button>
40             <Button android:id="@+id/keypad_9"
41                 android:text="9">
42             </Button>
43     </TableRow>
44     
45     <TableRow>
46             <Button android:text="">
47             </Button>
48             <Button android:id="@+id/back_1"
49                 android:text="@string/back_1">
50             </Button>
51             <Button android:text="">
52             </Button>
53     </TableRow>
54 
55 </TableLayout>

Game.java:

  1 package com.soccer.shudu;
  2 
  3 public class Game {
  4     //数独初始化数据
  5     private final String str = "360000000004230800000004200"
  6             +"070460003820000014500013020"
  7             +"001900000007048300000000045";
  8     private int sudoku [] = new int[9*9];
  9     //用于存储每个单元格已经不可用的数据
 10     private int used[][][] = new int[9][9][];
 11     
 12     public Game(){
 13         sudoku = fromPuzzleString(str);
 14         calculateAllUsedTile();
 15     }
 16     //根据九宫格当中的坐标,返回该坐标对应的数字
 17     private int getTile(int x,int y){
 18         return sudoku[y*9 + x];
 19     }
 20     private void setTile(int x,int y,int value){
 21         sudoku[y * 9 + x] = value;
 22     }
 23     
 24     public String getTileString(int x, int y){
 25         int v = getTile(x,y);
 26         if(v == 0){          //0就不显示
 27             return "";
 28         }
 29         else
 30             return String.valueOf(v);
 31     }
 32     protected boolean setTileIfValid(int x,int y,int value){
 33         int tiles[] = getUsedTileByCoor(x,y);
 34         if(value != 0){
 35             for(int tile : tiles){
 36                 if(tile == value)
 37                     return false;
 38             }
 39         }
 40         setTile(x,y,value);
 41         calculateAllUsedTile();
 42         return true;
 43     }
 44     
 45     //根据一个字符串数据生成一个整形数组,作为数独游戏的初始化数据
 46     protected int[] fromPuzzleString(String src){
 47         int []sudo = new int[src.length()];
 48         for(int i = 0;i < sudo.length;i++)
 49         {
 50             sudo[i] = src.charAt(i) - '0';
 51         }
 52         return sudo;
 53     } 
 54     
 55     //计算所有单元格对应的不可用数据
 56     public void calculateAllUsedTile(){
 57         for(int x = 0;x < 9;x++){
 58             for(int y = 0;y < 9;y++){
 59                 used[x][y] = calculateUsedTiles(x, y);
 60             }
 61         }
 62     }
 63     
 64     //取出某一单元格当中已经不可用的数据
 65     public int[] getUsedTileByCoor(int x,int y){
 66         return used[x][y];
 67     }
 68     
 69     //计算某一单元格当中已经不可用的数据
 70     public int[] calculateUsedTiles(int x,int y){
 71         int c[] = new int[9];
 72         
 73         for(int i = 0;i < 9;i++){
 74             if(i == y)
 75                 continue;
 76             int t = getTile(x, i);
 77             if(t != 0)
 78                 c[t - 1] = t;
 79          }
 80         
 81         for(int i = 0;i < 9;i++){
 82             if(i == x)
 83                 continue;
 84             int t = getTile(i, y);
 85             if(t != 0)
 86                 c[t - 1] = t;
 87          }
 88         
 89         int startx = (x / 3) * 3;
 90         int starty = (y / 3) * 3;
 91         for(int i = startx; i < startx + 3; i++){
 92             for(int j = starty;j < starty + 3; j++){
 93                 if(i == x && j == y)
 94                     continue;
 95                 int t = getTile(i,j);
 96                 if(t!=0)
 97                     c[t-1] = t;
 98             }
 99         }
100         //compress
101         int nused = 0;
102         for(int t:c){
103             if(t!=0)
104                 nused++;
105         }
106         int c1[] = new int[nused];
107         nused = 0;
108         for(int t:c){
109             if(t!=0)
110                 c1[nused++] = t;
111         }
112         return c1;
113     }    
114 }

界面效果如下:

 

原文地址:https://www.cnblogs.com/soccer/p/3592687.html