Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.DJR.MazeMaker;
- import android.graphics.Point;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Iterator;
- import java.util.LinkedList;
- import android.app.Activity;
- import android.app.AlertDialog;
- import android.content.DialogInterface;
- import android.content.pm.ActivityInfo;
- import android.graphics.Bitmap;
- import android.graphics.Bitmap.Config;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.graphics.Rect;
- import android.graphics.RectF;
- import android.hardware.Sensor;
- import android.hardware.SensorEvent;
- import android.hardware.SensorEventListener;
- import android.hardware.SensorManager;
- import android.os.Bundle;
- import android.util.Log;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.view.View.OnTouchListener;
- public class MazeMaker extends Activity implements OnTouchListener
- {
- //actual Maze object
- private Maze maze;
- //holds maze, so only have to calculate drawing of image once, and can then redraw maze from image
- private Bitmap mazeBitmap;
- private Canvas mazeCanvas;
- private MazeView mazeView;
- //the length of each side of a cell (in pixels)
- private float horizWallLength, vertWallLength;
- //controls animation
- private ThreadClass animation_;
- //in cells, not pixels!!
- private int mazeWidth, mazeHeight;
- //start is 0, most recent point is the last
- private ArrayList<Point> path;
- //stores points for the fancy path
- private ArrayList<Point> pathPoints;
- private float thickness = -1;
- //volatile b/c modified in UI thread but used in main thread, want to make sure value is consistent
- private volatile int fingerX, fingerY;
- private volatile boolean fingerOn;
- private int startX, startY, endX,endY,minLength;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
- }
- @Override
- public void onStart()
- {
- super.onStart();
- AlertDialog.Builder dialog = new AlertDialog.Builder(this);
- dialog.setMessage("Welcome to Maze Maker, where YOU can solve randomly generated mazes!");
- dialog.setPositiveButton("OK", new DialogInterface.OnClickListener()
- {
- @Override
- public void onClick(DialogInterface dialog, int which)
- {
- dialog.dismiss();
- startGame();
- }
- });
- dialog.show();
- mazeView = (MazeView)findViewById(R.id.maze_view);
- if(mazeView == null){
- Log.e("Maze View","Could not find");
- }
- else{
- mazeView.setOnTouchListener(this);
- }
- }
- /**
- * Draws the maze image to the canvas and the current path over the canvas
- * @param canvas:the canvas to draw on
- */
- protected void drawGameContents(Canvas canvas)
- {
- if(mazeBitmap == null){
- resetMaze();
- }
- Paint p = new Paint();
- Bitmap tempBitmap = Bitmap.createBitmap(mazeView.getWidth(),mazeView.getHeight(),Bitmap.Config.ARGB_8888);
- Canvas tempCanvas = new Canvas(tempBitmap);
- tempCanvas.drawBitmap(mazeBitmap,new Rect(0,0,mazeBitmap.getWidth(),mazeBitmap.getHeight()), new RectF(0,0,mazeView.getWidth(),mazeView.getHeight()),p);
- //draw path and finger
- int drawColor = Color.RED;
- p.setColor(drawColor);
- float draw1X, draw2X, draw1Y, draw2Y;
- thickness = Math.min(horizWallLength,vertWallLength)/3;
- p.setStrokeWidth(thickness);
- p.setColor(Color.RED);
- if(pathPoints!=null)
- for(int i = 0; i < pathPoints.size()-1; i++){
- tempCanvas.drawLine(pathPoints.get(i).x,pathPoints.get(i).y,
- pathPoints.get(i+1).x,pathPoints.get(i+1).y,p);
- tempCanvas.drawOval(new RectF(pathPoints.get(i).x-(thickness/2), pathPoints.get(i).y-(thickness/2),
- pathPoints.get(i).x+(thickness/2), pathPoints.get(i).y+(thickness/2)), p);
- if(i == pathPoints.size()-1){
- tempCanvas.drawOval(new RectF(pathPoints.get(i+1).x-(thickness/2), pathPoints.get(i+1).y-(thickness/2),
- pathPoints.get(i+1).x+(thickness/2), pathPoints.get(i+1).y+(thickness/2)), p);
- }
- }
- //Old Path Drawing
- /*if(path!=null && path.size()>1){
- //Log.e("Drawing path",""+path.size());
- //starts from end b/c used to try to do color gradient as path got older, but too much work/didn't work
- int i = path.size()-1;
- Point cur = path.get(i);
- draw2X = (cur.x +0.5f)*horizWallLength;
- draw2Y = (cur.y +0.5f)*vertWallLength;
- thickness = Math.min(horizWallLength,vertWallLength)/3;
- p.setStrokeWidth(thickness);
- i--;
- while(i>=0){
- cur = path.get(i);
- draw1X = draw2X;
- draw1Y = draw2Y;
- draw2X = (cur.x +0.5f)*horizWallLength;
- draw2Y = (cur.y +0.5f)*vertWallLength;
- //drawColor -= 0x080000;
- if(drawColor<0x800000){
- drawColor = 0x800000;//after a while, all same color
- }
- p.setColor(drawColor);
- //tempCanvas.drawRect(draw1X-.2f*horizWallLength,draw1Y-.2f*vertWallLength,draw2X+.2f*horizWallLength,draw2Y+.2f*vertWallLength, p);
- tempCanvas.drawLine(draw1X,draw1Y,draw2X,draw2Y,p);
- i--;
- }
- }*/
- /*p.setStrokeWidth(6);
- if(fingerOn && path!=null && path.size()>0){
- //Log.e("Drawing","Finger");
- Point last = path.get(path.size()-1);
- draw1X = (last.x +0.5f)*horizWallLength;
- draw1Y = (last.y +0.5f)*vertWallLength;
- draw2X = (fingerX +0.5f)*horizWallLength;
- draw2Y = (fingerY +0.5f)*vertWallLength;
- p.setColor(0x00FF00);
- tempCanvas.drawLine(draw1X,draw1Y,draw2X,draw2Y,p);
- }*/
- if(fingerOn){
- p.setColor(Color.YELLOW);
- //tempCanvas.drawCircle(fingerX,fingerY,Math.min(horizWallLength,vertWallLength)/2,p);
- //tempCanvas.drawCircle(path.getFirst().x, path.getFirst().y, Math.min(horizWallLength,vertWallLength)/3, p);
- }
- //copy drawing from temp bitmap over to final bitmap
- p.setColor(Color.WHITE);//not sure why this prevents whole screen from being black, but it does...
- 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
- }
- private void resetMaze(){
- int r, c;
- //prompt user for menu (probably small, medium, large, maybe XL choice from a list) TODO - use AlertDialog
- r = 5;
- c = 10;
- maze = new Maze(r,c);
- maze.generateMaze();
- Log.e("copy",maze.printMaze());
- horizWallLength = (1.0f*mazeView.getWidth())/c;
- vertWallLength = (1.0f*mazeView.getHeight())/r;
- if(path!=null){
- path.clear();
- }
- else{
- path = new ArrayList<Point>();
- }
- mazeBitmap = Bitmap.createBitmap(mazeView.getWidth(),mazeView.getHeight(),Config.ARGB_8888);
- mazeCanvas = new Canvas(mazeBitmap);
- Log.e("Maze Bitmap created: ",mazeCanvas.getWidth()+"x"+mazeCanvas.getHeight());
- Paint p = new Paint();
- p.setStrokeWidth(3);
- mazeCanvas.drawColor(Color.WHITE);
- int[] endsStuff = maze.getFurthestEnds();
- //gets furthest start and end points, as well as the distance between them
- startX = endsStuff[0];
- startY = endsStuff[1];
- endX = endsStuff[2];
- endY = endsStuff[3];
- minLength = endsStuff[4];
- p.setColor(Color.GREEN);
- mazeCanvas.drawRect(startX*horizWallLength, startY*vertWallLength, (startX+1)*horizWallLength, (startY+1)*vertWallLength, p);
- p.setColor(Color.CYAN);
- mazeCanvas.drawRect(endX*horizWallLength, endY*vertWallLength, (endX+1)*horizWallLength, (endY+1)*vertWallLength, p);
- p.setColor(Color.BLACK);
- mazeCanvas.drawLine(0,0,mazeCanvas.getWidth(),0,p);
- mazeCanvas.drawLine(0,0,0,mazeCanvas.getHeight(),p);
- //top right corner of square being drawn
- float drawX, drawY;
- drawY = 0.0f;
- for(int r2 = 0; r2<r;r2++){
- drawX = 0;
- for(int c2 = 0; c2<c;c2++){
- if(maze.hasSouthWall(r2, c2)){
- mazeCanvas.drawLine(drawX,drawY+vertWallLength,drawX+horizWallLength,drawY+vertWallLength,p);
- //Log.e("("+r2+","+c2+")","has south wall, drawing from ("+(drawX/horizWallLength)+","+((drawY+vertWallLength)/vertWallLength)+") to ("+((drawX+horizWallLength)/horizWallLength)+","+((drawY+vertWallLength)/vertWallLength)+")");
- }
- if(maze.hasEastWall(r2,c2)){
- mazeCanvas.drawLine(drawX+horizWallLength, drawY, drawX+horizWallLength, drawY+vertWallLength, p);
- //Log.e("("+r2+","+c2+")","has east wall, drawing from ("+((drawX+horizWallLength)/horizWallLength)+","+(drawY/vertWallLength)+") to ("+((drawX+horizWallLength)/horizWallLength)+","+((drawY+vertWallLength)/vertWallLength)+")");
- }
- /*p.setColor(Color.RED);
- mazeCanvas.drawCircle(drawX,drawY,12,p);
- p.setColor(Color.BLACK);*/
- drawX+=horizWallLength;
- }
- drawY+=vertWallLength;
- }
- /*//make up bs path for testing
- path = new LinkedList<Point>();
- path.addFirst(new Point(0,0));
- path.addFirst(new Point(0,1));
- path.addFirst(new Point(1,1));
- path.addFirst(new Point(2,1));
- for(int i = 0; i<walls.length;i++){
- Log.e("Walls",Arrays.toString(walls[i]));
- }*/
- //need to do the wall checking testing
- //Log.e("Clear between (0,0) and (1,1)",""+noWallsBetween(new Point(0,0), new Point(1,1)));
- //Log.e("Clear between (0,0) and (1,0)",""+noWallsBetween(new Point(0,0), new Point(1,0)));
- //Log.e("Clear between (0,0) and (0,1)",""+noWallsBetween(new Point(0,0), new Point(0,1)));
- //Log.e("Clear between (1,1) and (4,1)",""+noWallsBetween(new Point(1,1), new Point(4,1)));
- }
- private void handlePathPoint(int x, int y){
- Point p = new Point(x,y);
- if(checkPathPoint(p)){
- pathPoints.add(p);
- }
- }
- private boolean checkPathPoint(Point p){
- if(thickness == -1)
- return false;
- float remX = p.x%horizWallLength;
- float remY = p.y % vertWallLength;
- return remX>thickness/2 && remX < horizWallLength-(thickness/2) &&
- remY>thickness/2 && remY < vertWallLength-(thickness/2);
- }
- private boolean pointsEqual(Point p1, Point p2){
- return p1.x==p2.x && p1.y == p2.y;
- }
- /**
- * Starts the animation thread, which starts the game
- */
- public void startGame()
- {
- if(animation_==null)
- {
- animation_ = new ThreadClass(this);
- }
- animation_.start();
- if(mazeView == null){
- Log.e("Maze View","Retrying to set maze view");
- }
- if(mazeView == null){
- Log.e("Maze View","Retry failed");
- }
- else{
- Log.e("Maze View","Retry succesful");
- }
- }
- /**
- * Stops the animation thread, which stops the game
- */
- public void stopGame()
- {
- if(animation_!=null)
- {
- animation_.stop();
- }
- animation_ = null;
- }
- /*private void reset()
- {
- if(data_!=null)
- {
- data_.reset();
- }
- else
- {
- data_ = new GameData(this);
- }
- }*/
- @Override
- protected void onResume()
- {
- super.onResume();
- if(animation_!=null)
- {
- animation_.start();
- }
- }
- @Override
- protected void onPause()
- {
- super.onPause();
- if(animation_!=null)
- {
- animation_.pause();
- }
- }
- @Override
- protected void onStop()
- {
- super.onStop();
- stopGame();
- if(mazeView!=null)
- mazeView.setCanvas(null);
- mazeView = null;
- }
- /**
- * Class that runs the animation thread
- */
- private class ThreadClass
- {
- private Thread thread_;
- private boolean running_;
- private MazeMaker parent_;
- public ThreadClass(MazeMaker parent)
- {
- this.thread_ = null;
- this.running_ = false;
- parent_ = parent;
- }
- public void start()
- {
- this.running_ = true;
- if(this.thread_ == null)
- {
- this.thread_ = new Thread(new Runnable()
- {
- @Override
- public void run() {
- try {
- Thread.sleep(10);
- } catch (InterruptedException e1) {
- Log.e("Animation","Sleep at beginning failed");
- }
- while(running_)
- {
- updateScreen();
- try {
- Thread.sleep(20);//framerate of 50
- } catch (InterruptedException e) {
- e.printStackTrace();
- }//could add draw tracking to make sure sleeps exactly 20 seconds
- //and not just 20 seconds + the time it takes the frame to draw - TODO?
- }
- }
- }, "Animation Thread");
- }
- try
- {
- this.thread_.start();
- }
- catch(Exception e) {}
- }
- private void updateScreen(){
- MazeView mv = parent_.mazeView;
- if(mv == null){
- //Log.e("Maze View","Maze View is still null, trying to reset before drawing");
- parent_.mazeView = (MazeView)parent_.findViewById(R.id.maze_view);
- if(parent_.mazeView == null){
- Log.e("Maze View","Maze View is eternally null, quitting this drawing cycle");
- return;
- }
- }
- try
- {
- mv.setCanvas( mv.getHolder().lockCanvas() );
- synchronized (mv.getHolder())//google said to >.>
- {
- parent_.drawGameContents(mv.getCanvas());
- }
- }
- catch (NullPointerException e)
- {
- Log.e("Drawing","Null Pointer when drawing: "+Arrays.toString(e.getStackTrace()));
- }
- catch(IndexOutOfBoundsException e){
- Log.e("Drawing","OBOE when drawing: "+Arrays.toString(e.getStackTrace()));
- }
- finally
- {
- if(mv.getCanvas()!=null)
- {
- mv.getHolder().unlockCanvasAndPost(mv.getCanvas());
- }
- }
- }
- public void pause()
- {
- this.running_ = false;
- }
- public void stop()
- {
- this.running_ = false;
- }
- }
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- //Log.e("Touch event",event.toString());
- int a = event.getAction();
- if(a==MotionEvent.ACTION_UP || a == MotionEvent.ACTION_CANCEL){
- if(path==null){
- path = new ArrayList<Point>();
- }
- else{
- path.clear();
- }
- if(pathPoints == null){
- pathPoints = new ArrayList<Point>();
- }
- else
- pathPoints.clear();
- fingerOn = false;
- }
- else if(a==MotionEvent.ACTION_DOWN){
- if(path==null){
- path = new ArrayList<Point>();
- }
- else{
- path.clear();
- }
- if(pathPoints == null){
- pathPoints = new ArrayList<Point>();
- }
- else
- pathPoints.clear();
- fingerX = (int)event.getX();
- fingerY = (int)event.getY();
- handlePathPoint(fingerX,fingerY);
- Point temp = new Point((int)(fingerX/horizWallLength),(int)(fingerY/vertWallLength));
- if(temp.x == startX && temp.y == startY){
- Log.e("Path","Starting path at ("+temp.x+","+temp.y+")");
- path.add(temp);
- fingerOn = true;
- }
- }
- else if(a == MotionEvent.ACTION_MOVE){
- if(fingerOn){
- fingerX = (int)event.getX();
- fingerY = (int)event.getY();
- Point temp = new Point((int)(fingerX/horizWallLength),(int)(fingerY/vertWallLength));
- if(noWallsBetween(path.get(path.size()-1),temp)){
- handlePathPoint(fingerX,fingerY);
- if(!pointsEqual(path.get(path.size()-1),temp)){
- addAllBetween(path.get(path.size()-1),temp);
- Log.e("Path","Adding ("+temp.x+","+temp.y+")");
- path.add(temp);
- if(temp.x == endX && temp.y == endY){
- gameWon();
- }
- }
- }
- }
- else{
- Point temp = new Point((int)(fingerX/horizWallLength),(int)(fingerY/vertWallLength));
- if(temp.x == startX && temp.y == startY){
- handlePathPoint(fingerX,fingerY);
- path.add(temp);
- fingerOn = true;
- Log.e("Path","Starting path at ("+temp.x+","+temp.y+")");
- }
- }
- }
- return true;
- }
- private boolean noWallsBetween(Point a, Point b){
- if(a.x!=b.x && a.y!=b.y){
- return false;
- }
- //return false in this special case because a = b, so no need to add more points to path
- /* I needed this for something with the fancy path
- else if(a.x == b.x && a.y == b.y){
- return false;
- }*/
- else if(a.x == b.x){
- int min = Math.min(a.y,b.y);
- int max = Math.max(a.y,b.y);
- for(int i = min;i<max;i++){
- if(maze.hasSouthWall(i,a.x)){
- Log.e("Wall between","Failed: South wall at ("+a.x+","+i+")");
- return false;
- }
- }
- return true;
- }
- //a.y == b.y
- else{
- int min = Math.min(a.x,b.x);
- int max = Math.max(a.x,b.x);
- for(int i = min;i<max;i++){
- if(maze.hasEastWall(a.y,i)){
- Log.e("Wall between","Failed: East wall at ("+i+","+a.y+")");
- return false;
- }
- }
- return true;
- }
- }
- /**
- * Precondition: assumes in line, no walls between a and b
- * @param a
- * @param b
- */
- private void addAllBetween(Point a, Point b){
- //starts at a+1 because a is already in path
- //stops right before b, because b will get added after
- if(a.x == b.x){
- if(a.y>b.y){
- for(int i = a.y-1;i>b.y;i--){
- path.add(new Point(a.x,i));
- }
- }
- else{
- for(int i = a.y+1;i<b.y;i++){
- path.add(new Point(a.x,i));
- }
- }
- }
- //a.y == b.y
- else{
- if(a.y!=b.y){
- Log.e("AddAllBetween","Sanity check error, method was called when points were not in line");
- return;
- }
- if(a.x>b.x){
- for(int i = a.x-1;i>b.x;i--){
- path.add(new Point(i,a.y));
- }
- }
- else{
- for(int i = a.x+1;i<b.x;i++){
- path.add(new Point(i,a.y));
- }
- }
- }
- }
- /**
- * Tells the user that they have successfully completed the game,
- * offers them multiple options for what to do next
- */
- private void gameWon(){
- Log.e("Game","You won!");
- AlertDialog.Builder dialog = new AlertDialog.Builder(this);
- dialog.setCancelable(false);
- dialog.setPositiveButton("Try a new maze", new DialogInterface.OnClickListener()
- {
- public void onClick(DialogInterface dialog, int id)
- {
- //restart
- resetMaze();
- dialog.dismiss();
- }
- });
- dialog.setNegativeButton("Quit", new DialogInterface.OnClickListener()
- {
- public void onClick(DialogInterface dialog, int id)
- {
- finish();//quit
- }
- });
- String s = "Congratulations! You solved the maze!\n";
- if(minLength >= path.size()-1){//maybe an oboe?.. who knows
- //if(minLength == 0){for testing
- s+="You made it from start to finish with the shortest path possible!";
- dialog.setMessage(s+"\nDo you want to quit or play a new maze?");
- dialog.show();
- }
- else{
- s+="However, there was a shorter path from start to end that was ";
- if(path.size()-minLength-1 ==1){
- s+= "1 space shorter.";
- }
- else{
- s+=(path.size()-minLength-1)+" spaces shorter.";
- }
- dialog.setCancelable(true);
- dialog.setNeutralButton("Retry", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id)
- {
- fingerOn = false;
- }
- });
- dialog.setMessage(s+"\nDo you want to play again, quit, or play a new maze?");
- dialog.show();
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement