Conderoga

Untitled

Dec 30th, 2011
16
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. package com.DJR.MazeMaker;
  2.  
  3.  
  4. import android.graphics.Point;
  5.  
  6. import java.util.ArrayList;
  7. import java.util.Arrays;
  8. import java.util.Iterator;
  9. import java.util.LinkedList;
  10.  
  11. import android.app.Activity;
  12. import android.app.AlertDialog;
  13. import android.content.DialogInterface;
  14. import android.content.pm.ActivityInfo;
  15. import android.graphics.Bitmap;
  16. import android.graphics.Bitmap.Config;
  17. import android.graphics.Canvas;
  18. import android.graphics.Color;
  19. import android.graphics.Paint;
  20. import android.graphics.Rect;
  21. import android.graphics.RectF;
  22. import android.hardware.Sensor;
  23. import android.hardware.SensorEvent;
  24. import android.hardware.SensorEventListener;
  25. import android.hardware.SensorManager;
  26. import android.os.Bundle;
  27. import android.util.Log;
  28. import android.view.MotionEvent;
  29. import android.view.View;
  30. import android.view.View.OnClickListener;
  31. import android.view.View.OnTouchListener;
  32.  
  33. public class MazeMaker extends Activity implements OnTouchListener
  34. {
  35.  
  36. //actual Maze object
  37. private Maze maze;
  38. //holds maze, so only have to calculate drawing of image once, and can then redraw maze from image
  39. private Bitmap mazeBitmap;
  40. private Canvas mazeCanvas;
  41. private MazeView mazeView;
  42. //the length of each side of a cell (in pixels)
  43. private float horizWallLength, vertWallLength;
  44. //controls animation
  45. private ThreadClass animation_;
  46. //in cells, not pixels!!
  47. private int mazeWidth, mazeHeight;
  48. //start is 0, most recent point is the last
  49. private ArrayList<Point> path;
  50. //stores points for the fancy path
  51. private ArrayList<Point> pathPoints;
  52. private float thickness = -1;
  53. //volatile b/c modified in UI thread but used in main thread, want to make sure value is consistent
  54. private volatile int fingerX, fingerY;
  55. private volatile boolean fingerOn;
  56. private int startX, startY, endX,endY,minLength;
  57.  
  58.  
  59. @Override
  60. public void onCreate(Bundle savedInstanceState) {
  61. super.onCreate(savedInstanceState);
  62. setContentView(R.layout.main);
  63. this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
  64. }
  65.  
  66. @Override
  67. public void onStart()
  68. {
  69. super.onStart();
  70. AlertDialog.Builder dialog = new AlertDialog.Builder(this);
  71. dialog.setMessage("Welcome to Maze Maker, where YOU can solve randomly generated mazes!");
  72. dialog.setPositiveButton("OK", new DialogInterface.OnClickListener()
  73. {
  74. @Override
  75. public void onClick(DialogInterface dialog, int which)
  76. {
  77. dialog.dismiss();
  78. startGame();
  79. }
  80. });
  81. dialog.show();
  82. mazeView = (MazeView)findViewById(R.id.maze_view);
  83. if(mazeView == null){
  84. Log.e("Maze View","Could not find");
  85. }
  86. else{
  87. mazeView.setOnTouchListener(this);
  88. }
  89.  
  90. }
  91.  
  92. /**
  93. * Draws the maze image to the canvas and the current path over the canvas
  94. * @param canvas:the canvas to draw on
  95. */
  96. protected void drawGameContents(Canvas canvas)
  97. {
  98. if(mazeBitmap == null){
  99. resetMaze();
  100. }
  101. Paint p = new Paint();
  102. Bitmap tempBitmap = Bitmap.createBitmap(mazeView.getWidth(),mazeView.getHeight(),Bitmap.Config.ARGB_8888);
  103. Canvas tempCanvas = new Canvas(tempBitmap);
  104. tempCanvas.drawBitmap(mazeBitmap,new Rect(0,0,mazeBitmap.getWidth(),mazeBitmap.getHeight()), new RectF(0,0,mazeView.getWidth(),mazeView.getHeight()),p);
  105. //draw path and finger
  106. int drawColor = Color.RED;
  107. p.setColor(drawColor);
  108. float draw1X, draw2X, draw1Y, draw2Y;
  109.  
  110. thickness = Math.min(horizWallLength,vertWallLength)/3;
  111. p.setStrokeWidth(thickness);
  112. p.setColor(Color.RED);
  113. if(pathPoints!=null)
  114. for(int i = 0; i < pathPoints.size()-1; i++){
  115. tempCanvas.drawLine(pathPoints.get(i).x,pathPoints.get(i).y,
  116. pathPoints.get(i+1).x,pathPoints.get(i+1).y,p);
  117. tempCanvas.drawRect(pathPoints.get(i).x-(thickness/2.2f), pathPoints.get(i).y-(thickness/2.2f),
  118. pathPoints.get(i).x+(thickness/2.2f), pathPoints.get(i).y+(thickness/2.2f), p);
  119. if(i == pathPoints.size()-1){
  120. tempCanvas.drawRect(pathPoints.get(i+1).x-(thickness/2.2f), pathPoints.get(i+1).y-(thickness/2.2f),
  121. pathPoints.get(i+1).x+(thickness/2.2f), pathPoints.get(i+1).y+(thickness/2.2f), p);
  122. }
  123. }
  124.  
  125. //Old Path Drawing
  126. /*if(path!=null && path.size()>1){
  127. //Log.e("Drawing path",""+path.size());
  128. //starts from end b/c used to try to do color gradient as path got older, but too much work/didn't work
  129. int i = path.size()-1;
  130. Point cur = path.get(i);
  131. draw2X = (cur.x +0.5f)*horizWallLength;
  132. draw2Y = (cur.y +0.5f)*vertWallLength;
  133. thickness = Math.min(horizWallLength,vertWallLength)/3;
  134. p.setStrokeWidth(thickness);
  135. i--;
  136. while(i>=0){
  137. cur = path.get(i);
  138. draw1X = draw2X;
  139. draw1Y = draw2Y;
  140. draw2X = (cur.x +0.5f)*horizWallLength;
  141. draw2Y = (cur.y +0.5f)*vertWallLength;
  142. //drawColor -= 0x080000;
  143. if(drawColor<0x800000){
  144. drawColor = 0x800000;//after a while, all same color
  145. }
  146. p.setColor(drawColor);
  147. //tempCanvas.drawRect(draw1X-.2f*horizWallLength,draw1Y-.2f*vertWallLength,draw2X+.2f*horizWallLength,draw2Y+.2f*vertWallLength, p);
  148. tempCanvas.drawLine(draw1X,draw1Y,draw2X,draw2Y,p);
  149. i--;
  150. }
  151.  
  152. }*/
  153. /*p.setStrokeWidth(6);
  154. if(fingerOn && path!=null && path.size()>0){
  155. //Log.e("Drawing","Finger");
  156. Point last = path.get(path.size()-1);
  157. draw1X = (last.x +0.5f)*horizWallLength;
  158. draw1Y = (last.y +0.5f)*vertWallLength;
  159. draw2X = (fingerX +0.5f)*horizWallLength;
  160. draw2Y = (fingerY +0.5f)*vertWallLength;
  161. p.setColor(0x00FF00);
  162. tempCanvas.drawLine(draw1X,draw1Y,draw2X,draw2Y,p);
  163. }*/
  164. if(fingerOn){
  165. p.setColor(Color.YELLOW);
  166. //tempCanvas.drawCircle(fingerX,fingerY,Math.min(horizWallLength,vertWallLength)/2,p);
  167. //tempCanvas.drawCircle(path.getFirst().x, path.getFirst().y, Math.min(horizWallLength,vertWallLength)/3, p);
  168. }
  169. //copy drawing from temp bitmap over to final bitmap
  170. p.setColor(Color.WHITE);//not sure why this prevents whole screen from being black, but it does...
  171. canvas.drawBitmap(tempBitmap,new Rect(0,0,mazeView.getWidth(),mazeView.getHeight()), new RectF(0,0,mazeView.getWidth(),mazeView.getHeight()),p);//allows scaling of final thing to fit screen while having to do no scaling calculations throughout logic
  172. }
  173.  
  174. private void resetMaze(){
  175. int r, c;
  176. //prompt user for menu (probably small, medium, large, maybe XL choice from a list) TODO - use AlertDialog
  177. r = 5;
  178. c = 10;
  179. maze = new Maze(r,c);
  180. maze.generateMaze();
  181. Log.e("copy",maze.printMaze());
  182. horizWallLength = (1.0f*mazeView.getWidth())/c;
  183. vertWallLength = (1.0f*mazeView.getHeight())/r;
  184. if(path!=null){
  185. path.clear();
  186. }
  187. else{
  188. path = new ArrayList<Point>();
  189. }
  190. mazeBitmap = Bitmap.createBitmap(mazeView.getWidth(),mazeView.getHeight(),Config.ARGB_8888);
  191. mazeCanvas = new Canvas(mazeBitmap);
  192. Log.e("Maze Bitmap created: ",mazeCanvas.getWidth()+"x"+mazeCanvas.getHeight());
  193. Paint p = new Paint();
  194. p.setStrokeWidth(3);
  195. mazeCanvas.drawColor(Color.WHITE);
  196.  
  197. int[] endsStuff = maze.getFurthestEnds();
  198. //gets furthest start and end points, as well as the distance between them
  199. startX = endsStuff[0];
  200. startY = endsStuff[1];
  201. endX = endsStuff[2];
  202. endY = endsStuff[3];
  203. minLength = endsStuff[4];
  204.  
  205. p.setColor(Color.GREEN);
  206. mazeCanvas.drawRect(startX*horizWallLength, startY*vertWallLength, (startX+1)*horizWallLength, (startY+1)*vertWallLength, p);
  207. p.setColor(Color.CYAN);
  208. mazeCanvas.drawRect(endX*horizWallLength, endY*vertWallLength, (endX+1)*horizWallLength, (endY+1)*vertWallLength, p);
  209. p.setColor(Color.BLACK);
  210. mazeCanvas.drawLine(0,0,mazeCanvas.getWidth(),0,p);
  211. mazeCanvas.drawLine(0,0,0,mazeCanvas.getHeight(),p);
  212. //top right corner of square being drawn
  213. float drawX, drawY;
  214. drawY = 0.0f;
  215. for(int r2 = 0; r2<r;r2++){
  216. drawX = 0;
  217. for(int c2 = 0; c2<c;c2++){
  218. if(maze.hasSouthWall(r2, c2)){
  219. mazeCanvas.drawLine(drawX,drawY+vertWallLength,drawX+horizWallLength,drawY+vertWallLength,p);
  220. //Log.e("("+r2+","+c2+")","has south wall, drawing from ("+(drawX/horizWallLength)+","+((drawY+vertWallLength)/vertWallLength)+") to ("+((drawX+horizWallLength)/horizWallLength)+","+((drawY+vertWallLength)/vertWallLength)+")");
  221. }
  222. if(maze.hasEastWall(r2,c2)){
  223. mazeCanvas.drawLine(drawX+horizWallLength, drawY, drawX+horizWallLength, drawY+vertWallLength, p);
  224. //Log.e("("+r2+","+c2+")","has east wall, drawing from ("+((drawX+horizWallLength)/horizWallLength)+","+(drawY/vertWallLength)+") to ("+((drawX+horizWallLength)/horizWallLength)+","+((drawY+vertWallLength)/vertWallLength)+")");
  225. }
  226. /*p.setColor(Color.RED);
  227. mazeCanvas.drawCircle(drawX,drawY,12,p);
  228. p.setColor(Color.BLACK);*/
  229. drawX+=horizWallLength;
  230. }
  231. drawY+=vertWallLength;
  232. }
  233. /*//make up bs path for testing
  234. path = new LinkedList<Point>();
  235. path.addFirst(new Point(0,0));
  236. path.addFirst(new Point(0,1));
  237. path.addFirst(new Point(1,1));
  238. path.addFirst(new Point(2,1));
  239. for(int i = 0; i<walls.length;i++){
  240. Log.e("Walls",Arrays.toString(walls[i]));
  241. }*/
  242. //need to do the wall checking testing
  243. //Log.e("Clear between (0,0) and (1,1)",""+noWallsBetween(new Point(0,0), new Point(1,1)));
  244. //Log.e("Clear between (0,0) and (1,0)",""+noWallsBetween(new Point(0,0), new Point(1,0)));
  245. //Log.e("Clear between (0,0) and (0,1)",""+noWallsBetween(new Point(0,0), new Point(0,1)));
  246. //Log.e("Clear between (1,1) and (4,1)",""+noWallsBetween(new Point(1,1), new Point(4,1)));
  247.  
  248. }
  249. private void handlePathPoint(int x, int y){
  250. Point p = new Point(x,y);
  251. if(checkPathPoint(p)){
  252. pathPoints.add(p);
  253. }
  254. }
  255. private boolean checkPathPoint(Point p){
  256. if(thickness == -1)
  257. return false;
  258. float remX = p.x%horizWallLength;
  259. float remY = p.y % vertWallLength;
  260. return remX>thickness/2 && remX < horizWallLength-(thickness/2) &&
  261. remY>thickness/2 && remY < vertWallLength-(thickness/2);
  262. }
  263. private boolean pointsEqual(Point p1, Point p2){
  264. return p1.x==p2.x && p1.y == p2.y;
  265. }
  266. /**
  267. * Starts the animation thread, which starts the game
  268. */
  269. public void startGame()
  270. {
  271. if(animation_==null)
  272. {
  273. animation_ = new ThreadClass(this);
  274. }
  275. animation_.start();
  276. if(mazeView == null){
  277. Log.e("Maze View","Retrying to set maze view");
  278. }
  279. if(mazeView == null){
  280. Log.e("Maze View","Retry failed");
  281. }
  282. else{
  283. Log.e("Maze View","Retry succesful");
  284. }
  285.  
  286. }
  287. /**
  288. * Stops the animation thread, which stops the game
  289. */
  290. public void stopGame()
  291. {
  292. if(animation_!=null)
  293. {
  294. animation_.stop();
  295. }
  296. animation_ = null;
  297. }
  298.  
  299. /*private void reset()
  300. {
  301. if(data_!=null)
  302. {
  303. data_.reset();
  304. }
  305. else
  306. {
  307. data_ = new GameData(this);
  308. }
  309. }*/
  310.  
  311.  
  312. @Override
  313. protected void onResume()
  314. {
  315. super.onResume();
  316. if(animation_!=null)
  317. {
  318. animation_.start();
  319. }
  320. }
  321.  
  322. @Override
  323. protected void onPause()
  324. {
  325. super.onPause();
  326. if(animation_!=null)
  327. {
  328. animation_.pause();
  329. }
  330. }
  331.  
  332. @Override
  333. protected void onStop()
  334. {
  335. super.onStop();
  336. stopGame();
  337. if(mazeView!=null)
  338. mazeView.setCanvas(null);
  339. mazeView = null;
  340. }
  341.  
  342. /**
  343. * Class that runs the animation thread
  344. */
  345. private class ThreadClass
  346. {
  347. private Thread thread_;
  348. private boolean running_;
  349. private MazeMaker parent_;
  350.  
  351. public ThreadClass(MazeMaker parent)
  352. {
  353. this.thread_ = null;
  354. this.running_ = false;
  355. parent_ = parent;
  356. }
  357.  
  358. public void start()
  359. {
  360. this.running_ = true;
  361.  
  362. if(this.thread_ == null)
  363. {
  364. this.thread_ = new Thread(new Runnable()
  365. {
  366. @Override
  367. public void run() {
  368. try {
  369. Thread.sleep(100);
  370. } catch (InterruptedException e1) {
  371. Log.e("Animation","Sleep at beginning failed");
  372. }
  373. while(running_)
  374. {
  375. updateScreen();
  376. try {
  377. Thread.sleep(20);//framerate of 50
  378. } catch (InterruptedException e) {
  379. e.printStackTrace();
  380. }//could add draw tracking to make sure sleeps exactly 20 seconds
  381. //and not just 20 seconds + the time it takes the frame to draw - TODO?
  382.  
  383. }
  384. }
  385. }, "Animation Thread");
  386. }
  387. try
  388. {
  389. this.thread_.start();
  390. }
  391. catch(Exception e) {}
  392. }
  393. private void updateScreen(){
  394. MazeView mv = parent_.mazeView;
  395. if(mv == null){
  396. //Log.e("Maze View","Maze View is still null, trying to reset before drawing");
  397. parent_.mazeView = (MazeView)parent_.findViewById(R.id.maze_view);
  398. if(parent_.mazeView == null){
  399. Log.e("Maze View","Maze View is eternally null, quitting this drawing cycle");
  400. return;
  401. }
  402. }
  403. try
  404. {
  405. mv.setCanvas( mv.getHolder().lockCanvas() );
  406. synchronized (mv.getHolder())//google said to >.>
  407. {
  408. parent_.drawGameContents(mv.getCanvas());
  409. }
  410. }
  411. catch (NullPointerException e)
  412. {
  413. Log.e("Drawing","Null Pointer when drawing: "+Arrays.toString(e.getStackTrace()));
  414. }
  415. catch(IndexOutOfBoundsException e){
  416. Log.e("Drawing","OBOE when drawing: "+Arrays.toString(e.getStackTrace()));
  417. }
  418. finally
  419. {
  420. if(mv.getCanvas()!=null)
  421. {
  422. mv.getHolder().unlockCanvasAndPost(mv.getCanvas());
  423. }
  424. }
  425. }
  426.  
  427. public void pause()
  428. {
  429. this.running_ = false;
  430. }
  431.  
  432. public void stop()
  433. {
  434. this.running_ = false;
  435. }
  436. }
  437.  
  438. @Override
  439. public boolean onTouch(View v, MotionEvent event) {
  440. //Log.e("Touch event",event.toString());
  441. int a = event.getAction();
  442. if(a==MotionEvent.ACTION_UP || a == MotionEvent.ACTION_CANCEL){
  443. if(path==null){
  444. path = new ArrayList<Point>();
  445. }
  446. else{
  447. path.clear();
  448. }
  449. if(pathPoints == null){
  450. pathPoints = new ArrayList<Point>();
  451. }
  452. else
  453. pathPoints.clear();
  454. fingerOn = false;
  455. }
  456. else if(a==MotionEvent.ACTION_DOWN){
  457. if(path==null){
  458. path = new ArrayList<Point>();
  459. }
  460. else{
  461. path.clear();
  462. }
  463. if(pathPoints == null){
  464. pathPoints = new ArrayList<Point>();
  465. }
  466. else
  467. pathPoints.clear();
  468. fingerX = (int)event.getX();
  469. fingerY = (int)event.getY();
  470. handlePathPoint(fingerX,fingerY);
  471. Point temp = new Point((int)(fingerX/horizWallLength),(int)(fingerY/vertWallLength));
  472. if(temp.x == startX && temp.y == startY){
  473. Log.e("Path","Starting path at ("+temp.x+","+temp.y+")");
  474. path.add(temp);
  475. fingerOn = true;
  476. }
  477. }
  478. else if(a == MotionEvent.ACTION_MOVE){
  479. if(fingerOn){
  480. fingerX = (int)event.getX();
  481. fingerY = (int)event.getY();
  482. Point temp = new Point((int)(fingerX/horizWallLength),(int)(fingerY/vertWallLength));
  483. if(noWallsBetween(path.get(path.size()-1),temp)){
  484. handlePathPoint(fingerX,fingerY);
  485. if(!pointsEqual(path.get(path.size()-1),temp)){
  486. addAllBetween(path.get(path.size()-1),temp);
  487. Log.e("Path","Adding ("+temp.x+","+temp.y+")");
  488. path.add(temp);
  489. if(temp.x == endX && temp.y == endY){
  490. gameWon();
  491. }
  492. }
  493. }
  494. }
  495. else{
  496. Point temp = new Point((int)(fingerX/horizWallLength),(int)(fingerY/vertWallLength));
  497. if(temp.x == startX && temp.y == startY){
  498. handlePathPoint(fingerX,fingerY);
  499. path.add(temp);
  500. fingerOn = true;
  501. Log.e("Path","Starting path at ("+temp.x+","+temp.y+")");
  502. }
  503. }
  504. }
  505. return true;
  506. }
  507.  
  508. private boolean noWallsBetween(Point a, Point b){
  509. if(a.x!=b.x && a.y!=b.y){
  510. return false;
  511. }
  512. //return false in this special case because a = b, so no need to add more points to path
  513. /* I needed this for something with the fancy path
  514. else if(a.x == b.x && a.y == b.y){
  515. return false;
  516. }*/
  517.  
  518. else if(a.x == b.x){
  519. int min = Math.min(a.y,b.y);
  520. int max = Math.max(a.y,b.y);
  521. for(int i = min;i<max;i++){
  522. if(maze.hasSouthWall(i,a.x)){
  523. Log.e("Wall between","Failed: South wall at ("+a.x+","+i+")");
  524. return false;
  525. }
  526. }
  527. return true;
  528. }
  529. //a.y == b.y
  530. else{
  531. int min = Math.min(a.x,b.x);
  532. int max = Math.max(a.x,b.x);
  533. for(int i = min;i<max;i++){
  534. if(maze.hasEastWall(a.y,i)){
  535. Log.e("Wall between","Failed: East wall at ("+i+","+a.y+")");
  536. return false;
  537. }
  538. }
  539. return true;
  540. }
  541. }
  542. /**
  543. * Precondition: assumes in line, no walls between a and b
  544. * @param a
  545. * @param b
  546. */
  547. private void addAllBetween(Point a, Point b){
  548. //starts at a+1 because a is already in path
  549. //stops right before b, because b will get added after
  550. if(a.x == b.x){
  551. if(a.y>b.y){
  552. for(int i = a.y-1;i>b.y;i--){
  553. path.add(new Point(a.x,i));
  554. }
  555. }
  556. else{
  557. for(int i = a.y+1;i<b.y;i++){
  558. path.add(new Point(a.x,i));
  559. }
  560. }
  561. }
  562. //a.y == b.y
  563. else{
  564. if(a.y!=b.y){
  565. Log.e("AddAllBetween","Sanity check error, method was called when points were not in line");
  566. return;
  567. }
  568. if(a.x>b.x){
  569. for(int i = a.x-1;i>b.x;i--){
  570. path.add(new Point(i,a.y));
  571. }
  572. }
  573. else{
  574. for(int i = a.x+1;i<b.x;i++){
  575. path.add(new Point(i,a.y));
  576. }
  577. }
  578. }
  579. }
  580.  
  581. /**
  582. * Tells the user that they have successfully completed the game,
  583. * offers them multiple options for what to do next
  584. */
  585. private void gameWon(){
  586. Log.e("Game","You won!");
  587. AlertDialog.Builder dialog = new AlertDialog.Builder(this);
  588. dialog.setCancelable(false);
  589. dialog.setPositiveButton("Try a new maze", new DialogInterface.OnClickListener()
  590. {
  591. public void onClick(DialogInterface dialog, int id)
  592. {
  593. //restart
  594. resetMaze();
  595. dialog.dismiss();
  596. }
  597. });
  598. dialog.setNegativeButton("Quit", new DialogInterface.OnClickListener()
  599. {
  600. public void onClick(DialogInterface dialog, int id)
  601. {
  602. finish();//quit
  603. }
  604. });
  605. String s = "Congratulations! You solved the maze!\n";
  606. if(minLength >= path.size()-1){//maybe an oboe?.. who knows
  607. //if(minLength == 0){for testing
  608. s+="You made it from start to finish with the shortest path possible!";
  609. dialog.setMessage(s+"\nDo you want to quit or play a new maze?");
  610. dialog.show();
  611. }
  612. else{
  613. s+="However, there was a shorter path from start to end that was ";
  614. if(path.size()-minLength-1 ==1){
  615. s+= "1 space shorter.";
  616. }
  617. else{
  618. s+=(path.size()-minLength-1)+" spaces shorter.";
  619. }
  620.  
  621. dialog.setCancelable(true);
  622. dialog.setNeutralButton("Retry", new DialogInterface.OnClickListener() {
  623. @Override
  624. public void onClick(DialogInterface dialog, int id)
  625. {
  626. fingerOn = false;
  627. }
  628. });
  629. dialog.setMessage(s+"\nDo you want to play again, quit, or play a new maze?");
  630. dialog.show();
  631. }
  632.  
  633. }
  634. }
RAW Paste Data