android游戏开发项目实战——数独 .

二、代码实现


1、main.xml

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:paddingBottom="@dimen/activity_vertical_margin"  
  6.     android:paddingLeft="@dimen/activity_horizontal_margin"  
  7.     android:paddingRight="@dimen/activity_horizontal_margin"  
  8.     android:paddingTop="@dimen/activity_vertical_margin"  
  9.     tools:context=".MainActivity" >  
  10.   
  11.     <TextView  
  12.         android:layout_width="wrap_content"  
  13.         android:layout_height="wrap_content"  
  14.         android:text="@string/hello_world" />  
  15.   
  16. </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

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:orientation="vertical" >  
  6.       
  7.   
  8.     <TextView   
  9.         android:id="@+id/usedTextId"  
  10.         android:layout_width="fill_parent"  
  11.         android:layout_height="wrap_content"  
  12.         android:text="@string/hello_world"  
  13.         />  
  14. </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

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

  1. package com.njupt.shudu;  
  2.   
  3. import android.os.Bundle;  
  4. import android.app.Activity;  
  5. import android.view.Menu;  
  6.   
  7. public class MainActivity extends Activity {  
  8.   
  9.     @Override  
  10.     protected void onCreate(Bundle savedInstanceState) {  
  11.         super.onCreate(savedInstanceState);  
  12.         setContentView(new ShuduView(this));  
  13.     }  
  14.   
  15.     @Override  
  16.     public boolean onCreateOptionsMenu(Menu menu) {  
  17.         // Inflate the menu; this adds items to the action bar if it is present.   
  18.         getMenuInflater().inflate(R.menu.main, menu);  
  19.         return true;  
  20.     }  
  21.   
  22. }  
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

  1. package com.njupt.shudu;  
  2.   
  3. import android.app.AlertDialog;  
  4. import android.content.Context;  
  5. import android.graphics.Canvas;  
  6. import android.graphics.Color;  
  7. import android.graphics.Paint;  
  8. import android.graphics.Paint.FontMetrics;  
  9. import android.view.LayoutInflater;  
  10. import android.view.MotionEvent;  
  11. import android.view.View;  
  12. import android.widget.TextView;  
  13.   
  14. public class ShuduView extends View{  
  15.   
  16.     //单元格的宽度和高度   
  17.     private float width;  
  18.     private float height;  
  19.       
  20.     private Game game = new Game();  
  21.     private int selectedX;  
  22.     private int selectedY;  
  23.       
  24.     public ShuduView(Context context) {  
  25.         super(context);  
  26.           
  27.     }  
  28.       
  29.     /** 
  30.      * w:当前view的宽度 
  31.      * h:当前view的高度 
  32.      *  
  33.      */  
  34.     @Override  
  35.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
  36.         //计算当前单元格的宽度和高度   
  37.         this.width = w / 9f;  
  38.         this.height = h / 9f;  
  39.           
  40.         super.onSizeChanged(w, h, oldw, oldh);  
  41.     }  
  42.       
  43.     @Override  
  44.     protected void onDraw(Canvas canvas) {  
  45.         //生成用于绘制背景色的画笔   
  46.         Paint backgroundPaint = new Paint();  
  47.         //设置画笔的颜色   
  48.         backgroundPaint.setColor(getResources().getColor(R.color.shudu_background));  
  49.         //绘制背景色   
  50.         canvas.drawRect(00,getWidth(),getHeight(),backgroundPaint);  
  51.           
  52.         Paint darkPaint = new Paint();  
  53.         darkPaint.setColor(getResources().getColor(R.color.shudu_dark));  
  54.           
  55.         Paint hilitePaint = new Paint();  
  56.         hilitePaint.setColor(getResources().getColor(R.color.shudu_hilite));  
  57.           
  58.         Paint lightPaint = new Paint();  
  59.         lightPaint.setColor(getResources().getColor(R.color.shudu_light));  
  60.           
  61.         /** 
  62.          * 绘制用于分割小九宫格的线(即将屏幕分成81个格子) 
  63.          */  
  64.         for(int i = 0 ; i < 9 ; ++i){  
  65.             /** 
  66.              * canvas.drawLine(0, i*height, getWidth(),i*height, lightPaint) 
  67.              * 第1、2个参数: 起点的坐标 
  68.              * 第3、4个参数: 终点的坐标 
  69.              * 第5个参数: 所使用的画笔 
  70.              */  
  71.             canvas.drawLine(0, i*height, getWidth(),i*height, lightPaint);//划横线   
  72.             canvas.drawLine(0, i*height + 1, getWidth(), i*height + 1, hilitePaint);//也是划横线,为了对比突出那种"刻出来"的效果   
  73.             canvas.drawLine(i*width, 0, i*width, getHeight(), lightPaint);  
  74.             canvas.drawLine(i*width + 10, i*width + 1, getHeight() , hilitePaint);  
  75.               
  76.         }  
  77.           
  78.         /** 
  79.          * 绘制用于将屏幕分成9个大九宫格的线 
  80.          */  
  81.         for(int i = 0 ; i < 9 ; ++i){  
  82.             if(i % 3 == 0){  
  83.                 continue;  
  84.             }  
  85.               
  86.             canvas.drawLine(0, i*height, getWidth(),i*height, darkPaint);//划横线   
  87.             canvas.drawLine(0, i*height + 1, getWidth(), i*height + 1, hilitePaint);//也是划横线,为了对比突出那种"刻出来"的效果   
  88.             canvas.drawLine(i*width, 0, i*width, getHeight(), darkPaint);  
  89.             canvas.drawLine(i*width + 10, i*width + 1, getHeight() , hilitePaint);  
  90.               
  91.         }  
  92.           
  93.         //绘制数字   
  94.         Paint numberPaint = new Paint();  
  95.         numberPaint.setColor(Color.BLACK);  
  96.         numberPaint.setStyle(Paint.Style.STROKE);  
  97.         numberPaint.setTextSize(height*0.75f);  
  98.         numberPaint.setTextAlign(Paint.Align.CENTER);//设置对齐方式   
  99.           
  100.         FontMetrics fm = numberPaint.getFontMetrics();  
  101.         float x = width / 2;  
  102.         float y = height/2 - (fm.ascent + fm.descent)/2;  
  103.           
  104.         //生成数独的初始化数据   
  105.         for(int i = 0 ; i < 9 ; ++i){  
  106.             for(int j = 0 ; j < 9 ; ++j){  
  107.                 canvas.drawText(game.getTileString(i, j), i*width + x, j*height + y, numberPaint);  
  108.             }  
  109.         }  
  110.           
  111.         super.onDraw(canvas);  
  112.     }  
  113.       
  114.     @Override  
  115.     public boolean onTouchEvent(MotionEvent event) {  
  116.         if(event.getAction() != MotionEvent.ACTION_DOWN){  
  117.             return super.onTouchEvent(event);  
  118.         }  
  119.           
  120.         //判断用户点击的是哪一个单元格   
  121.         selectedX = (int)(event.getX() / width);  
  122.         selectedY = (int)(event.getY() / height);  
  123.           
  124.         int used[] = game.getUsedTilesByCoor(selectedX, selectedY);  
  125.         StringBuffer sb = new StringBuffer();  
  126.         for(int i = 0 ; i < used.length ; ++i){//用来验证一下看对不对   
  127.             sb.append(used[i]);  
  128.         }  
  129.           
  130. //      //生成一个LayoutInflater对象   
  131. //      LayoutInflater layoutInflater = LayoutInflater.from(this.getContext());   
  132. //      //使用LayoutInflater对象根据一个布局文件,生成一个View   
  133. //      View layoutView = layoutInflater.inflate(R.layout.dialog, null);   
  134. //      //从生成好的TextView中,取出相应的控件   
  135. //      TextView textView = (TextView)layoutView.findViewById(R.id.usedTextId);   
  136. //      //设置TextView的内容   
  137. //      textView.setText(sb.toString());   
  138. //      //生成一个对话框的Builder对象   
  139. //      AlertDialog.Builder builder = new AlertDialog.Builder(this.getContext());   
  140. //      //设置对话框索要显示的内容   
  141. //      builder.setView(layoutView);   
  142. //      //生成对话框对象,并将其显示出来   
  143. //      AlertDialog dialog = builder.create();   
  144. //      dialog.show();   
  145. //     
  146.         KeyDialog keyDialog = new KeyDialog(getContext(),used,this);  
  147.         keyDialog.show();  
  148.           
  149.         return true;  
  150.     }  
  151.   
  152.     public void setSelectedTile(int tile) {  
  153.         if(game.setTileIfValid(selectedX,selectedY,tile)){  
  154.             invalidate();  
  155.         }  
  156.     }  
  157. }  
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

  1. package com.njupt.shudu;  
  2.   
  3. public class Game {  
  4.   
  5.     //数独初始化数据的基础   
  6.     private final String str = "360000000004230800000004200"  
  7.             +"070460003820000014500013020"  
  8.             +"001900000007048300000000045";  
  9.       
  10.     private int sudoku[] = new int[9*9];  
  11.     //用于存储每个单元格已经不可用的数据   
  12.     private int used[][][] = new int[9][9][];  
  13.       
  14.     public Game() {  
  15.         sudoku = fromPuzzleString(str);  
  16.         calculateAllUsedTiles();  
  17.     }  
  18.       
  19.       
  20.   
  21.     /** 
  22.      * 根据九宫格当中的坐标,返回该坐标所应该填写的数字 
  23.      * @param x 
  24.      * @param y 
  25.      * @return 
  26.      */  
  27.     private int getTile(int x, int y){  
  28.         return sudoku[y*9 + x];  
  29.     }  
  30.       
  31.     /** 
  32.      * 根据x轴坐标和y轴坐标得到这一单元格不可用的数据 
  33.      * @param x 
  34.      * @param y 
  35.      * @return 
  36.      */  
  37.     public String getTileString(int x, int y){  
  38.         int v = getTile(x,y);  
  39.         if(v == 0){  
  40.             return "";  
  41.         }else{  
  42.             return String.valueOf(v);  
  43.         }  
  44.     }  
  45.       
  46.     /** 
  47.      * 根据一个字符串数据,生成一个整型数组,所谓数独游戏的初始化数据 
  48.      * @param src 
  49.      * @return 
  50.      */  
  51.     protected int[] fromPuzzleString(String src){  
  52.         int[] sudo = new int[src.length()];  
  53.           
  54.         for(int i = 0 ; i < sudo.length ; ++i){  
  55.             sudo[i] = src.charAt(i) - '0';   
  56.         }  
  57.           
  58.         return sudo;  
  59.     }  
  60.       
  61.     /** 
  62.      * 计算所有单元格对应的不可用的数据 
  63.      */  
  64.     public void calculateAllUsedTiles(){  
  65.         for(int x = 0 ; x < 9 ; ++x){  
  66.             for(int y = 0 ; y < 9 ; ++y){  
  67.                 used[x][y] = calculateUsedTiles(x, y);  
  68.             }  
  69.         }  
  70.     }  
  71.       
  72.       
  73.     /** 
  74.      * 取出某一单元格中已经不可用的数据 
  75.      * @param x 
  76.      * @param y 
  77.      * @return 
  78.      */  
  79.     public int[] getUsedTilesByCoor(int x, int y){  
  80.         return used[x][y];  
  81.     }  
  82.       
  83.       
  84.     /** 
  85.      * 计算某一单元格之中已经不可用的数据 
  86.      * @param x 
  87.      * @param y 
  88.      */  
  89.     public int[] calculateUsedTiles(int x,int y) {  
  90.         int c[] = new int[9];  
  91.           
  92.         /** 
  93.          * 计算在y轴(列)方向上那些数字不可用... 
  94.          */  
  95.         for(int i = 0 ; i < 9 ; ++i){  
  96.             if(i == y){//如果这是用户点击的格子   
  97.                 continue;  
  98.             }  
  99.               
  100.             int t = getTile(x,i);  
  101.             if(t != 0){  
  102.                 c[t - 1] = t;  
  103.             }  
  104.         }  
  105.           
  106.         for(int i = 0 ; i < 9 ; ++i){  
  107.             if(i == x){  
  108.                 continue;  
  109.             }  
  110.               
  111.             int t = getTile(i,y);  
  112.             if(t != 0){  
  113.                 c[t - 1] = t;  
  114.             }  
  115.         }  
  116.           
  117.         /** 
  118.          * 计算在小的九宫格中有那些数字已经用过了.. 
  119.          */  
  120.         int startX = (x/3)*3;  
  121.         int startY = (y/3)*3;  
  122.         for(int i = startX ; i < startX + 3 ; ++i){  
  123.             for(int j = startY ; j < startY + 3 ; ++j){  
  124.                 if(i == x && j == y){  
  125.                     continue;  
  126.                 }  
  127.                   
  128.                 int t = getTile(i, j);  
  129.                 if(t != 0 ){  
  130.                     c[t - 1] = t;  
  131.                 }  
  132.             }  
  133.         }  
  134.           
  135.           
  136.         /** 
  137.          * 把c中的0给去掉 
  138.          */  
  139.         int nused = 0;  
  140.         for(int t : c){  
  141.             if(t != 0){  
  142.                 nused++;  
  143.             }  
  144.         }  
  145.           
  146.         int c1[] = new int[nused];  
  147.         nused = 0;  
  148.         for(int t : c){  
  149.             if(t != 0){  
  150.                 c1[nused++] = t;  
  151.             }  
  152.         }  
  153.           
  154.         return c1;  
  155.           
  156.           
  157.     }  
  158.   
  159.   
  160.   
  161.     public boolean setTileIfValid(int x, int y, int value) {  
  162.         int tiles[] = getUesdTiles(x,y);  
  163.         if(value != 0){  
  164.             for(int tile : tiles){  
  165.                 if(tile == value){  
  166.                     return false;  
  167.                 }  
  168.             }  
  169.         }  
  170.           
  171.         setTile(x,y,value);//把用户输入的数字添加到九宫格中   
  172.         calculateAllUsedTiles();//更新该单元格可以使用的数字   
  173.         return true;  
  174.     }  
  175.   
  176.   
  177.   
  178.     protected int[] getUesdTiles(int x, int y) {  
  179.         return used[x][y];  
  180.     }  
  181.       
  182.     private void setTile(int x, int y, int value){  
  183.         sudoku[y*9 + x] = value;  
  184.     }  
  185. }  
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

  1. package com.njupt.shudu;  
  2.   
  3. import android.app.Dialog;  
  4. import android.content.Context;  
  5. import android.os.Bundle;  
  6. import android.view.View;  
  7.   
  8. /** 
  9.  * 该类用于实现Dialog,实现自定义的对话框功能... 
  10.  * @author Administrator 
  11.  * 
  12.  */  
  13. public class KeyDialog extends Dialog{  
  14.   
  15.     //用来存放代表对话框当中按钮的对象   
  16.     private final View keys[] = new View[9];  
  17.     private final int used[];  
  18.       
  19.     private ShuduView shuduView;  
  20.     /** 
  21.      *  
  22.      * 构造函数的第二个参数中保存着当前单元格已经使用过的数字 
  23.      * @param context 
  24.      * @param used 
  25.      */  
  26.     public KeyDialog(Context context , int[] used , ShuduView shuduView) {  
  27.         super(context);  
  28.         this.used = used;  
  29.         this.shuduView = shuduView;  
  30.     }  
  31.       
  32.     /** 
  33.      * 当一个Dialog第一次显示的时候,会调用其onCreate方法 
  34.      */  
  35.     @Override  
  36.     protected void onCreate(Bundle savedInstanceState) {  
  37.         super.onCreate(savedInstanceState);  
  38.           
  39.         //设置对话框的标题   
  40.         setTitle("KeyDialog");  
  41.         //用于为该Dialog设置布局文件   
  42.         setContentView(R.layout.keypad1);  
  43.         findViews();  
  44.           
  45.         //显示某一单元格中可用的数字   
  46.         for(int i = 0 ; i < used.length ; ++i){  
  47.             if(used[i] != 0){  
  48.                 keys[used[i] - 1].setVisibility(View.INVISIBLE);  
  49.             }  
  50.         }  
  51.           
  52.         //为对话框当中所有按钮设置监听器   
  53.         setListeners();  
  54.     }  
  55.   
  56.     private void findViews() {  
  57.         keys[0] = findViewById(R.id.keypad_1);  
  58.         keys[1] = findViewById(R.id.keypad_2);  
  59.         keys[2] = findViewById(R.id.keypad_3);  
  60.         keys[3] = findViewById(R.id.keypad_4);  
  61.         keys[4] = findViewById(R.id.keypad_5);  
  62.         keys[5] = findViewById(R.id.keypad_6);  
  63.         keys[6] = findViewById(R.id.keypad_7);  
  64.         keys[7] = findViewById(R.id.keypad_8);  
  65.         keys[8] = findViewById(R.id.keypad_9);  
  66.           
  67.     }  
  68.       
  69.     /** 
  70.      * 通知ShuduView对象,刷新挣个九宫格显示的数据 
  71.      * @param tile 
  72.      */  
  73.     private void returnResult(int tile){  
  74.         System.out.println("shuduView: " + shuduView);  
  75.         shuduView.setSelectedTile(tile);  
  76.         dismiss();//取消对话框的显示   
  77.     }  
  78.       
  79.     private void setListeners(){  
  80.         for(int i = 0 ; i < keys.length ; ++i){  
  81.             final int t = i + 1;  
  82.             keys[i].setOnClickListener(new View.OnClickListener() {  
  83.                   
  84.                 @Override  
  85.                 public void onClick(View v) {  
  86.                     returnResult(t);  
  87.                 }  
  88.             });  
  89.         }  
  90.     }  
  91. }  
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);
				}
			});
		}
	}
}


