0% found this document useful (0 votes)
38 views47 pages

Pathfinder Project

The document discusses a pathfinding visualizer project. It describes the hardware and software requirements to run the project. It also explains the A* pathfinding algorithm and breadth-first search algorithm used in the project. The project allows users to visually see how these algorithms find paths in mazes.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
38 views47 pages

Pathfinder Project

The document discusses a pathfinding visualizer project. It describes the hardware and software requirements to run the project. It also explains the A* pathfinding algorithm and breadth-first search algorithm used in the project. The project allows users to visually see how these algorithms find paths in mazes.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 47

PATHFINDING VISUALIZER

A PROJECT REPORT

Submitted by
ABHINAV PREMKUMAR

(2023179053)

SELVAKUMAR R
(2023179049)

submitted to the faculty of

DEPARTMENT OF INFORMATION
SCIENCE AND TECHNOLOGY

MASTER OF COMPUTER APPLICATIONS

DEPARTMENT OF INFORMATION SCIENCE AND


TECHNOLOGY

COLLEGE OF ENGINEERING,

GUINDY ANNA UNIVERSITY

CHENNAI 600025

JANUARY 2024
ABHINAV PREMKUMAR 2023179053 SELVAKUMAR R 2023179049
INDEX
CONTENT

1. PROJECT OVERVIEW.

1.1 INTRODUCTION

1.2 ABSTRACT

2. SYSTEM REQUIREMENTS.

2.1 HARDWARE REQUIREMENTS

2.2 SOFTWARE REQUIREMENTS

3. ALGORITHMS USED.

3.1 PATHFINDER

3.2 A* PATHFINDING ALGORITHM

3.3 BREADTH FIRST SEARCH

4. SOFTWARE DESCRIPTION.

4.1 FRONT END

4.2 BACK END

5. PROJECT DESCRIPTION.

5.1 INTRODUCTION

ABHINAV PREMKUMAR 2023179053 SELVAKUMAR R 2023179049


6. ARCHITECTURE DIAGRAM.

6.1 A* ALGORITHM

6.2 BREADTH FIRST SEARCH ALGORITHM

7. CONCLUSION.

8. APPENDIX.

8.1 SAMPLE CODING

8.2 SCREENSHOTS

ABHINAV PREMKUMAR 2023179053 SELVAKUMAR R 2023179049


1. PROJECT OVERVIEW

1.1 INTRODUCTION

The A* Pathfinding Visualizer represents a sophisticated desktop graphical user interface (GUI)
application meticulously crafted in Java, utilizing the Swing framework as its foundational GUI
tool. This application encapsulates a suite of features designed to provide users with a
comprehensive exploration of pathfinding algorithms within a visually dynamic environment.

At the forefront of its capabilities is a responsive and dynamic GUI, affording users the
flexibility to interact seamlessly with the application. The visualizer empowers users to create
intricate 2D mazes by placing walls with precision, defining pivotal start and end nodes that
serve as the locus for pathfinding endeavors.

Central to the application's functionality are two prominent pathfinding algorithms: the A*
Pathfinding Algorithm and the Breadth-First Search algorithm. These algorithms, renowned for
their efficacy in determining optimal routes, form the computational backbone of the visualizer.
The application seamlessly computes the shortest path from the designated start to end nodes,
providing users with a nuanced understanding of algorithmic decision-making.

A distinctive feature of the A* Pathfinding Visualizer lies in its real-time visualization of the
computational process. As users manipulate the maze and nodes, the application dynamically
illustrates the algorithmic journey, revealing step-by-step insights into the decision-making
mechanisms employed to navigate the maze optimally.

In essence, the A* Pathfinding Visualizer serves as an advanced educational tool, inviting users
to engage with the intricacies of pathfinding algorithms within a formal Java-based
environment. The integration of the Swing framework, coupled with the precise implementation
of algorithms, positions this application as a valuable resource for those seeking a formal and in-
depth exploration of the A* Pathfinding Algorithm and Breadth-First Search in a visual manner.

ABHINAV PREMKUMAR 2023179053 SELVAKUMAR R 2023179049


1.2 ABSTRACT

The A* Pathfinding Visualizer is a meticulously engineered desktop GUI application developed


in Java, featuring the Swing framework as the principal GUI architecture. This application
serves as a sophisticated platform for users to engage in a comprehensive exploration of
pathfinding algorithms. Noteworthy features include a responsive and dynamic GUI that enables
users to craft intricate 2D mazes by strategically placing walls, and defining distinct start and
end nodes.
The computational core of the visualizer is driven by two prominent pathfinding algorithms—
the A* Pathfinding Algorithm and Breadth-First Search. Through these algorithms, the
application adeptly computes the shortest path from user-defined start to end nodes. A
distinctive attribute of the visualizer is its real-time visualization capability, dynamically
illustrating the step-by-step computational process as users manipulate the maze and nodes. In
its entirety, the A* Pathfinding Visualizer stands as an advanced educational tool, providing
users with a formal and insightful exploration of pathfinding algorithms within the confines of a
Java-based environment, showcasing the synthesis of precision algorithmic implementation and
the versatility of the Swing framework.

ABHINAV PREMKUMAR 2023179053 SELVAKUMAR R 2023179049


2. SYSTEM REQUIREMENT

System description are the configuration that a system must have in order for a
hardware or software application to run smoothly and effectively. Failure to meet these
requirements can result in performance problems.

2.1 HARDWARE REQUIREMENT (MINIMUM REQUIREMENT)

• x86_64 CPU architecture; 5th generation Intel Core or newer, or AMD


CPU with support for a Windows Hypervisor.

• 4 GB RAM or more.

• GB of available disk space minimum

• 1280 x 800 minimum screen resolution.

2.2 SOFTWARE REQUIREMENT (MINIMUM REQUIREMENT)

2.2.1 A computer running a 64-bit version of Windows (7,8, 10, or 11), Linux,
mac-OS (10.14 Mojave or later), or Chrome-OS.

2.2.2 Eclipse – Swing setup | 2020.3. 1

➢ Front-End: Java Swing


➢ Back-End: Java

ABHINAV PREMKUMAR 2023179053 SELVAKUMAR R 2023179049


ALGORITHMS USED

3.1. PATHFINDING

Pathfinding typically involves determining the most efficient route or path from
a starting node to an end node. The problem may also include additional constraints, such as
avoiding certain nodes or minimizing the total cost.
Common Pathfinding Algorithms:
A* Algorithm:
An informed search algorithm that uses heuristics to guide the search.
Balances the cost of reaching a node and the estimated cost from that node to the goal.
Breadth-First Search (BFS):
Systematically explores all nodes at the current depth before moving on to the next level.
Guarantees the shortest path for unweighted graphs.
Applications:
Robotics:
Pathfinding is crucial in robotics for planning the movement of robots to navigate through
environments, avoid obstacles, and reach destinations.
Video Games:
Pathfinding is extensively used in game development to enable non-player characters (NPCs) or
entities to navigate game environments intelligently.
Network Routing:
In computer networks, pathfinding algorithms are employed to determine optimal routes for data
packets to traverse the network efficiently.

