数独游戏设计与实现之第三篇——项目开发的过程
分成四个类:CrosswordsActivity,DialogView,Game,MainView
CrosswordsActivity(主类):
package com.Crosswords.Activity; import android.app.Activity; import android.os.Bundle; public class CrosswordsActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new MainView(this)); } }
DialogView(对话框的一个类):
package com.Crosswords.Activity; import android.app.Dialog; import android.content.Context; import android.os.Bundle; import android.view.View; public class DialogView extends Dialog{ MainView mainview; // View []views=new View[9]; View[] views=new View[12]; int []used; public DialogView(Context context,int []used,MainView mainview) { super(context); this.used=used; this.mainview=mainview; } @Override public void onCreate(Bundle buildle){ super.onCreate(buildle); setTitle("请输入数字"); setContentView(R.layout.dialog); this.getView(); for(int i=0;i<used.length;i++){ if(used[i]!=0){ views[used[i]-1].setVisibility(View.INVISIBLE); } } views[9].setVisibility(View.INVISIBLE); views[11].setVisibility(View.INVISIBLE); setListener(); } public void getView(){ views[0]=findViewById(R.id.keypad_1); views[1]=findViewById(R.id.keypad_2); views[2]=findViewById(R.id.keypad_3); views[3]=findViewById(R.id.keypad_4); views[4]=findViewById(R.id.keypad_5); views[5]=findViewById(R.id.keypad_6); views[6]=findViewById(R.id.keypad_7); views[7]=findViewById(R.id.keypad_8); views[8]=findViewById(R.id.keypad_9); views[9]=findViewById(R.id.keypad_10); views[10]=findViewById(R.id.keypad_11); views[11]=findViewById(R.id.keypad_12); } public void ReturnResult(int title){ mainview.SetSelectTitle(title); dismiss(); } public void setListener(){ for(int i=0;i<views.length;i++){ //次数的t为真实的数字 final int t=i+1; views[i].setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ReturnResult(t); } }); } } }
Game(数独的算法类):
package com.Crosswords.Activity; public class Game { String str= "500200008"+ "700008400"+ "000390060"+ "001630009"+ "000000654"+ "968400000"+ "005006071"+ "609005803"+ "080903046"; //全部的数字 int []crosswords=new int[9*9]; //各个坐标已经使用的数字 int [][][]usedwords=new int[9][9][]; //用来标记能够修改 int [][]flag =new int[9][9]; public Game() { // TODO Auto-generated constructor stub crosswords=getCrossword(str); flag=getflag(); //GetAllUsed(); } //得到所有已经使用数组 public void GetAllUsed(){ for(int i=0;i<9;i++){ for(int j=0;j<9;j++){ usedwords[i][j]=getUsedWords(i, j); } } } //用来计算单元格中已经使用的格子 public int[] getUsedWords(int x,int y){ int [] c=new int[9]; //计算一行 int temp; for(int i=0;i<9;i++){ temp=gettitle(i, y); if(x==i){ continue; }else{ if(temp!=0){ c[temp-1]=temp; } } } //计算一列 for(int i=0;i<9;i++){ temp=gettitle(x, i); if(y==i){ continue; }else{ if(temp!=0){ c[temp-1]=temp; } } } //计算单元格 //这个表达式是为了求出点击事件的具体大方块位置 int stax=(x/3)*3; int stay=(y/3)*3; for(int i=stax;i<stax+3;i++){ for(int j=stay;j<stay+3;j++){ temp=gettitle(i, j); if(x==i&&y==j){ continue; }else{ if(temp!=0){ c[temp-1]=temp; } } } } //进行冗余处理 int sum=0; for(int temp1:c){//此处必须重新声明temp1 if(temp1!=0) sum++; } int []usedword=new int [sum]; sum=0; for(int temp2:c){ if(temp2!=0){ usedword[sum]=temp2; sum++; } } return usedword; } //得到数字板的数独 public int[] getCrossword(String str){ int []sodu=new int[str.length()]; for(int i=0;i<str.length();i++){ //减去0的编码用来算出具体的值 sodu[i]=str.charAt(i)-'0'; } return sodu; } public String gettitleString(int x,int y){ String a=null; //此处不能直接调用方法 会报错 int b=gettitle(x, y); if(b==0){ a=""; } else{ a=String.valueOf(b); } return a; } //得到对应坐标的数字 public int gettitle(int x,int y){ int temp=crosswords[y*9+x]; return temp; } //分析哪些坐标不能改变 public int[][] getflag(){ int temp; int flag[][]=new int[9][9]; for(int i=0;i<str.length();i++){ //减去0的编码用来算出具体的值 temp=str.charAt(i)-'0'; if(temp==0){ flag[i%9][i/9]=1; //System.out.println("此处可以填写:"+i%9+" "+i/9); } } return flag; } //得到标记 public int flag(int x,int y){ return flag[x][y]; } //用来在改变数字的时候进行更新 public void settitle(int x,int y,int title){ crosswords[y*9+x]=title; } // public boolean SetTitleValid(int staX,int staY,int title){ int temp[]=getUsedWords(staX, staY); //用来判断是不是清空按钮 if(title<=9){ for(int t:temp){ //为什么要判断 if(t==title){ System.out.println("==================="+t); return false; } } settitle(staX,staY,title); }else{ settitle(staX,staY,0); } return true; } }
MainView(计算单元格的一个类):
package com.Crosswords.Activity; import android.app.AlertDialog; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.Paint.FontMetrics; import android.text.style.LineBackgroundSpan; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewDebug.FlagToString; import android.widget.TextView; public class MainView extends View{ float width; float height; int selectedX; int selectedY; Game game=new Game(); //画笔不能重用 public MainView(Context context) { super(context); // TODO Auto-generated constructor stub } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { // TODO Auto-generated method stub super.onSizeChanged(w, h, oldw, oldh); //计算单元格 width=w/9; height=h/9; } //画笔事件 @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); Paint backgroundpaint=new Paint(); backgroundpaint.setColor(Color.parseColor("#C2E7C2")); canvas.drawRect(0,0,getWidth(),getHeight(), backgroundpaint); //#BFCDDB小格子颜色 Paint linepaint1=new Paint(); linepaint1.setColor(Color.parseColor("#BFCDDB")); for (int i = 0; i < 10; i++) { canvas.drawLine(0,i*getHeight()/9, getWidth(), i*getHeight()/9, linepaint1); canvas.drawLine(i*getWidth()/9, 0, i*getWidth()/9, getHeight(), linepaint1); } Paint linepaint2=new Paint(); linepaint2.setColor(Color.parseColor("#3399FF")); for(int i=0;i<4;i++){ canvas.drawLine(0, i*getHeight()/3, getWidth(), i*getHeight()/3, linepaint2); canvas.drawLine(i*getWidth()/3, 0, i*getWidth()/3, getHeight(), linepaint2); } Paint numberpaint=new Paint(); 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; String text; for (int i = 0; i < 9; i++) { for(int j=0;j<9;j++){ text=game.gettitleString(i, j); if(game.flag(i,j)==1){ numberpaint.setColor(Color.BLACK); canvas.drawText(text, width*i+x, height*j+y, numberpaint); }else{ numberpaint.setColor(Color.parseColor("#6B6743")); canvas.drawText(text, width*i+x, height*j+y, numberpaint); } } } } //监听点击面板事件 @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 [] usedwords=game.getUsedWords(selectedX, selectedY); StringBuffer usedstr=new StringBuffer(); for(int x:usedwords){ usedstr.append(x+" "); } //使用自定义的对话框 /* LayoutInflater inflater=LayoutInflater.from(this.getContext()); View view=inflater.inflate(R.layout.dialog, null); TextView text=(TextView)view.findViewById(R.id.used); text.setText(usedstr.toString()); AlertDialog.Builder builder=new AlertDialog.Builder(this.getContext()); builder.setView(view); AlertDialog dialog=builder.create(); dialog.show(); */ //判断坐标是否是原来的数独 if(game.flag(selectedX, selectedY)==1){ DialogView dialog=new DialogView(getContext(), usedwords,this); dialog.show(); } return true; } public void SetSelectTitle(int title){ if(game.SetTitleValid(selectedX, selectedY, title)){ //刷新页面 invalidate(); } } }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】博客园携手 AI 驱动开发工具商 Chat2DB 推出联合终身会员
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 聊一聊 C#异步 任务延续的三种底层玩法
· 敏捷开发:如何高效开每日站会
· 为什么 .NET8线程池 容易引发线程饥饿
· golang自带的死锁检测并非银弹
· 如何做好软件架构师
· 欧阳的2024年终总结,迷茫,重生与失业
· 聊一聊 C#异步 任务延续的三种底层玩法
· 上位机能不能替代PLC呢?
· 2024年终总结:5000 Star,10w 下载量,这是我交出的开源答卷
· .NET Core:架构、特性和优势详解