Posted By

on 04/03/10


Tagged


Versions (?)

Sudoku (PuzzleView.java)


 / Published in: Java
 

from "Hello Android 2nd Edition" (ISBN: 1-934356-49-2)

  1. package org.example.sudoku;
  2.  
  3. import android.content.Context;
  4. import android.graphics.Canvas;
  5. import android.graphics.Paint;
  6. import android.graphics.Rect;
  7. import android.graphics.Paint.FontMetrics;
  8. import android.graphics.Paint.Style;
  9. import android.util.Log;
  10. import android.view.KeyEvent;
  11. import android.view.MotionEvent;
  12. import android.view.View;
  13. import android.view.animation.AnimationUtils;
  14.  
  15. public class PuzzleView extends View {
  16. private static final String TAG = "Sudoku";
  17. private final Game game;
  18. public PuzzleView(Context context) {
  19. super(context);
  20. this.game = (Game)context;
  21. setFocusable(true);
  22. setFocusableInTouchMode(true);
  23. }
  24.  
  25. private float width; // width of one tile
  26. private float height; // height of one tile
  27. private int selX; // X index of selection
  28. private int selY; // Y index of selection
  29. private final Rect selRect = new Rect();
  30.  
  31. @Override
  32. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  33. width = w / 9f;
  34. height = h / 9f;
  35. getRect(selX, selY, selRect);
  36. Log.d(TAG, "onSizeChanged: width " + width + ", height " + height);
  37. super.onSizeChanged(w, h, oldw, oldh);
  38. }
  39. private void getRect(int x, int y, Rect rect) {
  40. rect.set((int)(x * width), (int)(y * height),
  41. (int)(x * width + width), (int)(y * height + height));
  42. }
  43.  
  44. @Override
  45. protected void onDraw(Canvas canvas) {
  46. // Draw the background...
  47. Paint background = new Paint();
  48. background.setColor(getResources().getColor(R.color.puzzle_background));
  49. canvas.drawRect(0, 0, getWidth(), getHeight(), background);
  50.  
  51. // Draw the board...
  52. // Define colors for the grid lines
  53. Paint dark = new Paint();
  54. dark.setColor(getResources().getColor(R.color.puzzle_dark));
  55.  
  56. Paint hilite = new Paint();
  57. hilite.setColor(getResources().getColor(R.color.puzzle_hilite));
  58.  
  59. Paint light = new Paint();
  60. light.setColor(getResources().getColor(R.color.puzzle_light));
  61.  
  62. // Draw the minor grid lines
  63. for (int i = 0; i < 9; i++) {
  64. canvas.drawLine(0, i * height, getWidth(), i * height, light);
  65. canvas.drawLine(0, i * height + 1, getWidth(), i * height + 1, hilite);
  66. canvas.drawLine(i * width, 0, i * width, getHeight(), light);
  67. canvas.drawLine(i * width + 1, 0, i * width + 1, getHeight(), hilite);
  68. }
  69.  
  70. // Draw the major grid lines
  71. for (int i = 0; i < 9; i++) {
  72. if (i % 3 != 0)
  73. continue;
  74. canvas.drawLine(0, i * height, getWidth(), i * height, dark);
  75. canvas.drawLine(0, i * height + 1, getWidth(), i * height + 1, hilite);
  76. canvas.drawLine(i * width, 0, i * width, getHeight(), dark);
  77. canvas.drawLine(i * width + 1, 0, i * width + 1, getHeight(), hilite);
  78. }
  79.  
  80. // Draw the numbers...
  81. // Define color and style for numbers
  82. Paint foreground = new Paint(Paint.ANTI_ALIAS_FLAG);
  83. foreground.setColor(getResources().getColor(R.color.puzzle_foreground));
  84. foreground.setStyle(Style.FILL);
  85. foreground.setTextSize(height * 0.75f);
  86. foreground.setTextScaleX(width / height);
  87. foreground.setTextAlign(Paint.Align.CENTER);
  88.  
  89. // Draw the number in the center of the tile
  90. FontMetrics fm = foreground.getFontMetrics();
  91. // Centering in X: use alignment (and X at midpoint)
  92. float x = width / 2;
  93. // Centering in Y: measure ascent/descent first
  94. float y = height / 2 - (fm.ascent + fm.descent) / 2;
  95. for (int i = 0; i < 9; i++) {
  96. for (int j = 0; j < 9; j++) {
  97. canvas.drawText(this.game.getTileString(i, j), i * width + x, j * height + y, foreground);
  98. }
  99. }
  100.  
  101. if(Prefs.getHints(getContext())) {
  102. // Draw the hints...
  103. // Pick a hint color based on #moves left
  104. Paint hint = new Paint();
  105. int c[] = { getResources().getColor(R.color.puzzle_hint_0),
  106. getResources().getColor(R.color.puzzle_hint_1),
  107. getResources().getColor(R.color.puzzle_hint_2), };
  108. Rect r = new Rect();
  109. for(int i = 0; i < 9; i++) {
  110. for(int j = 0; j < 9; j++) {
  111. int movesleft = 9 - game.getUsedTiles(i, j).length;
  112. if(movesleft < c.length) {
  113. getRect(i, j, r);
  114. hint.setColor(c[movesleft]);
  115. canvas.drawRect(r, hint);
  116. }
  117. }
  118. }
  119. }
  120.  
  121. // Draw the selection
  122. Log.d(TAG, "selRect=" + selRect);
  123. Paint selected = new Paint();
  124. selected.setColor(getResources().getColor(R.color.puzzle_selected));
  125. canvas.drawRect(selRect, selected);
  126. }
  127.  
  128. @Override
  129. public boolean onKeyDown(int keyCode, KeyEvent event) {
  130. Log.d(TAG, "onKeyDown: keycode=" + keyCode + ", event=" + event);
  131. switch(keyCode) {
  132. case KeyEvent.KEYCODE_DPAD_UP:
  133. select(selX, selY - 1);
  134. break;
  135. case KeyEvent.KEYCODE_DPAD_DOWN:
  136. select(selX, selY + 1);
  137. break;
  138. case KeyEvent.KEYCODE_DPAD_LEFT:
  139. select(selX - 1, selY);
  140. break;
  141. case KeyEvent.KEYCODE_DPAD_RIGHT:
  142. select(selX + 1, selY);
  143. break;
  144. case KeyEvent.KEYCODE_0:
  145. case KeyEvent.KEYCODE_SPACE: setSelectedTile(0); break;
  146. case KeyEvent.KEYCODE_1: setSelectedTile(1); break;
  147. case KeyEvent.KEYCODE_2: setSelectedTile(2); break;
  148. case KeyEvent.KEYCODE_3: setSelectedTile(3); break;
  149. case KeyEvent.KEYCODE_4: setSelectedTile(4); break;
  150. case KeyEvent.KEYCODE_5: setSelectedTile(5); break;
  151. case KeyEvent.KEYCODE_6: setSelectedTile(6); break;
  152. case KeyEvent.KEYCODE_7: setSelectedTile(7); break;
  153. case KeyEvent.KEYCODE_8: setSelectedTile(8); break;
  154. case KeyEvent.KEYCODE_9: setSelectedTile(9); break;
  155. case KeyEvent.KEYCODE_ENTER:
  156. case KeyEvent.KEYCODE_DPAD_CENTER:
  157. game.showKeypadOrError(selX, selY);
  158. break;
  159. default:
  160. return super.onKeyDown(keyCode, event);
  161. }
  162. return true;
  163. }
  164.  
  165. @Override
  166. public boolean onTouchEvent(MotionEvent event) {
  167. if(event.getAction() != MotionEvent.ACTION_DOWN)
  168. return super.onTouchEvent(event);
  169.  
  170. select((int)(event.getX() / width), (int)(event.getY() / height));
  171. game.showKeypadOrError(selX, selY);
  172. Log.d(TAG, "onTouchEvent: x " + selX + ", y " + selY);
  173. return true;
  174. }
  175.  
  176. private void select(int x, int y) {
  177. invalidate(selRect);
  178. selX = Math.min(Math.max(x, 0), 8);
  179. selY = Math.min(Math.max(y, 0), 8);
  180. getRect(selX, selY, selRect);
  181. invalidate(selRect);
  182. }
  183.  
  184. public void setSelectedTile(int tile) {
  185. if(game.setTileIfValid(selX, selY, tile)) {
  186. invalidate(); // may change hints
  187. } else {
  188. // Number is not valid for this tile
  189. Log.d(TAG, "setSelectedTile: invalid: " + tile);
  190. startAnimation(AnimationUtils.loadAnimation(game, R.anim.shake));
  191. }
  192. }
  193. }

Report this snippet  

You need to login to post a comment.