ABHINAV PREMKUMAR 2023179053 SELVAKUMAR R 2023179049


3.2. A* ALGORITHM

The A* (A-star) algorithm is a widely used and efficient pathfinding algorithm in


computer science and artificial intelligence. It is particularly effective in finding the
shortest path from a start node to a goal node in a graph, taking into account both the
actual cost to reach the node and a heuristic estimate of the cost to reach the goal from
that node. ALGORITHM IS :

function AStar(graph, start, goal, heuristic):


openSet = PriorityQueue()
openSet.add(start)
cameFrom = empty map
gScore = map with infinity values for all nodes
gScore[start] = 0

while openSet is not empty:


current = node with the lowest fScore in openSet

if current equals goal:


return reconstructPath(cameFrom, start, goal)

openSet.remove(current)

for each neighbor of current:


tentativeGScore = gScore[current] + cost(current, neighbor)
if tentativeGScore < gScore[neighbor]:
gScore[neighbor] = tentativeGScore
fScore = tentativeGScore + heuristic(neighbor, goal)
if neighbor not in openSet:
openSet.add(neighbor)
cameFrom[neighbor] = current

return null // No path found

function reconstructPath(cameFrom, start, goal):


path = [goal]
current = goal
while current is in cameFrom:
current = cameFrom[current]
path.prepend(current)
return path

ABHINAV PREMKUMAR 2023179053 SELVAKUMAR R 2023179049


3.3. BREADTH FIRST SEARCH

Breadth-First Search is a fundamental graph traversal algorithm that systematically


explores all the nodes at the current depth before on to nodes at the next depth. It
operates in a breadthward motion, exploring the graph level by level.
ALGORITHM:
1. Start at the initial node and enqueue it in the queue.
2. Dequeue a node from the queue and visit it.
3.Enqueue all unvisited neighbors of the current node.
4. Repeat steps 2-3 until the queue is empty.
function BreadthFirstSearch(graph, start, goal):
queue = Queue()
queue.enqueue(start)
visited = set()
cameFrom = empty map
while queue is not empty:
current = queue.dequeue()
if current equals goal:
return reconstructPath(cameFrom, start, goal)
visited.add(current)
for each neighbor of current:
if neighbor not in visited:
queue.enqueue(neighbor)
visited.add(neighbor)
cameFrom[neighbor] = current
return null // No path found
function reconstructPath(cameFrom, start, goal):
path = [goal]
current = goal
while current is in cameFrom:
current = cameFrom[current]
path.prepend(current) return path

ABHINAV PREMKUMAR 2023179053 SELVAKUMAR R 2023179049


2.2.3 SOFTWARE DESCRIPTION

1.1 FRONT-END

Swing is a Java Foundation Classes [JFC] library and an extension of the


Abstract Window Toolkit [AWT]. Java Swing offers much-improved functionality over
AWT, new components, expanded components features, and excellent event handling with
drag- and-drop support.
Introduction of Java Swing

JAVA SWING:

Swing has about four times the number of User Interface [UI] components as
AWT and is part of the standard Java distribution. By today's application GUI requirements,
AWT is a limited implementation, not quite capable of providing the components required for
developing complex GUls required in modern commercial applications. The AWT
component set has quite a few bugs and does take up a lot of system resources when
compared to equivalent Swing resources. Netscape introduced its Internet Foundation Classes
[IFC] library for use with Java. Its Classes became very popular with programmers creating
GUI's for commercial applications.

. Swing is a Set of API (API- Set of Classes and Interfaces)


. Swing is Provided to Design Graphical User Interfaces
. Swing is an Extension library to the AWT (Abstract Window Toolkit) 5:00 –
5:30 pm
. Includes New and improved Components that have been enhancing the looks
and Functionality of GUIs'
. Swing can be used to build (Develop) The Standalone swing GUI Apps as
Servlets and Applets
· It Employs model/view design architecture.
. Swing is more portable and more flexible than AWT, the Swing is built on top
of the AWT.
· Swing is Entirely written in Java.

ABHINAV PREMKUMAR 2023179053 SELVA KUMAR 2023179049


. Java Swing Components are Platform-independent, and The Swing Components
are lightweight.
. Swing Supports a Pluggable look and feel and Swing provides more powerful
components.
. such as tables, lists, Scrollpanes, Colourchooser, tabbed pane, etc.
. Further Swing Follows MVC.

4.2. BACK-END

JAVA:

Java is an object-oriented, class-based programming language. The language is


designed to have as few dependencies implementations as possible. The intention of using
this language is to give relief to the developers from writing codes for every platform. The
term WORA, write once and run everywhere is often associated with this language. It means
whenever we compile a Java code, we get the byte code (.class file), and that can be executed
(without compiling it again) on different platforms provided they support Java. In the year
1995, Java language was developed. It is mainly used to develop web, desktop, and mobile
devices. The Java language is known for its robustness, security, and simplicity features. That
is designed to have as few implementation dependencies as possible.

HISTORY:

The Java language has a very interesting history. Patrick Naughton, Mike Sheridan,
and Jame Gosling, known as the Green team, started the development of Java in the year
1991. These people were the engineers at Sun Microsystems. In 1996, the first public
implementation was released as Java 1.0. The compiler of Java 1.0 was rewritten by Arthur
Van Hoff to comply strictly with its specification. With the introduction of Java 2, the new
versions have multiple different configurations that have been built for the various platforms.
It is worth noting that James Gosling is also known as the father of Java.
The ISO standard body was approached by Sun Microsystems in the year 1997 to formalize
Java, but the process was withdrawn soon. At one point in time, Sun Microsystems provided
most of its implementation of Java available without any cost, despite having the status of
proprietary software.

APPLICATIONS PROGRAMS:

The Implementation of an application program in Java application includes the following


steps.

1. The program creation (writing the code)


2. The program compilation.
3. Executing the compiled code.

It is worth noting here that JDK (Java Development Kit) should be installed properly on the
system, and the path should also be set.
5.PROJECT DESCRIPTION

5.1 INTRODUCTION.
The Pathfinding Visualizer project is a Java-based application designed
to evaluate the performance of algorithms. The application provides a platform
for users to assess the performance of A* algorithm and breadth first search
algorithm.

The Pathfinding Visualizer is a desktop GUI application written in Java using


Swing as the main GUI framework. This application features the following:

1. Dynamic GUI.
2. Drawing 2D "maze" by placing walls, as well as a start and end node.
3. Computing the shortest path from start to end node, using
 A* Pathfinding Algorithm
 Breadth First Search
4.Visualizing the computational process of the shortest path.
ARCHITECTURE DIAGRAM

6.1 BFS ALGORITHM DIAGRAM

6.2 A* ALGORITHM DIAGRAM


6. CONCLUSION

The project has been successful in achieving its objectives, and the following
are the key outcomes:

 A user-friendly GUI application has been developed, allowing users


to find which algorithm has better perfomance.
 The speed calculation formula has been implemented, and the results
are displayed on the GUI.
 The user experience has been enhanced by providing an interactive
learning experience.

This project has provided valuable learning opportunities for those involved,
Including:

 Gaining knowledge in Java programming and GUI development


using the Swing API.
 Understanding breadth first search and a* algorithm.
 Developing problem solving and critical thinking skill through the
project’s implementation.

In conclusion, the path finding visualiser project in Java using the Swing API
has successfully created a use friendly and interactive platform for analyzing
algorithms . The project has provided valuable learning opportunities and has
demonstrated the potential of java and the Swing API in developing efficient
and interactive software solutions.
9. APPENDIX
8.1 SAMPLING CODING:
JAVA CODE:

App.java
public class App {
public static void main(String[] args) throws Exception {

// Launch GUI window


GUI window = new GUI();
}
}

Board.java
/**
* Enum representing different cell types
*/
enum Cell {
FREE(0),
START(1),
WALL(2),
END(3);

private final int value;


private Cell(int value) {
this.value = value;
}

public int getValue() {


return value;
}

public static Cell getEnum(int value) {


for (Cell c : Cell.values()) {
if(value == c.getValue()) {
return c;
}
}
return Cell.WALL;
}
}

/**
* A class representing a board/grid consisting of Cells.
*/
public class Board {
private Cell[][] board;
private int xSize;
private int ySize;

private int[] start;


private boolean startset = false;

private int[] end;


private boolean endset = false;

public Board(int xSize, int ySize) {


this.xSize = xSize;
this.ySize = ySize;
this.board = new Cell[ySize][xSize];
clearBoard();
}

/**
* Fills the board with free cells and notes start and end nodes as not set.
*/
public void clearBoard() {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
board[i][j] = Cell.FREE;
}
}
startset = false;
endset = false;
}

/**
* Places a specific tile type at a point on the board.
* @param tileType - Type of tile/cell to place.
* @param xPos - x-position on the board to place tile.
* @param yPos - y-position on the board to place tile.
*/
public void setTile(Cell tileType, int xPos, int yPos) {
// If tile being set is START or END tile, update information
automatically, and reset already placed start and end tiles
if (tileType == Cell.START) {
if (startset) {
setTile(Cell.FREE, start[0], start[1]); // remove already placed
start cell
}
start = new int[]{xPos, yPos}; // place current startcell
startset = true;
} else if (tileType == Cell.END) {
if (endset) {
setTile(Cell.FREE, end[0], end[1]); // remove already placed end
cell
}
end = new int[]{xPos, yPos}; // place current endcell
endset = true;
} else {
// check if tile that is being overwritten is a start or end tile
if (getTile(xPos, yPos) == Cell.START) {
startset = false;
} else if (getTile(xPos, yPos) == Cell.END) {
endset = false;
}
}

board[yPos][xPos] = tileType; // place cell/tile to actual board


}

/**
* Gets type of tile/cell at specific position.
* @param xPos
* @param yPos
* @return
*/
public Cell getTile(int xPos, int yPos) {
return board[yPos][xPos];
}

/**
* Returns the board.
* @return
*/
public Cell[][] getBoard() {
return board;
}

/**
* Returns the x-Size of the board.
* @return
*/
public int getXSize() {
return xSize;
}

/**
* Returns the y-Size of the board.
* @return
*/
public int getYSize() {
return ySize;
}
/**
* Returns whether the start node has been set.
* @return
*/
public boolean isStartSet() {
return startset;
}

/**
* Returns whether the end node has been set.
* @return
*/
public boolean isEndSet() {
return endset;
}

/**
* Returns the coordinates of the start node.
* @return
*/
public int[] getStart() {
return start;
}

/**
* Returns the coordinates of the end node.
* @return
*/
public int[] getEnd() {
return end;
}

/**
* Computes coordinates of the cells adjacent straight to cell with
specified x and y coordinates.
* @param xPos
* @param yPos
* @return
*/
private int[][] getAdjacent(int xPos, int yPos) {

int[][] adj = new int[4][2];


adj[0] = new int[] {xPos - 1, yPos};
adj[1] = new int[] {xPos + 1, yPos};
adj[2] = new int[] {xPos, yPos - 1};
adj[3] = new int[] {xPos, yPos + 1};

return adj;
}
/**
* Computes coordinates of the cells adjacent diagonally to cell with
specified x and y coordinates.
* @param xPos
* @param yPos
* @return
*/
private int[][] getAdjacent_Diagonal(int xPos, int yPos) {

int[][] adj = new int[4][2];

adj[0] = new int[] {xPos - 1, yPos - 1};


adj[1] = new int[] {xPos - 1, yPos + 1};
adj[2] = new int[] {xPos + 1, yPos - 1};
adj[3] = new int[] {xPos + 1, yPos + 1};

return adj;
}

/**
* Parses the board and computes weighted bidirectional graph.
* @return - weighted bidirectional graph in adjacency matrix
representation.
*/
public int[][][][] getGraph(boolean diagonals) {

/**
* Edges are stored in adjacency matrix representation on the form:
* new int[xSize][ySize][4][3]
* ^ xCoordinate, yCoordinate and weight of
edge
* ^ number of adjacent nodes (8 if with
diagonals, 4 if without)
* ^ yCoordinate of edge target node
* ^ xCoordinate of edge target node
*/

// Create adjacency matrix


int[][][][] adj = new int[xSize][ySize][diagonals ? 8 : 4][3];

// Iterate for each cell


for (int y = 0; y < ySize; y++) {
for (int x = 0; x < xSize; x++) {

// Get a reference to the list of outgoing edges from this node


int[][] edges = adj[x][y];

// Fetch if current cell is wall


boolean isWall = getTile(x, y) == Cell.WALL;
// Grab adjacent nodes
int[][] adjacent = getAdjacent(x, y);

// Iterate for each adjacent node


for (int i = 0; i < adjacent.length; i++) {
// Save coordinates of adjacent cell
int ax = adjacent[i][0];
int ay = adjacent[i][1];

// Put no connection in as default.


edges[i] = new int[] {ax, ay, 0};

// If current cell isnt wall and adjacent cell isnt wall,


and in boundaries
if (!isWall && (0 <= ax && ax < xSize) && (0 <= ay && ay <
ySize) && !(getTile(ax, ay) == Cell.WALL)) {
// Put in edge with weight 1
edges[i] = new int[] {ax, ay, 1};
}
}

// If diagonals are enabled do same as for regular, but also


with diagonals
if (diagonals) {
int[][] adjacentDiagonals = getAdjacent_Diagonal(x, y);

// Iterate for each adjacent node


for (int i = 0; i < adjacentDiagonals.length; i++) {
// Save coordinates of adjacent cell
int ax = adjacentDiagonals[i][0];
int ay = adjacentDiagonals[i][1];

// Put no connection in as default.


edges[i+4] = new int[] {ax, ay, 0};

// If current cell isnt wall and adjacent cell isnt


wall, and in boundaries
if (!isWall && (0 <= ax && ax < xSize) && (0 <= ay && ay
< ySize) && !(getTile(ax, ay) == Cell.WALL)) {
// Put in diagonal edge
edges[i+4] = new int[] {ax, ay, 1}; // Diagonal
edges have weight 1, but possible to specify otherwise.
}
}
}
}
}

// Return adjacency matrix.


return adj;
}
}

