数独游戏是一种源自18世纪末的瑞士的游戏,后在美国发展、并在日本得以发扬光大的数学智力拼图游戏。拼图是九宫格(即3格宽×3格高)的正方形状,每一格又细分为一个九宫格。在每一个小九宫格中,分别填上1至9的数字,让整个大九宫格每一列、每一行的数字都不重复。
数独的玩法逻辑简单,数字排列方式千变万化。不少教育者认为数独是锻炼脑筋的好方法,上外语阅读课的时候外教老师就很喜欢带我们玩这个,乐此不疲,老外的教学方式还是很受欢迎的。但是每次玩这个游戏的时候都要发一张数独游戏卡,嫌麻烦,就想着写一个demo放自己手机上,想想那个时候真是好奇心爆棚,碰上很火爆的小游戏都想整一个DIY的Demo,叨叨够了,哈哈,上源码。
一、界面布局
1.主界面
<?xml version="1.0" enCoding="utf-8"?><linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" androID:background="@color/background" androID:layout_height="fill_parent" androID:layout_wIDth="fill_parent" androID:padding="30dip" androID:orIEntation="horizontal"> <linearLayout androID:orIEntation="vertical" androID:layout_wIDth="fill_parent" androID:layout_height="wrap_content" androID:layout_gravity="center"> <TextVIEw androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:layout_gravity="center" androID:layout_marginBottom="25dip" androID:text="@string/main_Title" androID:textSize="24sp" /> <button androID:ID="@+ID/continue_button" androID:layout_wIDth="fill_parent" androID:layout_height="wrap_content" androID:text="@string/continue_label" /> <button androID:ID="@+ID/new_button" androID:layout_wIDth="fill_parent" androID:layout_height="wrap_content" androID:text="@string/new_game_label" /> <button androID:ID="@+ID/about_button" androID:layout_wIDth="fill_parent" androID:layout_height="wrap_content" androID:text="@string/about_label" /> <button androID:ID="@+ID/exit_button" androID:layout_wIDth="fill_parent" androID:layout_height="wrap_content" androID:text="@string/exit_label" /> </linearLayout></linearLayout>
2.数字键盘布局
<?xml version="1.0" enCoding="utf-8"?><tableLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" androID:ID="@+ID/keypad" androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:orIEntation="vertical" androID:background="@color/puzzle_background" androID:stretchColumns="*" > <tableRow > <button androID:ID="@+ID/keypad_1" androID:text="@string/keypad_1" /> <button androID:ID="@+ID/keypad_2" androID:text="@string/keypad_2" /> <button androID:ID="@+ID/keypad_3" androID:text="@string/keypad_3" /> </tableRow> <tableRow > <button androID:ID="@+ID/keypad_4" androID:text="@string/keypad_4" /> <button androID:ID="@+ID/keypad_5" androID:text="@string/keypad_5" /> <button androID:ID="@+ID/keypad_6" androID:text="@string/keypad_6" /> </tableRow> <tableRow > <button androID:ID="@+ID/keypad_7" androID:text="@string/keypad_7" /> <button androID:ID="@+ID/keypad_8" androID:text="@string/keypad_8" /> <button androID:ID="@+ID/keypad_9" androID:text="@string/keypad_9" /> </tableRow></tableLayout>
3.游戏提示布局
<?xml version="1.0" enCoding="utf-8"?><ScrollVIEw xmlns:androID="http://schemas.androID.com/apk/res/androID" androID:layout_wIDth="fill_parent" androID:layout_height="fill_parent" androID:padding="10dip"> <TextVIEw androID:ID="@+ID/about_content" androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:text="@string/about_text"/></ScrollVIEw>
二、游戏提示类
package com.DW.gamesuduku;import androID.app.Activity;import androID.os.Bundle;public class About extends Activity { @OverrIDe protected voID onCreate(Bundle savedInstanceState) { // Todo auto-generated method stub super.onCreate(savedInstanceState); setContentVIEw(R.layout.about); }}
三、逻辑实现1
package com.DW.gamesuduku;import androID.app.Activity;import androID.app.Dialog;import androID.os.Bundle;import androID.util.Log;import androID.vIEw.Gravity;import androID.Widget.Toast;public class Game extends Activity { private static final String TAG="Sudoku"; private static final String PREF_PUZZLE="puzzle"; protected static final int DIFFICulTY_CONTINUE=-1; public static final String KEY_DIFFICulTY="difficulty"; public static final int DIFFICulTY_EASY=0; public static final int DIFFICulTY_MEDIUM=1; public static final int DIFFICulTY_HARD=2; private int puzzle[]=new int[9*9]; private PuzzleVIEw puzzleVIEw; //三种游戏模式 private static final String easyPuzzle="360000000004230800000004200"+ "070460003820000014500013010"+ "001900000007048300000000045"; private static final String mediumpuzzle="650000070000506000014000005"+ "007009000002314700000700800"+ "500000630000201000030000097"; private static final String hardPuzzle="009000000080605020501078000"+ "000000700706040102004000000"+ "000720903090301080000000600"; private final int used[][][]=new int[9][9][]; @OverrIDe protected voID onCreate(Bundle savedInstanceState) { // Todo auto-generated method stub super.onCreate(savedInstanceState); Log.e(TAG,"onCreate"); int diff=getIntent().getIntExtra(KEY_DIFFICulTY,DIFFICulTY_EASY); puzzle=getPuzzle(diff); calculateUsedTiles(); puzzleVIEw=new PuzzleVIEw(this); setContentVIEw(puzzleVIEw); puzzleVIEw.requestFocus(); //if the activity is restarted,do a continue next time getIntent().putExtra(KEY_DIFFICulTY,DIFFICulTY_CONTINUE); } @OverrIDe protected voID onPause() { // Todo auto-generated method stub super.onPause(); Music.stop(this); //Save the current puzzle getPreferences(MODE_PRIVATE).edit().putString(PREF_PUZZLE,topuzzleString(puzzle)).commit(); } @OverrIDe protected voID onResume() { // Todo auto-generated method stub super.onResume(); Music.play(this,R.raw.game); } protected int[] getUsedTiles(int x,int y){ return used[x][y]; } private voID calculateUsedTiles() { // Todo auto-generated method stub for (int x = 0; x < 9; x++) { for (int y = 0; y < 9; y++) { used[x][y]=calculateUsedTiles(x,y); } } } private int[] calculateUsedTiles(int x,int y) { // Todo auto-generated method stub int c[]=new int[9]; //horizontal for(int i=0;i<9;i++){ if(i==y) continue; int t=getTitle(x,i); if(t!=0) c[t-1]=t; } //vertical for(int i=0;i<9;i++){ if(i==x) continue; int t=getTitle(i,y); if(t!=0) c[t-1]=t; } //same cell block 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=getTitle(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; } //give a difficulty level private int[] getPuzzle(int diff) { // Todo auto-generated method stub String puz = null; switch (diff) { case DIFFICulTY_CONTINUE: puz=getPreferences(MODE_PRIVATE).getString(PREF_PUZZLE,easyPuzzle); break; case DIFFICulTY_HARD: puz=hardPuzzle; break; case DIFFICulTY_MEDIUM: puz=mediumpuzzle; break; case DIFFICulTY_EASY: puz=easyPuzzle; break; } return frompuzzleString(puz); } //convert an array into a puzzle string static private String topuzzleString(int[] puz){ StringBuilder buf=new StringBuilder(); for (int element : puz) { buf.append(element); } return buf.toString(); } //convert a puzzle string to an array static protected int[] frompuzzleString(String string) { // Todo auto-generated method stub int[] puz=new int[string.length()]; for (int i = 0; i < puz.length; i++) { puz[i]=string.charat(i)-'0'; } return puz; } public String getTitleString(int x,int y) { // Todo auto-generated method stub int v=getTitle(x,y); if(v==0) return ""; else return String.valueOf(v); } private int getTitle(int x,int y) { // Todo auto-generated method stub return puzzle[y*9+x]; } private voID setTitle(int x,int y,int value){ puzzle[y*9+x]=value; } //change the tile only if it's a valID move protected boolean setTileIfValID(int x,int value) { // Todo auto-generated method stub int tiles[]=getUsedTiles(x,y); if(value!=0){ for (int tile : tiles) { if(tile==value) return false; } } setTitle(x,y,value); calculateUsedTiles(); return true; } //open the keypad if there are any valID moves protected voID showKeypadOrError(int x,int y) { // Todo auto-generated method stub int tiles[]=getUsedTiles(x,y); if(tiles.length==9){ Toast toast=Toast.makeText(this,R.string.no_moves_label,Toast.LENGTH_SHORT); toast.setGravity(Gravity.BottOM,0); toast.show(); }else{ Log.d(TAG,"showKeypad:used="+topuzzleString(tiles)); Dialog v=new Keypad(this,tiles,puzzleVIEw); v.show(); } }}
四、数字键盘
package com.DW.gamesuduku;import androID.app.Dialog;import androID.content.Context;import androID.os.Bundle;import androID.vIEw.KeyEvent;import androID.vIEw.VIEw;public class Keypad extends Dialog { protected static final String TAG="Sudoku"; private final VIEw keys[]=new VIEw[9]; private VIEw keypad; private final int useds[]; private PuzzleVIEw puzzleVIEw; public Keypad(Context context,int useds[],PuzzleVIEw puzzleVIEw){ super(context); this.useds=useds; this.puzzleVIEw=puzzleVIEw; } @OverrIDe protected voID onCreate(Bundle savedInstanceState) { // Todo auto-generated method stub super.onCreate(savedInstanceState); setContentVIEw(R.layout.keypad); findVIEws(); for (int element : useds) { if(element!=0){ keys[element-1].setVisibility(VIEw.INVISIBLE); } setListeners(); } } @OverrIDe public boolean onKeyDown(int keyCode,KeyEvent event) { // Todo auto-generated method stub int tile=0; switch (keyCode) { case KeyEvent.KEYCODE_0: case KeyEvent.KEYCODE_SPACE:tile=0;break; case KeyEvent.KEYCODE_1:tile=1;break; case KeyEvent.KEYCODE_2:tile=2;break; case KeyEvent.KEYCODE_3:tile=3;break; case KeyEvent.KEYCODE_4:tile=4;break; case KeyEvent.KEYCODE_5:tile=5;break; case KeyEvent.KEYCODE_6:tile=6;break; case KeyEvent.KEYCODE_7:tile=7;break; case KeyEvent.KEYCODE_8:tile=8;break; case KeyEvent.KEYCODE_9:tile=9;break; default: return super.onKeyDown(keyCode,event); } if(isValID(tile)){ returnResult(tile); } return true; } private boolean isValID(int tile) { // Todo auto-generated method stub for (int t : useds) { if(tile==t) return false; } return true; } private voID findVIEws() { // Todo auto-generated method stub keypad=findVIEwByID(R.ID.keypad); 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); } 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 arg0) { // Todo auto-generated method stub returnResult(t); } }); } keypad.setonClickListener(new VIEw.OnClickListener() { public voID onClick(VIEw arg0) { // Todo auto-generated method stub returnResult(0); } }); } private voID returnResult(int tile) { // Todo auto-generated method stub puzzleVIEw.setSelectedTile(tile); dismiss(); }}
五、背景音乐
package com.DW.gamesuduku;import androID.content.Context;import androID.media.MediaPlayer;public class Music { private static MediaPlayer mp=null; //stop old song and start a new song public static voID play(Context context,int resource){ stop(context); if(Settings.getMusic(context)){ mp=MediaPlayer.create(context,resource); mp.setLooPing(true); mp.start(); } } //stop the music public static voID stop(Context context) { // Todo auto-generated method stub if(mp!=null){ mp.stop(); mp.release(); mp=null; } }}
六、逻辑实现2
package com.DW.gamesuduku;import androID.annotation.Suppresslint;import androID.content.Context;import androID.graphics.Canvas;import androID.graphics.Paint;import androID.graphics.Paint.FontMetrics;import androID.graphics.Paint.Style;import androID.graphics.Rect;import androID.os.Bundle;import androID.os.Parcelable;import androID.util.Log;import androID.vIEw.KeyEvent;import androID.vIEw.MotionEvent;import androID.vIEw.VIEw;import androID.vIEw.animation.AnimationUtils;@Suppresslint("DrawAllocation")public class PuzzleVIEw extends VIEw { private static final String TAG = "Sudoku"; private final Game game; private float wIDth; private float height; private int selX; private int selY; private final Rect selRect = new Rect(); private static final String SELX="selX"; private static final String SELY="selY"; private static final String VIEW_STATE="vIEwState"; private static final int ID=42;//any positive int num public PuzzleVIEw(Context context) { super(context); this.game = (Game) context; setFocusable(true); setFocusableIntouchMode(true); setID(ID); } @OverrIDe protected voID onSizeChanged(int w,int h,int olDW,int oldh) { // Todo auto-generated method stub wIDth = w / 9f; height = h / 9f; getRect(selX,selY,selRect); Log.d(TAG,"onSizeChanged:wIDth" + wIDth + ",height" + height); super.onSizeChanged(w,h,olDW,oldh); } //实例状态保存在bundle中,保存当前游戏状态 @OverrIDe protected Parcelable onSaveInstanceState() { // Todo auto-generated method stub Parcelable p=super.onSaveInstanceState(); Log.d(TAG,"onSavedInstanceState"); Bundle bundle=new Bundle(); bundle.putInt(SELX,selX); bundle.putInt(SELY,selY); bundle.putParcelable(VIEW_STATE,p); return bundle; } //恢复已经保存的信息 @OverrIDe protected voID onRestoreInstanceState(Parcelable state) { // Todo auto-generated method stub Log.d(TAG,"onRestoreInstanceState"); Bundle bundle=(Bundle) state; select(bundle.getInt(SELX),bundle.getInt(SELY)); super.onRestoreInstanceState(bundle.getParcelable(VIEW_STATE)); return; } @OverrIDe protected voID onDraw(Canvas canvas) { // Todo auto-generated method stub // draw background Paint background = new Paint(); background.setcolor(getResources().getcolor(R.color.puzzle_background)); canvas.drawRect(0,getWIDth(),getHeight(),background); // draw board Paint dark = new Paint(); dark.setcolor(getResources().getcolor(R.color.puzzle_dark)); Paint hilite = new Paint(); hilite.setcolor(getResources().getcolor(R.color.puzzle_hilite)); Paint light = new Paint(); light.setcolor(getResources().getcolor(R.color.puzzle_light)); // draw minor grID lines for (int i = 0; i < 9; i++) { canvas.drawline(0,i * height,light); canvas.drawline(0,i * height + 1,hilite); canvas.drawline(i * wIDth,i * wIDth,dark); canvas.drawline(i * wIDth + 1,i * wIDth + 1,hilite); } // draw major grID lines for (int i = 0; i < 9; i++) { if (i % 3 != 0) continue; canvas.drawline(0,dark); canvas.drawline(0,hilite); } // draw numbers Paint foreground = new Paint(Paint.ANTI_AliAS_FLAG); foreground.setcolor(getResources().getcolor(R.color.puzzle_foregroud)); foreground.setStyle(Style.FILL); foreground.setTextSize(height * 0.75f); foreground.setTextScaleX(wIDth / height); foreground.setTextAlign(Paint.Align.CENTER); // draw num in the center of the tile FontMetrics fm = foreground.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(this.game.getTitleString(i,j),i * wIDth + x,j * height + y,foreground); } } // draw the selection Log.e(TAG,"selRect=" + selRect); Paint selected = new Paint(); selected.setcolor(getResources().getcolor(R.color.puzzle_selected)); canvas.drawRect(selRect,selected); //draw the hints pick a hint color based on moves left //根据每个单元格可填的数目给出不同颜色的提示 if(Settings.getHints(getContext())){ Paint hint=new Paint(); int c[]={getResources().getcolor(R.color.puzzle_hint_0),getResources().getcolor(R.color.puzzle_hint_1),getResources().getcolor(R.color.puzzle_hint_2),}; Rect r=new Rect(); for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { int movesleft=9-game.getUsedTiles(i,j).length; if(movesleft<c.length){ getRect(i,j,r); hint.setcolor(c[movesleft]); canvas.drawRect(r,hint); } } } } } @OverrIDe public boolean onKeyDown(int keyCode,KeyEvent event) { // Todo auto-generated method stub Log.d(TAG,"onKeyDown:keycode=" + keyCode + ",event=" + event); switch (keyCode) { case KeyEvent.KEYCODE_DPAD_UP: select(selX,selY - 1); break; case KeyEvent.KEYCODE_DPAD_DOWN: select(selX,selY + 1); break; case KeyEvent.KEYCODE_DPAD_left: select(selX - 1,selY); break; case KeyEvent.KEYCODE_DPAD_RIGHT: select(selX + 1,selY); break; case KeyEvent.KEYCODE_0: case KeyEvent.KEYCODE_SPACE: setSelectedTile(0); break; case KeyEvent.KEYCODE_1: setSelectedTile(1); break; case KeyEvent.KEYCODE_2: setSelectedTile(2); break; case KeyEvent.KEYCODE_3: setSelectedTile(3); break; case KeyEvent.KEYCODE_4: setSelectedTile(4); break; case KeyEvent.KEYCODE_5: setSelectedTile(5); break; case KeyEvent.KEYCODE_6: setSelectedTile(6); break; case KeyEvent.KEYCODE_7: setSelectedTile(7); break; case KeyEvent.KEYCODE_8: setSelectedTile(8); break; case KeyEvent.KEYCODE_9: setSelectedTile(9); break; case KeyEvent.KEYCODE_ENTER: case KeyEvent.KEYCODE_DPAD_CENTER: game.showKeypadOrError(selX,selY); default: return super.onKeyDown(keyCode,event); } return true; } //显示软键盘 @OverrIDe public boolean ontouchEvent(MotionEvent event) { // Todo auto-generated method stub if(event.getAction()!=MotionEvent.ACTION_DOWN) return super.ontouchEvent(event); select((int)(event.getX()/wIDth),(int)(event.getY()/height)); game.showKeypadOrError(selX,selY); Log.d(TAG,"ontouchEvent:x"+selX+",y"+selY); return true; } public voID setSelectedTile(int tile) { // Todo auto-generated method stub //num is not valID for this tile Log.d(TAG,"selectedTile:invalID:"+tile);// startAnimation(AnimationUtils.loadAnimation(game,R.aims.shake)); if (game.setTileIfValID(selX,tile)) { invalIDate(); } else { // num is not invalID for this tile Log.d(TAG,"setSelectedTile:invalID " + tile); } } // 首先计算选定区域的x,y坐标,然后再次调用getRect方法计算新的选择矩形 private voID select(int x,int y) { // Todo auto-generated method stub invalIDate(selRect);// 第一次调用通知原选择的区域需要重绘 selX = Math.min(Math.max(x,0),8); selY = Math.min(Math.max(y,8); getRect(selX,selRect); invalIDate(selRect);// 第二次调用通知新选择的区域也需要重绘 } private voID getRect(int x,Rect rect) { // Todo auto-generated method stub rect.set((int) (x * wIDth),(int) (y * height),(int) (x * wIDth + wIDth),(int) (y * height + height)); }}
七、游戏设置
package com.DW.gamesuduku;import androID.app.Activity;import androID.content.Context;import androID.os.Bundle;import androID.preference.PreferenceFragment;import androID.preference.PreferenceManager;public class Settings extends Activity { private static final String OPT_MUSIC="music"; private static final boolean OPT_MUSIC_DEF=true; private static final String OPT_HINTS="hints"; private static final boolean OPT_HINTS_DEF=true; @OverrIDe public voID onCreate(Bundle savedInstanceState) { // Todo auto-generated method stub super.onCreate(savedInstanceState); getFragmentManager().beginTransaction().replace(androID.R.ID.content,new PrefsFragement()).commit(); } public static class PrefsFragement extends PreferenceFragment{ public voID onCreate(Bundle savedInstanceState) { // Todo auto-generated method stub super.onCreate(savedInstanceState); addPreferencesFromresource(R.xml.settings); } } //get the current music option public static boolean getMusic(Context context){ return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(OPT_MUSIC,OPT_MUSIC_DEF); } //get the current music option public static boolean getHints(Context context){ return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(OPT_HINTS,OPT_HINTS_DEF); }}
八、游戏入口
package com.DW.gamesuduku;import androID.app.Activity;import androID.app.AlertDialog;import androID.content.DialogInterface;import androID.content.Intent;import androID.os.Bundle;import androID.util.Log;import androID.vIEw.Menu;import androID.vIEw.MenuInflater;import androID.vIEw.MenuItem;import androID.vIEw.VIEw;import androID.vIEw.VIEw.OnClickListener;public class Sudoku extends Activity implements OnClickListener { private static final String TAG = "Sudoku"; @OverrIDe protected voID onCreate(Bundle savedInstanceState) { // Todo auto-generated method stub super.onCreate(savedInstanceState); setContentVIEw(R.layout.activity_main); VIEw continuebutton = this.findVIEwByID(R.ID.continue_button); continuebutton.setonClickListener(this); VIEw newbutton = this.findVIEwByID(R.ID.new_button); newbutton.setonClickListener(this); VIEw aboutbutton = this.findVIEwByID(R.ID.about_button); aboutbutton.setonClickListener(this); VIEw exitbutton = this.findVIEwByID(R.ID.exit_button); exitbutton.setonClickListener(this); } @OverrIDe public voID onClick(VIEw v) { // Todo auto-generated method stub switch (v.getID()) { case R.ID.continue_button: startGame(Game.DIFFICulTY_CONTINUE); case R.ID.about_button: Intent i = new Intent(this,About.class); startActivity(i); break; case R.ID.new_button: openNewGameDialog(); break; case R.ID.exit_button: finish(); break; } } @OverrIDe protected voID onResume() { // Todo auto-generated method stub super.onResume(); Music.play(this,R.raw.welcome); } @OverrIDe protected voID onPause() { // Todo auto-generated method stub super.onPause(); Music.stop(this); } @OverrIDe public boolean onCreateOptionsMenu(Menu menu) { // Todo auto-generated method stub super.onCreateOptionsMenu(menu); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu,menu); return true; } @OverrIDe public boolean onoptionsItemSelected(MenuItem item) { // Todo auto-generated method stub switch (item.getItemID()) { case R.ID.settings: startActivity(new Intent(this,Settings.class)); return true; } return false; } private voID openNewGameDialog() { // Todo auto-generated method stub new AlertDialog.Builder(this).setTitle(R.string.new_game_Title) .setItems(R.array.difficulty,new DialogInterface.OnClickListener() { @OverrIDe public voID onClick( DialogInterface dialoginterface,int i) { // Todo auto-generated method stub startGame(i); } }).show(); } protected voID startGame(int i) { // Todo auto-generated method stub Log.i(TAG,"clicked on"+i); Intent intent=new Intent(Sudoku.this,Game.class); intent.putExtra(Game.KEY_DIFFICulTY,i); startActivity(intent); }}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。
以上是内存溢出为你收集整理的Android应用实践之数独游戏开发全部内容,希望文章能够帮你解决Android应用实践之数独游戏开发所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)