热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android应用实践之数独游戏开发

这篇文章主要为大家详细介绍了Android应用实践之数独游戏开发,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

数独游戏是一种源自18世纪末的瑞士的游戏,后在美国发展、并在日本得以发扬光大的数学智力拼图游戏。拼图是九宫格(即3格宽×3格高)的正方形状,每一格又细分为一个九宫格。在每一个小九宫格中,分别填上1至9的数字,让整个大九宫格每一列、每一行的数字都不重复。

数独的玩法逻辑简单,数字排列方式千变万化。不少教育者认为数独是锻炼脑筋的好方法,上外语阅读课的时候外教老师就很喜欢带我们玩这个,乐此不疲,老外的教学方式还是很受欢迎的。但是每次玩这个游戏的时候都要发一张数独游戏卡,嫌麻烦,就想着写一个demo放自己手机上,想想那个时候真是好奇心爆棚,碰上很火爆的小游戏都想整一个DIY的Demo,叨叨够了,哈哈,上源码。

一、界面布局

1.主界面

<&#63;xml version="1.0" encoding="utf-8"&#63;>

  

    

    

2.数字键盘布局

<&#63;xml version="1.0" encoding="utf-8"&#63;>


  

    

3.游戏提示布局

<&#63;xml version="1.0" encoding="utf-8"&#63;>

  

二、游戏提示类

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
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

五、背景音乐

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, 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, getWidth(), i * height, light);
      canvas.drawLine(0, i * height + 1, getWidth(), i * height + 1,
          hilite);
      canvas.drawLine(i * width, 0, i * width, getHeight(), dark);
      canvas.drawLine(i * width + 1, 0, i * width + 1, getHeight(),
          hilite);
    }
    // draw major grid lines
    for (int i = 0; i <9; i++) {
      if (i % 3 != 0)
        continue;
      canvas.drawLine(0, i * height, getWidth(), i * height, dark);
      canvas.drawLine(0, i * height + 1, getWidth(), i * height + 1,
          hilite);
      canvas.drawLine(i * width, 0, i * width, getHeight(), dark);
      canvas.drawLine(i * width + 1, 0, i * width + 1, getHeight(),
          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

七、游戏设置

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 RadioButton放大或者缩小
    RadioButtonandroid并没有提供方法来控制按钮的大小,我自己在网 ... [详细]
  • 今天在家乡的一个it专栏上看到一位程序员写他自己面试前端的过程,一个水果忍者项目和一个电商平台项目,期望工资是20K,已经有三年工作经验了 ... [详细]
  • WPF调用模板
    WPF调用模板前台代码 ... [详细]
  • 开发笔记:python学习笔记
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了python学习笔记相关的知识,希望对你有一定的参考价值。1.loop ... [详细]
  • 为什么SpringBoot的jar可以直接运行
    这篇文章主要介绍了为什么SpringBoot的jar可以直接运行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着 ... [详细]
  • ***spring容器做的事情:*解析spring的配置文件,利用Java的反射机制创建对象**publicclasstestHelloWorld{T ... [详细]
  • 1、什么是Struts?   Struts是基于MVC的轻量级框架,主要处理请求分发的问题,重心在控制层和表现层。   –基于MVC:实现了MVC,满足MVC的设计思想。   –轻 ... [详细]
  • 1.什么时候使用到当使用到context:annotation-config或者context:component-scan配置的时候,及声明做为其它BeanFac ... [详细]
  • key_ctrl主要用于监控键盘按钮,定义按钮功能,便于智能车的控制和调试该包主要包含:key.hkey_ctrl_node.cpp ... [详细]
  • @JsonField和@JsonProperty的使用和区别
    @JsonFieldJsonField是位于fastjson包下的,实体类序列化为json字符串的时候,此类的原字段,序列化为json中的规定的字段配合JSON.toJSONStr ... [详细]
  • WCF多服务配置失败
    问题首先来看一下项目结构如图中所示,我需要在App.config文件中配置两个服务:IBookSerivices和IWcfSvrCallBack配置的结果如下面的XML代码 ... [详细]
  • [191]python3.6下scrapy框架的安装
    首先考虑使用最简单的方法安装pipinstallscrapy命令安装,提示FailedbuildingwheelforTwistedMicrosoftVisual ... [详细]
  • 1、war是一个web模块,其中需要包括WEB-INF,是可以直接运行的WEB模块;jar一般只是包括一些class文件,在声明了Main_class之后是可以用java命令运行的。2、wa ... [详细]
  • DimmyCompasnewMySTAComponent()PublicSubPage_Load()myComp.Name=BobEndSub  首选机 ... [详细]
  • spring data jpa介绍以及基础示例
    JPA介绍JPA的全称是JavaPersistenceAPI,提供了一个规范,用于将数据通过Java对象持久化、读取和管理数据库中的关系表。所以JPA本质上就是一种ORM规 ... [详细]
author-avatar
ayuanliang
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有