GraphicsCanvas.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.image.*;
import javax.swing.plaf.DimensionUIResource;

import java.util.LinkedList;
import java.util.ArrayList;

enum Mode {
FREEPLACE(0),
STARTPLACE(1),
WALLPLACE(2),
ENDPLACE(3);

private final int value;


private Mode(int value) {
this.value = value;
}

public int getValue() {


return value;
}
}

enum ComputationalMethod {
ASTAR("A*"),
BFS("Breadth First Search");

private final String value;


private ComputationalMethod(String value) {
this.value = value;
}

public String getValue() {


return value;
}

public static ComputationalMethod getEnum(String value) {


for (ComputationalMethod c : ComputationalMethod.values()) {
if (value.equals(c.getValue())) {
return c;
}
}
return ComputationalMethod.ASTAR;
}

/**
* A Graphics Canvas, used as the main viewport in the application.
*/
public class GraphicsCanvas extends Canvas {

// Decleare buffer and buffergraphics


private BufferedImage buffer;
private Graphics bufferGraphics;

// Define initial cell size


private int cellDimension = 8; //px

// Define size of board


int cellCountX = 60;
int cellCountY = 60;

// Width and Height of board in world size


int width = cellCountX * cellDimension;
int height = cellCountY * cellDimension;

// Define zoom and pan used for viewport/canvas


private double zoom = 1;
private double panX = 0;
private double panY = 0;
private double startPanX = 0;
private double startPanY = 0;

// Declare private field containing board information


private Board board;

// Define initial mode


private Mode mode = Mode.FREEPLACE;
private ComputationalMethod computationalMethod = ComputationalMethod.ASTAR;

// Stream for collecting calculation results


private LinkedList<ArrayList<ArrayList<int[]>>> computationList = new
LinkedList<ArrayList<ArrayList<int[]>>>();
// ^^ The arraylists holds arraylists for each of the type
of cells

// Current computationResult and shortest path


private ArrayList<ArrayList<int[]>> currentComputation =
computationList.pollFirst();
private ArrayList<int[]> currentPath;

private boolean showVizualization = true;


private boolean enableDiagonals = false;
private boolean finishedVisualizing = true;

// Timer for drawing steps


private Timer vizualizationTimer = new Timer(100, null);

// Declare references to other UI components


private JCheckBox showVizualizationCheckbox;
private JCheckBox enableDiagonalsCB;
private JSlider vizualizationSpeedSlider;
private JComboBox algorithmComboBox;

private JLabel startPointLabel;


private JLabel endPointLabel;
private JLabel shortestPathLabel;
private JLabel computationalTimeLabel;

private JTextArea outputLog;

/**
* Constructor for GraphicsCanvas class. UI references to certain components
are required.
* @param showVizualizationCheckbox
* @param enableDiagonalsCB
* @param vizualizationSpeedSlider
* @param algorithmComboBox
* @param startPointLabel
* @param endPointLabel
* @param shortestPathLabel
* @param computationalTimeLabel
* @param outputLog
*/
public GraphicsCanvas(JCheckBox showVizualizationCheckbox, JCheckBox
enableDiagonalsCB, JSlider vizualizationSpeedSlider, JComboBox
algorithmComboBox, JLabel startPointLabel, JLabel endPointLabel, JLabel
shortestPathLabel, JLabel computationalTimeLabel, JTextArea outputLog) {
super();
//this.createBufferStrategy(2);

// Set background and preferred dimension


Dimension preferredDimension = new DimensionUIResource(width, height);
setBackground(Color.LIGHT_GRAY);
setPreferredSize(preferredDimension);
// Create a board to contain all user input cells
board = new Board(cellCountX, cellCountY);

// Call reset() to set initial zoom and pan depending on viewport size
resetViewport(width, height);

// Set a start and end tile


board.setTile(Cell.START, 10, 30);
board.setTile(Cell.END, 50, 30);

// Update start and end labels


startPointLabel.setText("(" + board.getStart()[0] + ", " +
board.getStart()[1] + ")");
endPointLabel.setText("(" + board.getEnd()[0] + ", " + board.getEnd()[1]
+ ")");

// Add a mouselistener to listen for different mouse inputs.


this.addMouseListener(makeMouseInputAdapter());
this.addMouseMotionListener(makeMouseMotionListener(this));
this.addMouseWheelListener(makeMouseWheelListener());

// Set references to ui objects


this.showVizualizationCheckbox = showVizualizationCheckbox;
this.enableDiagonalsCB = enableDiagonalsCB;
this.vizualizationSpeedSlider = vizualizationSpeedSlider;
this.algorithmComboBox = algorithmComboBox;
this.startPointLabel = startPointLabel;
this.endPointLabel = endPointLabel;
this.shortestPathLabel = shortestPathLabel;
this.computationalTimeLabel = computationalTimeLabel;
this.outputLog = outputLog;
}

/**
* Sets the mode for this graphicscanvas
* @param mode - Desired mode.
*/
public void setMode(Mode mode) {
this.mode = mode;
}

/**
* Resets the board and repaints canvas with current viewport dimensions.
*/
public void reset() {
reset(getWidth(), getHeight());
}

/**
* Resets the board and repaints canvas, using specified parameters for
width and height of viewport-
* @param viewportWidth
* @param viewportHeight
*/
public void reset(int viewportWidth, int viewportHeight) {
// Clear board
board.clearBoard();

// Update labels
startPointLabel.setText("NOT SET");
endPointLabel.setText("NOT SET");
shortestPathLabel.setText("N/A");
computationalTimeLabel.setText("N/A");

// Clear vizualization list and vizualization and stop timer


currentComputation = null;
currentPath = null;
computationList = new LinkedList<>();
vizualizationTimer.stop();

// Reset the viewport


resetViewport(viewportWidth, viewportHeight);
}

/**
* Resets the pan and zoom only, using specified viewport sizes.
* @param viewportWidth
* @param viewportHeight
*/
public void resetViewport(int viewportWidth, int viewportHeight) {
// Reset zoom
zoom = 1;

// Calculate and set new pans such that grid/board is in center of


viewport
panX = -(viewportWidth/zoom - width) / 2;
panY = -(viewportHeight/zoom - height) / 2;

// Repaint canvas
repaint();
}

/**
* Forces parsing of the board, and a run of the specified algorithm.
*/
public void run() {
// Parse graph
int[][][][] adj = board.getGraph(enableDiagonals);
// Empty calculation list for collecting results
computationList = new LinkedList<>();
currentPath = null;

// Reset shortest path and computational time labels


shortestPathLabel.setText("N/A");
computationalTimeLabel.setText("N/A");

// If Board has start and end set, run pathfinding algorithm.


if (board.isStartSet() && board.isEndSet()) {

// Get current time


long t = System.currentTimeMillis();

// Run pathfinding algorithm on separate thread


Thread thread = new Thread(new Runnable() {
@Override
public void run() {

// Get start and end nodes


int[] start = board.getStart();
int[] end = board.getEnd();

// Run different algorithms depending on user selected


computational method
if (computationalMethod == ComputationalMethod.ASTAR) {
// Run A*
int[][][] results = Algorithm.A_Star(adj, start,
end, computationList, showVizualization);
// Compute shortest path using results
currentPath = Algorithm.A_Star_path(results, start,
end);
} else if (computationalMethod ==
ComputationalMethod.BFS) {
// Run BFS
int[][][] results = Algorithm.BFS(adj, start, end,
computationList, showVizualization);
// Compute shortest path using results
currentPath = Algorithm.BFS_path(results, start,
end);
}
// Update shortest path label
shortestPathLabel.setText("" + currentPath.size());
// Get total computational time
long t2 = System.currentTimeMillis() - t;
// Update label
computationalTimeLabel.setText(t2 + " ms");
// Write log
writeLog("Computation finished in: " + t2 + "ms.
Shortest path: " + currentPath.size() + " blocks.\n");
// Repaint for good measure
repaint();
}
});

// Run thread
thread.start();

// Stop vizualizatiotimer
vizualizationTimer.stop();

if (showVizualization) {
// Not finished visualizing
finishedVisualizing = false;

// Run timer for forcing update of vizualization


vizualizationTimer = new Timer((int)
(1000000/Math.pow(vizualizationSpeedSlider.getValue(), 3)), new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e) {

// Maybe overkill, idk.


Runnable r = new Runnable() {
public void run() {
ArrayList<ArrayList<int[]>> computationInstance
= computationList.pollFirst();

if (computationInstance != null) {
finishedVisualizing = false;
currentComputation = computationInstance;
repaint();
} else {
finishedVisualizing = true;
repaint();
}
}
};
Thread t = new Thread(r);
t.start();
}
});
vizualizationTimer.start();
} else {
finishedVisualizing = true;
currentComputation = computationList.pollLast();
}
} else {
// Write error message to log
writeLog("ERROR: START and END nodes required.\n");
}

/**
* Update method used for creating and updating the double buffer, as well
as repainting the canvas using double-buffer.
* This method is called through regular update() calls by the ui, as well
as through paint(), to trigger proper repaint when calling repaint().
* @param g - The graphics object used to draw to the actual canvas
*/
public void update(Graphics g) {
// Update grid dimensions based on possible resize
//cellDimension = Math.min(this.getWidth()/board.getXSize(),
this.getHeight()/board.getYSize());

// Initialize buffer
if (buffer == null) {
buffer = new BufferedImage(this.getSize().width,
this.getSize().height, BufferedImage.TYPE_INT_RGB);
bufferGraphics = buffer.getGraphics();
}

// Clear screen in background


bufferGraphics.setColor(getBackground());
bufferGraphics.fillRect(0, 0, this.getSize().width,
this.getSize().height);

// Paint the necessarry content to the buffer


paintContent(bufferGraphics);

// Draw buffer to screen


g.drawImage(buffer, 0, 0, this);
}

/**
* Calls update which utilizes double-buffering.
*/
public void paint(Graphics g) {
update(g);
}

/**
* Paints all content using specified Graphics object.
* @param g - Graphics object used for painting all content.
*/
private void paintContent(Graphics g) {

// Paint the current computation


paintComputation(g);

// Paint the computed shortest path


paintPath(g);

// Paint the board


paintBoard(g);

// Paint the grid


paintGrid(g);

/**
* Draws the grid to the screen.
* @param g - Graphics object to draw grid with.
*/
private void paintGrid(Graphics g) {

// Calculate lengths and clean offsets


double[] sc = new double[]{cellDimension * board.getXSize() *
zoom,cellDimension * board.getYSize() * zoom};
double[] offsets = worldToScreen(0, 0);

// Set grid color to black


g.setColor(Color.GRAY);

// Draw grid
for (int x = 0; x < board.getXSize() + 1; x++) {
double p = x * cellDimension * zoom;
g.drawLine((int)(p + offsets[0]), (int)(0 + offsets[1]), (int)(p +
offsets[0]), (int)(sc[1] + offsets[1]));
}

for (int y = 0; y < board.getYSize() + 1; y++) {


double p = y * cellDimension * zoom;
g.drawLine((int)(0 + offsets[0]), (int)(p + offsets[1]), (int)(sc[0]
+ offsets[0]), (int)(p + offsets[1]));
}

/**
* Draws the saved board contents to the screen.
* @param g - Graphics object to draw board with.
*/
private void paintBoard(Graphics g) {

// Fetch board
Cell[][] board = this.board.getBoard();

// Iterate through each cell in board


for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {

// Fetch cell type, and calculate cell position


Cell c = board[i][j];
int xPos = j*cellDimension;
int yPos = i*cellDimension;

// Draw color depending on cell type


switch (c) {
case FREE:
break;
case START:
drawTile(g, Color.RED, xPos, yPos, cellDimension);
break;
case WALL:
drawTile(g, Color.BLACK, xPos, yPos, cellDimension);
break;
case END:
drawTile(g, Color.BLUE, xPos, yPos, cellDimension);
break;
default:
break;
}
}
}
}

/**
* Draws the computation instance to screen, if any is available
* @param g - Graphics object to draw computation instance with
*/
private void paintComputation(Graphics g) {

if (currentComputation != null) {

int s = currentComputation.size();
if (s > 0) {
ArrayList<int[]> graynodes = currentComputation.get(0);
for (int[] n : graynodes) {
drawTile(g, Color.GREEN, n[0]*cellDimension,
n[1]*cellDimension, cellDimension);
}

if (s > 1) {
ArrayList<int[]> blacknodes = currentComputation.get(1);
for (int[] n : blacknodes) {
drawTile(g, Color.YELLOW, n[0]*cellDimension,
n[1]*cellDimension, cellDimension);
}
}
}
}
}

/**
* Draws the last computed shortest path to the screen
* @param g - Graphics object to draw path with
*/
private void paintPath(Graphics g) {
if (currentPath != null && finishedVisualizing) {
for (int[] n : currentPath) {
drawTile(g, Color.CYAN, n[0]*cellDimension, n[1]*cellDimension,
cellDimension);
}
}
}

/**
* Paints draws a tile with specified coordinates, size and color, using
specified graphics object.
* @param g - Graphics object to draw tile with.
* @param c - Color to draw tile with.
* @param xPos - desired x-position of tile
* @param yPos - desired y-position of tile
* @param size - desired size (dimension) of tile.
*/
private void drawTile(Graphics g, Color c, int xPos, int yPos, int size) {
// Apply zoom before drawing
double[] pos = worldToScreen(xPos, yPos);
int scale = (int)Math.ceil(size*zoom);

// Draw tile
g.setColor(c);
g.fillRect((int) pos[0], (int) pos[1], scale, scale);
}

/**
* Converts a set of world coordinates to screen coordinates.
* @param x
* @param y
* @return
*/
private double[] worldToScreen(int x, int y) {
double newX = ((x - panX)*zoom);
double newY = ((y - panY)*zoom);
return new double[]{newX, newY};
}

/**
* Converts a set of screen coordinates to world coordinates.
* @param x
* @param y
* @return
*/
private double[] screenToWorld(int x, int y) {
double newX = (x/zoom + panX);
double newY = (y/zoom + panY);
return new double[]{newX, newY};
}

/**
* Writes specified text to outputLog. Automatically moves the caret
position down to bottom.
* @param text - text to write
*/
private void writeLog(String text) {
outputLog.append(text);
outputLog.setCaretPosition(outputLog.getDocument().getLength());
}

/**
* Places tile at specified x and y coordinates to board, using currently
active mode.
* If the placed tile is a start or end tile, updates the labels.
* @param xPos
* @param yPos
*/
private void placeTile(int xPos, int yPos) {
// If tile that is being placed on top of (effectively erased) is a
start or end tile, update the labels
if (board.getTile(xPos, yPos).equals(Cell.START)) {
startPointLabel.setText("NOT SET");
}

if (board.getTile(xPos, yPos).equals(Cell.END)) {
endPointLabel.setText("NOT SET");
}

// Set the tile on board using transformed coordinates


board.setTile(Cell.getEnum(mode.getValue()), xPos, yPos);

// If tile that was just set, is a start tile, update label


if (board.getTile(xPos, yPos).equals(Cell.START)) {
startPointLabel.setText("(" + xPos + ", " + yPos + ")");
}
// If tile that was just set, is an end tile, update label
if (board.getTile(xPos, yPos).equals(Cell.END)) {
endPointLabel.setText("(" + xPos + ", " + yPos + ")");
}
}

private MouseInputAdapter makeMouseInputAdapter() {


return new MouseInputAdapter() {
public void mousePressed(MouseEvent e) {

if (e.getButton() == 1) { // if left-click
// Transform pressed coordinates into proper tile
coordinates in board
double[] worldPos = screenToWorld(e.getX(), e.getY());
int xTile = (int) (worldPos[0] / cellDimension);
int yTile = (int) (worldPos[1] / cellDimension);

if ((xTile >= 0 && xTile < cellCountX) && (yTile >= 0 &&
yTile < cellCountY)) {
// Place tile
placeTile(xTile, yTile);

// Repaint the canvas


repaint();
}
} else if (e.getButton() == 3) { // if right-click
// Update startPans
startPanX = e.getX();
startPanY = e.getY();
}
}
};
}

private MouseWheelListener makeMouseWheelListener() {


return new MouseWheelListener() {
public void mouseWheelMoved(MouseWheelEvent e) {
// Capture mouse position in world space before zoom
double[] beforeZoomMPos = screenToWorld(e.getX(), e.getY());

// Calculate new zoom


double scroll = e.getWheelRotation();
zoom = zoom * (1 - 2*scroll/100.0);

// Capture mouse position in world space after zoom


double[] afterZoomMPos = screenToWorld(e.getX(), e.getY());

// Calculate new pan values


double nPanX = panX + (beforeZoomMPos[0] - afterZoomMPos[0]);
double nPanY = panY + (beforeZoomMPos[1] - afterZoomMPos[1]);
// Update pan
panX = nPanX;
panY = nPanY;

// Repaint canvas
repaint();
}
};
}

private MouseMotionListener makeMouseMotionListener(Component parent) {


return new MouseMotionListener() {
public void mouseMoved(MouseEvent e) {}

public void mouseDragged(MouseEvent e) {


if (SwingUtilities.isRightMouseButton(e)) { // If panning
// Calculate new pan values
double nPanX = panX - (e.getX() - startPanX)/zoom;
double nPanY = panY - (e.getY() - startPanY)/zoom;

// Check that new pan values allow board visibility


int boardSizeX = cellCountX * cellDimension;
int boardSizeY = cellCountY * cellDimension;
double screenSizeX = -parent.getWidth()/zoom;
double screenSizeY = -parent.getHeight()/zoom;

if (nPanX > boardSizeX) nPanX = boardSizeX;


if (nPanY > boardSizeY) nPanY = boardSizeY;
if (nPanX < screenSizeX) nPanX = screenSizeX;
if (nPanY < screenSizeY) nPanY = screenSizeY;

// Update pan
panX = nPanX;
panY = nPanY;
startPanX = e.getX();
startPanY = e.getY();

// Repaint canvas
repaint();
} else if (SwingUtilities.isLeftMouseButton(e)) { // If drawing
// Transform pressed coordinates into proper tile
coordinates in board
double[] worldPos = screenToWorld(e.getX(), e.getY());
int xTile = (int) (worldPos[0] / cellDimension);
int yTile = (int) (worldPos[1] / cellDimension);

if ((xTile >= 0 && xTile < cellCountX) && (yTile >= 0 &&
yTile < cellCountY)) {
// Place Tile
placeTile(xTile, yTile);

// Repaint the canvas


repaint();
}
}
}
};
}

public void resized() {


buffer = new BufferedImage(this.getSize().width, this.getSize().height,
BufferedImage.TYPE_INT_RGB);
bufferGraphics = buffer.getGraphics();
}

public void updateTimer() {


vizualizationTimer.setDelay((int)
(1000000/Math.pow(vizualizationSpeedSlider.getValue(), 3)));
}

public void updateComputationalMethod() {


computationalMethod =
ComputationalMethod.getEnum(algorithmComboBox.getSelectedItem().toString());
}

public void setShowVizualization() {


this.showVizualization = showVizualizationCheckbox.isSelected();
}

public void setEnableDiagonals() {


this.enableDiagonals = enableDiagonalsCB.isSelected();
}

GUI.java
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.plaf.InsetsUIResource;
/**
* GUI Class for managing the Graphical User Interface of the application.
*/
public class GUI {

// Main frame of the application (main window)


private JFrame frame;

// Component references that are necessary for communication between


components
private GraphicsCanvas graphicsCanvas;

private JCheckBox showVizualizationCheckbox;


private JCheckBox enableDiagonalsCB;
private JSlider vizualizationSpeedSlider;
private JComboBox algorithmComboBox;

private JLabel startPointLabel;


private JLabel endPointLabel;
private JLabel shortestPathLabel;
private JLabel computationalTimeLabel;

private JTextArea outputLog;

/**
* Constructor for GUI class
*/
public GUI() {
makeFrame();
}

/**
* Initializes the frame for this class instance
*/
private void makeFrame() {
// Create frame
frame = new JFrame("Pathfinding Visualizer");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Allow
application to terminate peacefully when being exited

// Create content pane


Container contentPane = frame.getContentPane();
contentPane.setLayout(new BorderLayout(0, 0));

// "Fill out" the Borderlayout with widgets and stuff


Component westLayout = makeWestLayout();
frame.add(westLayout, BorderLayout.WEST);

Component southLayout = makeSouthLayout();


frame.add(southLayout, BorderLayout.SOUTH);

Component centerLayout = makeCenterLayout();


frame.add(centerLayout, BorderLayout.CENTER);

Component eastLayout = makeEastLayout();


frame.add(eastLayout, BorderLayout.EAST);
// Make a menubar for the frame
JMenuBar menuBar = makeMenuBar();
frame.setJMenuBar(menuBar);

// Pack frame and set visible


frame.pack();
frame.setVisible(true);
frame.setMinimumSize(frame.getPreferredSize());
}

/**
* Initializes a menu bar for the specified frame
* @return - the created menubar
*/
private JMenuBar makeMenuBar() {
// Create a menubar and assign it to frame
JMenuBar menubar = new JMenuBar();
//frame.setJMenuBar(menubar);

// Create File Menu


JMenu fileMenu = new JMenu("File");
menubar.add(fileMenu);

// Create menu items for File Menu


//JMenuItem openItem = new JMenuItem("Open");
//fileMenu.add(openItem);
JMenuItem quitItem = new JMenuItem("Quit");
quitItem.addActionListener(e -> quit());
fileMenu.add(quitItem);

// Create Help Menu


JMenu helpMenu = new JMenu("Help");
menubar.add(helpMenu);

// Create menu items for Help Menu


JMenuItem showHelpItem = new JMenuItem("Show Help");
showHelpItem.addActionListener(e -> JOptionPane.showMessageDialog(frame,
"Software written by Kostiantyn V. Milkevych.\nSource and Information on
GitHub.com/KMilkevych", "Help", JOptionPane.INFORMATION_MESSAGE));
helpMenu.add(showHelpItem);

return menubar;
}

/**
* Creates the west side of the content in the Borderlayout of the specified
content pane
* @return - The created layout packed inside a Component
*/
private Component makeWestLayout() {
// Create a panel to hold the components
JPanel westPanel = new JPanel();
westPanel.setLayout(new GridBagLayout());

// Create GridBagContraints
GridBagConstraints c = new GridBagConstraints();
c.insets = new InsetsUIResource(10, 10, 10, 10);

// Make settings panel


Component settingsPanel = makeSettingsSubPanel();
c.gridy = 0;
//c.anchor = GridBagConstraints.NORTH;
c.fill = GridBagConstraints.HORIZONTAL;
westPanel.add(settingsPanel, c);

// Make configuration panel


Component configurationPanel = makeConfigurationSubPanel();
c.gridy = 1;
//c.anchor = GridBagConstraints.NORTH;
c.fill = GridBagConstraints.HORIZONTAL;
westPanel.add(configurationPanel, c);

return westPanel;
}

/**
* Creates a Settings panel containing controls for all settings, such as
vizualization speed, and vizualization type
* @return - Created settingspanel
*/
private Component makeSettingsSubPanel() {
// Create a "Settings" panel to hold some components
JPanel settingsPanel = new JPanel();
settingsPanel.setLayout(new GridBagLayout());

settingsPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLin
eBorder(Color.black), "Settings"));

// Create GridBagConstraits
GridBagConstraints c = new GridBagConstraints();
c.insets = new InsetsUIResource(5, 10, 5, 5);

// Create "Show vizualization:" label


JLabel showVizualizationLabel = new JLabel("Show vizualization:");
c.gridx = 0;
c.gridy = 0;
c.anchor = GridBagConstraints.EAST;
settingsPanel.add(showVizualizationLabel, c);
// Create checkbox
JCheckBox showVizualizationCB = new JCheckBox();
showVizualizationCB.setSelected(true);
showVizualizationCB.addActionListener(e ->
graphicsCanvas.setShowVizualization());
c.gridx = 1;
c.gridy = 0;
c.anchor = GridBagConstraints.WEST;
settingsPanel.add(showVizualizationCB, c);
this.showVizualizationCheckbox = showVizualizationCB;

// Create "Enable diagonals: " label


JLabel enableDiagonalsLabel = new JLabel("Enable diagonals:");
c.gridx = 0;
c.gridy = 1;
c.anchor = GridBagConstraints.EAST;
settingsPanel.add(enableDiagonalsLabel, c);

// Create checkbox
JCheckBox enableDiagonalsCB = new JCheckBox();
enableDiagonalsCB.setSelected(false);
enableDiagonalsCB.addActionListener(e ->
graphicsCanvas.setEnableDiagonals());
c.gridx = 1;
c.gridy = 1;
c.anchor = GridBagConstraints.WEST;
settingsPanel.add(enableDiagonalsCB, c);
this.enableDiagonalsCB = enableDiagonalsCB;

// Create "Vizualization speed:" label


JLabel vizualizationSpeedLabel = new JLabel("Vizualization speed:");
c.gridx = 0;
c.gridy = 2;
c.anchor = GridBagConstraints.EAST;
settingsPanel.add(vizualizationSpeedLabel, c);

// Create slider
JSlider vizualizationSpeedSlider = new JSlider(10, 100, 50);
vizualizationSpeedSlider.addChangeListener(e ->
graphicsCanvas.updateTimer());
c.gridx = 1;
c.gridy = 2;
c.anchor = GridBagConstraints.WEST;
settingsPanel.add(vizualizationSpeedSlider, c);
this.vizualizationSpeedSlider = vizualizationSpeedSlider;

// Create "Pathfinding algorithm" label


JLabel pathfindingAlgorithmLabel = new JLabel("Algorithm:");
c.gridx = 0;
c.gridy = 3;
c.anchor = GridBagConstraints.EAST;
settingsPanel.add(pathfindingAlgorithmLabel, c);

// Add combobox for selection of algorithm


JComboBox algorithmComboBox = new JComboBox<>(new String[] {"A*",
"Breadth First Search"});
algorithmComboBox.addActionListener(e ->
graphicsCanvas.updateComputationalMethod());
c.gridx = 1;
c.gridy = 3;
c.anchor = GridBagConstraints.WEST;
settingsPanel.add(algorithmComboBox, c);
this.algorithmComboBox = algorithmComboBox;

return settingsPanel;
}

/**
* Creates a Configuration sub panel containing information about
current/last simulation, as well as RUN and CLEAR buttons
* @return - created configurationpanel
*/
private Component makeConfigurationSubPanel() {
// Create configuration panel
JPanel configurationPanel = new JPanel();
configurationPanel.setLayout(new GridBagLayout());

configurationPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.crea
teLineBorder(Color.black), "Configuration"));

// Create GridBagConstraints for layout


GridBagConstraints c = new GridBagConstraints();
c.insets = new InsetsUIResource(5, 5, 5, 5);

// Create Labels for showing info on startpoint, endpoint, shortest path


length and computation time
JLabel startLabel = new JLabel("Startpoint:");

JLabel startValLabel = new JLabel("NOT SET");


this.startPointLabel = startValLabel;

JLabel endLabel = new JLabel("Endpoint:");

JLabel endValLabel = new JLabel("NOT SET");


this.endPointLabel = endValLabel;

JLabel shortestPathLabel = new JLabel("Shortest path:");

JLabel shortestPathValLabel = new JLabel("N/A");


this.shortestPathLabel = shortestPathValLabel;
JLabel computationTimeLabel = new JLabel("Time:");

JLabel computationTimeValLabel = new JLabel("N/A");


this.computationalTimeLabel = computationTimeValLabel;

// Add left-side labels to layout


c.gridx = 0;
c.anchor = GridBagConstraints.EAST;

c.gridy = 0;
configurationPanel.add(startLabel, c);

c.gridy = 1;
configurationPanel.add(endLabel, c);

c.gridy = 2;
configurationPanel.add(shortestPathLabel, c);

c.gridy = 3;
configurationPanel.add(computationTimeLabel, c);

// Add right-side labels to layout


c.gridx = 1;
c.anchor = GridBagConstraints.WEST;

c.gridy = 0;
configurationPanel.add(startValLabel, c);

c.gridy = 1;
configurationPanel.add(endValLabel, c);

c.gridy = 2;
configurationPanel.add(shortestPathValLabel, c);

c.gridy = 3;
configurationPanel.add(computationTimeValLabel, c);

// Now create the RUN and CLEAR buttons


c.gridy = 4;
c.fill = GridBagConstraints.BOTH;
c.weightx = 0.5;

JButton runButton = new JButton("Run");


runButton.addActionListener(e -> graphicsCanvas.run());
c.gridx = 0;
c.anchor = GridBagConstraints.EAST;
configurationPanel.add(runButton, c);

JButton clearButton = new JButton("Clear");


clearButton.addActionListener(e -> graphicsCanvas.reset());
c.gridx = 1;
c.anchor = GridBagConstraints.WEST;
configurationPanel.add(clearButton, c);

return configurationPanel;
}

/**
* Creates the center part of the content in the Borderlayout of the
specified content pane
* @return - The created layout packed indside a Component
*/
private Component makeCenterLayout() {
// Create a sample canvas
GraphicsCanvas canvas = new GraphicsCanvas(showVizualizationCheckbox,
enableDiagonalsCB, vizualizationSpeedSlider, algorithmComboBox, startPointLabel,
endPointLabel, shortestPathLabel, computationalTimeLabel, outputLog);
canvas.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
canvas.resized();
}
});
this.graphicsCanvas = canvas;

