import java.awt.*; import java.awt.event.*; import java.awt.geom.Path2D; import java.util.*; import javax.swing.*; public class MazeGenerator extends JPanel { enum Dir { N(1, 0, -1), S(2, 0, 1), E(4, 1, 0), W(8, -1, 0); final int bit; final int dx; final int dy; Dir opposite; // use the static initializer to resolve forward references static { N.opposite = S; S.opposite = N; E.opposite = W; W.opposite = E; } Dir(int bit, int dx, int dy) { this.bit = bit; this.dx = dx; this.dy = dy; } }; final int nCols; final int nRows; final int cellSize = 25; final int margin = 25; final int[][] maze; LinkedList solution; public MazeGenerator(int size) { setPreferredSize(new Dimension(650, 650)); setBackground(Color.white); nCols = size; nRows = size; maze = new int[nRows][nCols]; solution = new LinkedList<>(); generateMaze(0, 0); addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { new Thread(() -> { solve(0); }).start(); } }); } @Override public void paintComponent(Graphics gg) { super.paintComponent(gg); Graphics2D g = (Graphics2D) gg; g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setStroke(new BasicStroke(5)); g.setColor(Color.black); // draw maze for (int r = 0; r < nRows; r++) { for (int c = 0; c < nCols; c++) { int x = margin + c * cellSize; int y = margin + r * cellSize; if ((maze[r][c] & 1) == 0) // N g.drawLine(x, y, x + cellSize, y); if ((maze[r][c] & 2) == 0) // S g.drawLine(x, y + cellSize, x + cellSize, y + cellSize); if ((maze[r][c] & 4) == 0) // E g.drawLine(x + cellSize, y, x + cellSize, y + cellSize); if ((maze[r][c] & 8) == 0) // W g.drawLine(x, y, x, y + cellSize); } } // draw pathfinding animation int offset = margin + cellSize / 2; Path2D path = new Path2D.Float(); path.moveTo(offset, offset); for (int pos : solution) { int x = pos % nCols * cellSize + offset; int y = pos / nCols * cellSize + offset; path.lineTo(x, y); } g.setColor(Color.orange); g.draw(path); g.setColor(Color.blue); g.fillOval(offset - 5, offset - 5, 10, 10); g.setColor(Color.green); int x = offset + (nCols - 1) * cellSize; int y = offset + (nRows - 1) * cellSize; g.fillOval(x - 5, y - 5, 10, 10); } void generateMaze(int r, int c) { Dir[] dirs = Dir.values(); Collections.shuffle(Arrays.asList(dirs)); for (Dir dir : dirs) { int nc = c + dir.dx; int nr = r + dir.dy; if (withinBounds(nr, nc) && maze[nr][nc] == 0) { maze[r][c] |= dir.bit; maze[nr][nc] |= dir.opposite.bit; generateMaze(nr, nc); } } } boolean withinBounds(int r, int c) { return c >= 0 && c < nCols && r >= 0 && r < nRows; } boolean solve(int pos) { if (pos == nCols * nRows - 1) return true; int c = pos % nCols; int r = pos / nCols; for (Dir dir : Dir.values()) { int nc = c + dir.dx; int nr = r + dir.dy; if (withinBounds(nr, nc) && (maze[r][c] & dir.bit) != 0 && (maze[nr][nc] & 16) == 0) { int newPos = nr * nCols + nc; solution.add(newPos); maze[nr][nc] |= 16; animate(); if (solve(newPos)) return true; animate(); solution.removeLast(); maze[nr][nc] &= ~16; } } return false; } void animate() { try { Thread.sleep(50L); } catch (InterruptedException ignored) { } repaint(); } public static void main(String[] args) { SwingUtilities.invokeLater(() -> { JFrame f = new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setTitle("Maze Generator"); f.setResizable(false); f.add(new MazeGenerator(24), BorderLayout.CENTER); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); }); } }