装载原文:http://blog.csdn.net/hjd_love_zzt/article/details/18773287

本项目源码下载:http://download.csdn.net/detail/caihongshijie6/6883785

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数独是一种逻辑推理的数学游戏,而Android数独游戏的代码实现也相对简单。以下是一个基本的Android数独游戏的代码示例: 首先,我们需要创建一个数独游戏的布局,可以使用Gridview或者Tablelayout布局来实现。然后,我们需要定义一个九宫格的二维数组,用来表示数独的当前状态。 在游戏的初始化中,我们可以通过随机算法生成一个数独游戏的初始状态。然后,将初始状态显示在九宫格中。 接下来,我们需要实现一个算法,用来判断当前数独的状态是否合法。可以通过检查每一行、每一列以及每一个小九宫格中是否有重复的数字来进行判断。 在游戏主界面中,我们可以添加一个文本框和一个确定按钮,用来输入和提交用户的答案。每次用户输入数字时,都需要进行合法性检查。当用户提交答案时,检查用户输入的答案是否与数独的正确答案一致,如果一致,游戏胜利;如果不一致,弹出提示框告诉用户答案错误。 为了提升用户体验,我们还可以添加一些功能,比如提示用户某个空格应该填写的数字、撤销上一步的操作等。 总之,Android数独游戏的代码实现主要涉及数独布局的创建、游戏的初始化、数独状态的合法性检查和用户答案的检查等功能。通过合理的算法和交互设计,我们可以实现一个简单而有趣的数独游戏

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值