return canvas;
}

/**
* Creates the south part of the content in the Borderlayout of the
specified content pane
* @return - the created layout packed inside a Component
*/
private Component makeSouthLayout() {

// Create text area for output log


JTextArea outputLog = new JTextArea("Welcome to Pathfinding Vizualizer!\
n", 6, 1);
outputLog.setEditable(false);
outputLog.setLineWrap(true);
/*
DefaultCaret caret = (DefaultCaret)outputLog.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
*/
this.outputLog = outputLog;

// Create a JScrollPane to house outputLog


JScrollPane logPanel = new JScrollPane(outputLog);

return logPanel;
}

private Component makeEastLayout() {

// Create a panel for containt components


JPanel eastPanel = new JPanel();
eastPanel.setLayout(new BoxLayout(eastPanel, BoxLayout.X_AXIS));

// Create a vertical separator


JSeparator separator = new JSeparator(JSeparator.VERTICAL);
eastPanel.add(separator);

// Create a toolbar
JToolBar toolbar = new JToolBar(JToolBar.VERTICAL);
eastPanel.add(toolbar);

// Create four buttons for toolbar


JButton whiteButton = new JButton(createImageIcon(Color.LIGHT_GRAY, 32,
32));
whiteButton.addActionListener(e ->
graphicsCanvas.setMode(Mode.FREEPLACE));
whiteButton.setToolTipText("Erase Node");
toolbar.add(whiteButton);

JButton redButton = new JButton(createImageIcon(Color.RED, 32, 32));


redButton.addActionListener(e ->
graphicsCanvas.setMode(Mode.STARTPLACE));
redButton.setToolTipText("Start Node");
toolbar.add(redButton);

JButton blueButton = new JButton(createImageIcon(Color.BLUE, 32, 32));


blueButton.addActionListener(e ->
graphicsCanvas.setMode(Mode.ENDPLACE));
blueButton.setToolTipText("End Node");
toolbar.add(blueButton);

JButton blackButton = new JButton(createImageIcon(Color.BLACK, 32, 32));


blackButton.addActionListener(e ->
graphicsCanvas.setMode(Mode.WALLPLACE));
blackButton.setToolTipText("Wall Node");
toolbar.add(blackButton);

// Return created eastPanel


return eastPanel;
}

private ImageIcon createImageIcon(Color color, int width, int height) {


BufferedImage img = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics g = img.createGraphics();
g.setColor(color);
g.fillRect(0, 0, width, height);
return new ImageIcon(img);
}

/**
* Calmly terminates the application
*/
private void quit() {
System.exit(0);
}

}
8.2 SCREENSHOTS :

You might also like