Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
149
Task/Maze-solving/Java/maze-solving-1.java
Normal file
149
Task/Maze-solving/Java/maze-solving-1.java
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class MazeSolver
|
||||
{
|
||||
/**
|
||||
* Reads a file into an array of strings, one per line.
|
||||
*/
|
||||
private static String[] readLines (InputStream f) throws IOException
|
||||
{
|
||||
BufferedReader r =
|
||||
new BufferedReader (new InputStreamReader (f, "US-ASCII"));
|
||||
ArrayList<String> lines = new ArrayList<String>();
|
||||
String line;
|
||||
while ((line = r.readLine()) != null)
|
||||
lines.add (line);
|
||||
return lines.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the maze half as wide (i. e. "+---+" becomes "+-+"), so that
|
||||
* each cell in the maze is the same size horizontally as vertically.
|
||||
* (Versus the expanded version, which looks better visually.)
|
||||
* Also, converts each line of the maze from a String to a
|
||||
* char[], because we'll want mutability when drawing the solution later.
|
||||
*/
|
||||
private static char[][] decimateHorizontally (String[] lines)
|
||||
{
|
||||
final int width = (lines[0].length() + 1) / 2;
|
||||
char[][] c = new char[lines.length][width];
|
||||
for (int i = 0 ; i < lines.length ; i++)
|
||||
for (int j = 0 ; j < width ; j++)
|
||||
c[i][j] = lines[i].charAt (j * 2);
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the maze, the x and y coordinates (which must be odd),
|
||||
* and the direction we came from, return true if the maze is
|
||||
* solvable, and draw the solution if so.
|
||||
*/
|
||||
private static boolean solveMazeRecursively (char[][] maze,
|
||||
int x, int y, int d)
|
||||
{
|
||||
boolean ok = false;
|
||||
for (int i = 0 ; i < 4 && !ok ; i++)
|
||||
if (i != d)
|
||||
switch (i)
|
||||
{
|
||||
// 0 = up, 1 = right, 2 = down, 3 = left
|
||||
case 0:
|
||||
if (maze[y-1][x] == ' ')
|
||||
ok = solveMazeRecursively (maze, x, y - 2, 2);
|
||||
break;
|
||||
case 1:
|
||||
if (maze[y][x+1] == ' ')
|
||||
ok = solveMazeRecursively (maze, x + 2, y, 3);
|
||||
break;
|
||||
case 2:
|
||||
if (maze[y+1][x] == ' ')
|
||||
ok = solveMazeRecursively (maze, x, y + 2, 0);
|
||||
break;
|
||||
case 3:
|
||||
if (maze[y][x-1] == ' ')
|
||||
ok = solveMazeRecursively (maze, x - 2, y, 1);
|
||||
break;
|
||||
}
|
||||
// check for end condition
|
||||
if (x == 1 && y == 1)
|
||||
ok = true;
|
||||
// once we have found a solution, draw it as we unwind the recursion
|
||||
if (ok)
|
||||
{
|
||||
maze[y][x] = '*';
|
||||
switch (d)
|
||||
{
|
||||
case 0:
|
||||
maze[y-1][x] = '*';
|
||||
break;
|
||||
case 1:
|
||||
maze[y][x+1] = '*';
|
||||
break;
|
||||
case 2:
|
||||
maze[y+1][x] = '*';
|
||||
break;
|
||||
case 3:
|
||||
maze[y][x-1] = '*';
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* Solve the maze and draw the solution. For simplicity,
|
||||
* assumes the starting point is the lower right, and the
|
||||
* ending point is the upper left.
|
||||
*/
|
||||
private static void solveMaze (char[][] maze)
|
||||
{
|
||||
solveMazeRecursively (maze, maze[0].length - 2, maze.length - 2, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opposite of decimateHorizontally(). Adds extra characters to make
|
||||
* the maze "look right", and converts each line from char[] to
|
||||
* String at the same time.
|
||||
*/
|
||||
private static String[] expandHorizontally (char[][] maze)
|
||||
{
|
||||
char[] tmp = new char[3];
|
||||
String[] lines = new String[maze.length];
|
||||
for (int i = 0 ; i < maze.length ; i++)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(maze[i].length * 2);
|
||||
for (int j = 0 ; j < maze[i].length ; j++)
|
||||
if (j % 2 == 0)
|
||||
sb.append (maze[i][j]);
|
||||
else
|
||||
{
|
||||
tmp[0] = tmp[1] = tmp[2] = maze[i][j];
|
||||
if (tmp[1] == '*')
|
||||
tmp[0] = tmp[2] = ' ';
|
||||
sb.append (tmp);
|
||||
}
|
||||
lines[i] = sb.toString();
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a maze as generated by:
|
||||
* http://rosettacode.org/wiki/Maze_generation#Java
|
||||
* in a file whose name is specified as a command-line argument,
|
||||
* or on standard input if no argument is specified.
|
||||
*/
|
||||
public static void main (String[] args) throws IOException
|
||||
{
|
||||
InputStream f = (args.length > 0
|
||||
? new FileInputStream (args[0])
|
||||
: System.in);
|
||||
String[] lines = readLines (f);
|
||||
char[][] maze = decimateHorizontally (lines);
|
||||
solveMaze (maze);
|
||||
String[] solvedLines = expandHorizontally (maze);
|
||||
for (int i = 0 ; i < solvedLines.length ; i++)
|
||||
System.out.println (solvedLines[i]);
|
||||
}
|
||||
}
|
||||
182
Task/Maze-solving/Java/maze-solving-2.java
Normal file
182
Task/Maze-solving/Java/maze-solving-2.java
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
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<Integer> 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue