Reputation: 1
I have a project that I am writing where I have a maze that is randomly created with one button and and I can solve the maze with another button. The issue I am having is that I currently have the solution path drawn all at once in the presenter and then the solve method in the presenter is called in the DrawingView and is activated through a button on the MainActivity. I want each rect that I am drawing in the presenter (render) method to draw with timed pauses in between them. This is my first time using the MVP design and I have done a bunch of research on this and I am just struggling a lot to run methods that don't have the canvas passed to them.
As a warning I did get rid of the imports of the classes to try to cut down a bit.
class DrawingView extends View implements DrawingContract.DrawingCanvas {
private final DrawingContract.DrawingPresenter drawingPresenter;
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
drawingPresenter = new Presenter(this);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawingPresenter.render(canvas);
}
public void generateNewMaze() {
drawingPresenter.createMaze();
postInvalidate();
}
public void solveAndPrintMazePath() {
drawingPresenter.solveMaze();
postInvalidate();
}
}
public class Presenter implements DrawingContract.DrawingPresenter{
DrawingContract.DrawingCanvas view;
//boolean for the maze path to be drawn
private boolean mazeIsSolved;
//2d array for maze and start/exit cells
private Cell[][] cells;
private Cell start, exit;
//Static variables for columns, rows and thickness of cell walls
private static final int COLS = 10, ROWS = 10;
private static final float WALL_THICKNESS = 4;
//Cell sizes and screen margins
private float cellSize, hMargin, vMargin;
//Paints
private Paint wallPaint, startPaint, exitPaint, cellPaint;
//Random for the maze generation
private Random random;
//Graph
private Graph mazeGraph;
//Depth first object to solve the maze
private DepthFirst myDFS;
public Presenter(DrawingContract.DrawingCanvas v) {
//Set the view
view = v;
//Set boolean to false so we don't draw solve path
mazeIsSolved = false;
//Create a new graph
mazeGraph = new Graph();
//Creating a paint for the walls
wallPaint = new Paint();
wallPaint.setColor(Color.WHITE);
wallPaint.setStrokeWidth(WALL_THICKNESS);
//Creating the paint for the start of the maze
startPaint = new Paint();
startPaint.setColor(Color.GREEN);
//Creating the paint for the exit of the maze
exitPaint = new Paint();
exitPaint.setColor(Color.BLUE);
//Creating the cell paint
cellPaint = new Paint();
cellPaint.setColor(Color.BLACK);
//Random for maze generation
random = new Random();
//Creating the DFS
myDFS = new DepthFirst();
//Creating an initial maze
createMaze();
}
@Override
public void render(Canvas canvas) {
canvas.drawColor(Color.BLACK);
int width = canvas.getWidth();
int height = canvas.getHeight();
if(width/height < COLS/ROWS)
cellSize = width/(COLS + 1);
else
cellSize = height/(ROWS + 1);
hMargin = (width - COLS * cellSize)/2;
vMargin = (height - ROWS * cellSize)/2;
canvas.translate(hMargin, vMargin - 300);
for(int x = 0; x < COLS; x++) {
for(int y = 0; y < ROWS; y++) {
if(cells[x][y].getTopWall()) {
canvas.drawLine(
x * cellSize,
y * cellSize,
(x + 1) * cellSize,
y * cellSize,
wallPaint);
}
if(cells[x][y].getRightWall()) {
canvas.drawLine(
(x + 1) * cellSize,
y * cellSize,
(x + 1) * cellSize,
(y + 1) * cellSize,
wallPaint);
}
if(cells[x][y].getBottomWall()) {
canvas.drawLine(
x * cellSize,
(y + 1) * cellSize,
(x + 1) * cellSize,
(y + 1) * cellSize,
wallPaint);
}
if(cells[x][y].getLeftWall()) {
canvas.drawLine(
x * cellSize,
y * cellSize,
x * cellSize,
(y + 1) * cellSize,
wallPaint);
}
}
}
canvas.drawRect(
start.col*cellSize,
start.row*cellSize,
(start.col + 1)*cellSize,
(start.row + 1)*cellSize,
startPaint);
canvas.drawRect(
exit.col*cellSize,
exit.row*cellSize,
(exit.col + 1)*cellSize,
(exit.row + 1)*cellSize,
exitPaint);
if(mazeIsSolved) {
cellPaint.setColor(Color.WHITE);
ArrayList<Cell> myList = solveMaze();
for (int i = 1; i < myList.size(); i++) {
canvas.drawRect(myList.get(i).col * cellSize + 20,
myList.get(i).row * cellSize + 20,
(myList.get(i).col + 1) * cellSize - 20,
(myList.get(i).row + 1) * cellSize - 20,
cellPaint);
}
}
else {
cellPaint.setColor(Color.BLACK);
for(int x = 0; x < COLS; x++) {
for(int y = 0; y < ROWS; y++) {
canvas.drawRect(cells[x][y].col * cellSize + 20,
cells[x][y].row * cellSize + 20,
(cells[x][y].col + 1) * cellSize - 20,
(cells[x][y].row + 1) * cellSize - 20,
cellPaint);
if(x == 0 && y == 0) {
canvas.drawRect(
start.col*cellSize,
start.row*cellSize,
(start.col + 1)*cellSize,
(start.row + 1)*cellSize,
startPaint);
}
if(x == (COLS - 1) && y == (ROWS - 1)) {
canvas.drawRect(
exit.col*cellSize,
exit.row*cellSize,
(exit.col + 1)*cellSize,
(exit.row + 1)*cellSize,
exitPaint);
}
}
}
}
}
public void createMaze() {
Stack<Cell> stack = new Stack<>();
mazeGraph = new Graph();
mazeIsSolved = false;
Cell current, next;
cells = new Cell[COLS][ROWS];
for (int x = 0; x < COLS; x++) {
for (int y = 0; y < ROWS; y++) {
cells[x][y] = new Cell(x, y);
}
}
start = cells[0][0];
exit = cells[COLS - 1][ROWS - 1];
exit.setExitStatus(true);
current = cells[0][0];
current.setVisited(true);
do {
next = getNeighbour(current);
if (next != null) {
removeWall(current, next);
stack.push(current);
mazeGraph.addEdge(current, next);
current = next;
current.setVisited(true);
} else
current = stack.pop();
}while(!stack.empty());
}
public Cell getNeighbour(Cell cell) {
ArrayList<Cell> neighbours = new ArrayList<>();
//left neighbour
if(cell.col > 0) {
if (!cells[cell.col - 1][cell.row].getVisited()) {
neighbours.add(cells[cell.col - 1][cell.row]);
}
}
//right neighbour
if(cell.col < COLS - 1) {
if (!cells[cell.col + 1][cell.row].getVisited()) {
neighbours.add(cells[cell.col + 1][cell.row]);
}
}
//top neighbour
if(cell.row > 0) {
if (!cells[cell.col][cell.row - 1].getVisited()) {
neighbours.add(cells[cell.col][cell.row - 1]);
}
}
//bottom neighbour
if(cell.row < ROWS - 1) {
if (!cells[cell.col][cell.row + 1].getVisited()) {
neighbours.add(cells[cell.col][cell.row + 1]);
}
}
if(neighbours.size() > 0) {
int index = random.nextInt(neighbours.size());
return neighbours.get(index);
}
return null;
}
public void removeWall(Cell current, Cell next) {
if(current.col == next.col && current.row == next.row + 1) {
current.setTopWall(false);
next.setBottomWall(false);
}
if(current.col == next.col && current.row == next.row - 1) {
current.setBottomWall(false);
next.setTopWall(false);
}
if(current.col == next.col + 1 && current.row == next.row) {
current.setLeftWall(false);
next.setRightWall(false);
}
if(current.col == next.col - 1 && current.row == next.row) {
current.setRightWall(false);
next.setLeftWall(false);
}
}
public ArrayList<Cell> solveMaze() {
mazeIsSolved = true;
myDFS = new DepthFirst();
return myDFS.TraverseGraph(mazeGraph, start);
}
}
public interface DrawingContract {
interface DrawingCanvas {
}
interface DrawingPresenter {
void render(Canvas canvas);
void createMaze();
Cell getNeighbour(Cell cell);
void removeWall(Cell current, Cell next);
ArrayList<Cell> solveMaze();
}
}
public class MainActivity extends AppCompatActivity {
private DrawingView drawView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
drawView = (DrawingView) findViewById(R.id.drawView);
Button newMaze = (Button) findViewById(R.id.newMazeButton);
Button solveMaze = (Button) findViewById(R.id.solveMazeButton);
newMaze.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
drawView.generateNewMaze();
}
});
solveMaze.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {drawView.solveAndPrintMazePath();}
});
}
}
I have tried to add thread pauses, timers, and some other things but I don't understand how to implement it with the DrawingView being decouples from the presenter and the model. This whole MVP design is a bit confusing to me and I'm trying my best to understand it and use the correct design structure but I think I am doing some things wrong. I also know that this code isn't very optimal with me drawing colored squares to artificially clear the maze or that I have a boolean in the render for the solving of the maze but I don't know what else to do as of now.
Thank you so much for taking a look and leaving any comments below it means a lot to me. I will continue to do research and try new things as this question is active and if I make any progress I will leave updates.
Upvotes: 0
Views: 61