Sync
This commit is contained in:
parent
6f050a029e
commit
776bba907c
3887 changed files with 59894 additions and 7280 deletions
|
|
@ -1,11 +1,9 @@
|
|||
import std.stdio, std.random, std.string, std.array, std.algorithm,
|
||||
std.traits;
|
||||
std.file;
|
||||
|
||||
enum int cx = 4; // Cell size x.
|
||||
enum int cy = 2; // Cell size y.
|
||||
enum int cx2 = cx / 2;
|
||||
enum int cy2 = cy / 2;
|
||||
enum char pathSymbol = '.';
|
||||
enum int cx = 4, cy = 2; // Cell size x and y.
|
||||
enum int cx2 = cx / 2, cy2 = cy / 2;
|
||||
enum pathSymbol = '.';
|
||||
struct V2 { int x, y; }
|
||||
|
||||
bool solveMaze(char[][] maze, in V2 s, in V2 end) pure nothrow {
|
||||
|
|
@ -25,15 +23,10 @@ bool solveMaze(char[][] maze, in V2 s, in V2 end) pure nothrow {
|
|||
}
|
||||
|
||||
void main() {
|
||||
auto maze = File("maze.txt")
|
||||
.byLine()
|
||||
.map!(r => r.strip().dup)()
|
||||
.filter!(r => !r.empty)()
|
||||
.array();
|
||||
|
||||
immutable int h = (maze.length - 1) / cy;
|
||||
auto maze = "maze.txt".readText.splitLines.map!(r => r.dup).array;
|
||||
immutable int h = ((cast(int)maze.length) - 1) / cy;
|
||||
assert (h > 0);
|
||||
immutable int w = (maze[0].length - 1) / cx;
|
||||
immutable int w = ((cast(int)maze[0].length) - 1) / cx;
|
||||
|
||||
immutable start = V2(cx2 + cx * uniform(0, w),
|
||||
cy2 + cy * uniform(0, h));
|
||||
|
|
@ -41,10 +34,9 @@ void main() {
|
|||
cy2 + cy * uniform(0, h));
|
||||
|
||||
maze[start.y][start.x] = pathSymbol;
|
||||
if (solveMaze(maze, start, end)) {
|
||||
maze[start.y][start.x] = 'S';
|
||||
maze[end.y][end.x] = 'E';
|
||||
writefln("%-(%s\n%)", maze);
|
||||
} else
|
||||
writeln("No solution path found.");
|
||||
if (!solveMaze(maze, start, end))
|
||||
return "No solution path found.".writeln;
|
||||
maze[start.y][start.x] = 'S';
|
||||
maze[end.y][end.x] = 'E';
|
||||
writefln("%-(%s\n%)", maze);
|
||||
}
|
||||
|
|
|
|||
39
Task/Maze-solving/Erlang/maze-solving.erl
Normal file
39
Task/Maze-solving/Erlang/maze-solving.erl
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
-module( maze_solving ).
|
||||
|
||||
-export( [task/0] ).
|
||||
|
||||
cells( {Start_x, Start_y}, {Stop_x, Stop_y}, Maze ) ->
|
||||
Start_pid = maze:cell_pid( Start_x, Start_y, Maze ),
|
||||
Stop_pid = maze:cell_pid( Stop_x, Stop_y, Maze ),
|
||||
{ok, Cells} = loop( Start_pid, Stop_pid, maze:cell_accessible_neighbours(Start_pid), [Start_pid] ),
|
||||
Cells.
|
||||
|
||||
task() ->
|
||||
Max_x = 16,
|
||||
Max_y = 8,
|
||||
Maze = maze:generation( Max_x, Max_y ),
|
||||
Start_x = random:uniform( Max_x ),
|
||||
Start_y = random:uniform( Max_y ),
|
||||
Stop_x = random:uniform( Max_x ),
|
||||
Stop_y = random:uniform( Max_y ),
|
||||
Cells = cells( {Start_x, Start_y}, {Stop_x, Stop_y}, Maze ),
|
||||
[maze:cell_content_set(X, ".") || X <- Cells],
|
||||
maze:cell_content_set( maze:cell_pid(Start_x, Start_y, Maze), "S" ),
|
||||
maze:cell_content_set( maze:cell_pid(Stop_x, Stop_y, Maze), "G" ),
|
||||
maze:display( Maze ),
|
||||
maze:stop( Maze ).
|
||||
|
||||
|
||||
|
||||
loop( _Start, _Stop, [], _Acc) -> {error, dead_end};
|
||||
loop( _Start, Stop, [Stop], Acc ) -> {ok, lists:reverse( [Stop | Acc] )};
|
||||
loop( Start, Stop, [Next], [Previous | _T]=Acc ) -> loop( Start, Stop, lists:delete(Previous, maze:cell_accessible_neighbours(Next)), [Next | Acc] );
|
||||
loop( Start, Stop, Nexts, Acc ) -> loop_stop( lists:member(Stop, Nexts), Start, Stop, Nexts, Acc ).
|
||||
|
||||
loop_stop( true, _Start, Stop, _Nexts, Acc ) -> {ok, lists:reverse( [Stop | Acc] )};
|
||||
loop_stop( false, Start, Stop, Nexts, Acc ) ->
|
||||
My_pid = erlang:self(),
|
||||
[erlang:spawn( fun() -> My_pid ! loop( Start, Stop, [X], Acc ) end ) || X <- Nexts],
|
||||
receive
|
||||
{ok, Cells} -> {ok, Cells}
|
||||
end.
|
||||
125
Task/Maze-solving/Icon/maze-solving-3.icon
Normal file
125
Task/Maze-solving/Icon/maze-solving-3.icon
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
global showMice
|
||||
|
||||
import Utils # To get 'Args' singleton class
|
||||
|
||||
procedure main(A)
|
||||
Args(A)
|
||||
if \Args().get("help","yes") then helpMesg()
|
||||
showMice := Args().get("showmice","yes") # Show movements of all mice
|
||||
mh := Args().get("rows") | 32 # Maze height (rows)
|
||||
mw := Args().get("cols") | 48 # Maze width (columns)
|
||||
|
||||
mz := DisplayMaze(GenerateMaze(mh,mw)) # Build and show maze
|
||||
|
||||
QMouse(mz.maze,findStart(mz.maze)) # Start first quantum mouse
|
||||
waitForCompletion() # block until all quantum mice have finished
|
||||
|
||||
# Mark the best path into the maze and display it.
|
||||
if showPath(mz.maze) then DisplayMazeSolution(mz) else write("No path found!")
|
||||
end
|
||||
|
||||
procedure helpMesg()
|
||||
write(&errout,"Usage: qSolve [--showmice] [--cols=C] [--rows=R]")
|
||||
write(&errout,"\twhere:")
|
||||
write(&errout,"\t\t--showmice # displays all mice paths as they search")
|
||||
write(&errout,"\t\t--cols=C # sets maze width to C (default 16) columns")
|
||||
write(&errout,"\t\t--rows=R # sets maze height to R (default 12) rows")
|
||||
stop()
|
||||
end
|
||||
|
||||
# A "Quantum-mouse" for traversing mazes. Each mouse lives for just one cell, but
|
||||
# can spawn other mice to search from adjoining cells.
|
||||
|
||||
global qMice, bestMouse, bestMouseLock, region, qMiceEmpty
|
||||
record Position(r,c)
|
||||
|
||||
# Must match values used in maze generation!
|
||||
$define FINISH 64 # exit
|
||||
$define START 32 # entrance
|
||||
$define PATH 128
|
||||
$define SEEN 16 # bread crumbs for generator
|
||||
$define NORTH 8 # sides ...
|
||||
$define EAST 4
|
||||
$define SOUTH 2
|
||||
$define WEST 1
|
||||
$define EMPTY 0 # like new
|
||||
|
||||
class QMouse(maze, loc, path, val)
|
||||
|
||||
method getPath(); return path; end
|
||||
method atEnd(); return EMPTY ~= iand(val, FINISH); end
|
||||
method goNorth(); if EMPTY ~= iand(val,NORTH) then return visit(loc.r-1, loc.c); end
|
||||
method goSouth(); if EMPTY ~= iand(val,SOUTH) then return visit(loc.r+1, loc.c); end
|
||||
method goEast(); if EMPTY ~= iand(val,EAST) then return visit(loc.r, loc.c+1); end
|
||||
method goWest(); if EMPTY ~= iand(val,WEST) then return visit(loc.r, loc.c-1); end
|
||||
|
||||
method visit(r,c)
|
||||
critical region[r,c]: if EMPTY = iand(maze[r,c],SEEN) then {
|
||||
if /bestMouse | (*path <= *bestMouse.path) then { # Keep going?
|
||||
mark(maze, r,c)
|
||||
unlock(region[r,c])
|
||||
return Position(r,c)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
initially (m, l, p)
|
||||
initial { # Construct critical region mutexes and completion condvar
|
||||
qMice := mutex(set())
|
||||
qMiceEmpty := condvar()
|
||||
bestMouseLock := mutex()
|
||||
region := list(*m) # Minimize critical region size
|
||||
every r := 1 to *m do region[r] := list(*m[1])
|
||||
every !!region := mutex()
|
||||
}
|
||||
maze := m
|
||||
loc := l
|
||||
val := maze[loc.r,loc.c] | fail # Fail if outside maze
|
||||
/path := []
|
||||
if \p then path := copy(p)
|
||||
put(path, loc)
|
||||
insert(qMice, self)
|
||||
thread {
|
||||
if atEnd() then {
|
||||
critical bestMouseLock:
|
||||
if /bestMouse | (*path < bestMouse.path) then bestMouse := self
|
||||
}
|
||||
else { # Spawn more mice to look for finish
|
||||
QMouse(maze, goNorth(), path)
|
||||
QMouse(maze, goSouth(), path)
|
||||
QMouse(maze, goEast(), path)
|
||||
QMouse(maze, goWest(), path)
|
||||
}
|
||||
|
||||
delete(qMice, self)
|
||||
if *qMice=0 then signal(qMiceEmpty)
|
||||
}
|
||||
end
|
||||
|
||||
procedure mark(maze, r,c)
|
||||
ior(maze[r,c],SEEN)
|
||||
if \showMice then markCell(r,c,"grey",5)
|
||||
return Position(r,c)
|
||||
end
|
||||
|
||||
procedure clearMaze(maze) # Clear out dregs from maze creation
|
||||
every r := 1 to *maze & c := 1 to *maze[1] do # remove breadcrumbs
|
||||
maze[r,c] := iand(maze[r,c],NORTH+EAST+SOUTH+WEST+START+FINISH)
|
||||
end
|
||||
|
||||
procedure findStart(maze) # Anywhere in maze
|
||||
clearMaze(maze) # Remove breadcrumbs
|
||||
every r := 1 to *maze & c := 1 to *maze[1] do # Locate START cell
|
||||
if EMPTY ~= iand(maze[r,c],START) then return mark(maze, r,c)
|
||||
end
|
||||
|
||||
procedure showPath(maze)
|
||||
if \bestMouse then { # Mark it in maze
|
||||
every p := !bestMouse.path do maze[p.r,p.c] +:= PATH
|
||||
return
|
||||
}
|
||||
end
|
||||
|
||||
procedure waitForCompletion()
|
||||
critical qMiceEmpty: while *qMice > 0 do wait(qMiceEmpty)
|
||||
end
|
||||
77
Task/Maze-solving/Perl/maze-solving.pl
Normal file
77
Task/Maze-solving/Perl/maze-solving.pl
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#!perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my ($width, $height) = @ARGV;
|
||||
$_ ||= 10 for $width, $height;
|
||||
|
||||
my %visited;
|
||||
|
||||
my $h_barrier = "+" . ("--+" x $width) . "\n";
|
||||
my $v_barrier = "|" . (" |" x $width) . "\n";
|
||||
my @output = ($h_barrier, $v_barrier) x $height;
|
||||
push @output, $h_barrier;
|
||||
my @dx = qw(-1 1 0 0);
|
||||
my @dy = qw(0 0 -1 1);
|
||||
|
||||
sub visit {
|
||||
my ($x, $y) = @_;
|
||||
$visited{$x, $y} = 1;
|
||||
my $rand = int rand 4;
|
||||
for my $n ( $rand .. 3, 0 .. $rand-1 ) {
|
||||
my ($xx, $yy) = ($x + $dx[$n], $y + $dy[$n]);
|
||||
next if $visited{ $xx, $yy };
|
||||
next if $xx < 0 or $xx >= $width;
|
||||
next if $yy < 0 or $yy >= $height;
|
||||
|
||||
my $row = $y * 2 + 1 + $dy[$n];
|
||||
my $col = $x * 3 + 1 + $dx[$n];
|
||||
substr( $output[$row], $col, 2, ' ' );
|
||||
|
||||
no warnings 'recursion';
|
||||
visit( $xx, $yy );
|
||||
}
|
||||
}
|
||||
|
||||
visit( int rand $width, int rand $height );
|
||||
|
||||
print "Here is the maze:\n";
|
||||
print @output;
|
||||
|
||||
%visited = ();
|
||||
|
||||
my @d = ('>>', '<<', 'vv', '^^');
|
||||
sub solve {
|
||||
my ($x, $y) = @_;
|
||||
return 1 if $x == 0 and $y == 0;
|
||||
$visited{ $x, $y } = 1;
|
||||
my $rand = int rand 4;
|
||||
for my $n ( $rand .. 3, 0 .. $rand-1 ) {
|
||||
my ($xx, $yy) = ($x + $dx[$n], $y + $dy[$n]);
|
||||
next if $visited{ $xx, $yy };
|
||||
next if $xx < 0 or $xx >= $width;
|
||||
next if $yy < 0 or $yy >= $height;
|
||||
|
||||
my $row = $y * 2 + 1 + $dy[$n];
|
||||
my $col = $x * 3 + 1 + $dx[$n];
|
||||
|
||||
my $b = substr( $output[$row], $col, 2 );
|
||||
next if " " ne $b;
|
||||
|
||||
no warnings 'recursion';
|
||||
next if not solve( $xx, $yy );
|
||||
|
||||
substr( $output[$row], $col, 2, $d[$n] );
|
||||
substr( $output[$row-$dy[$n]], $col-$dx[$n], 2, $d[$n] );
|
||||
return 1;
|
||||
}
|
||||
0;
|
||||
}
|
||||
|
||||
if( solve( $width-1, $height-1 ) ) {
|
||||
print "Here is the solution:\n";
|
||||
substr( $output[1], 1, 2, '**' );
|
||||
print @output;
|
||||
} else {
|
||||
print "Could not solve!\n";
|
||||
}
|
||||
|
|
@ -3,82 +3,69 @@ class Maze
|
|||
# Each queue entry is a path, that is list of coordinates with the
|
||||
# last coordinate being the one that shall be visited next.
|
||||
def solve
|
||||
queue = []
|
||||
path = nil
|
||||
|
||||
# Enqueue start position.
|
||||
enqueue_cell queue, [], @start_x, @start_y
|
||||
|
||||
# Loop as long as there are cells to visit and no solution has
|
||||
# been found yet.
|
||||
while !queue.empty? && !path
|
||||
path = solve_visit_cell queue
|
||||
end
|
||||
|
||||
# Clean up.
|
||||
reset_visiting_state
|
||||
|
||||
puts "No solution found?!" unless path
|
||||
# Enqueue start position.
|
||||
@queue = []
|
||||
enqueue_cell([], @start_x, @start_y)
|
||||
|
||||
# Mark the cells that make up the shortest path.
|
||||
for x, y in path
|
||||
@path[y][x] = true
|
||||
# Loop as long as there are cells to visit and no solution has
|
||||
# been found yet.
|
||||
path = nil
|
||||
until path || @queue.empty?
|
||||
path = solve_visit_cell
|
||||
end
|
||||
|
||||
if path
|
||||
# Mark the cells that make up the shortest path.
|
||||
for x, y in path
|
||||
@path[x][y] = true
|
||||
end
|
||||
else
|
||||
puts "No solution found?!"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Maze solving visiting method.
|
||||
def solve_visit_cell(queue)
|
||||
def solve_visit_cell
|
||||
# Get the next path.
|
||||
path = queue.shift
|
||||
path = @queue.shift
|
||||
# The cell to visit is the last entry in the path.
|
||||
x, y = path.last
|
||||
|
||||
# Have we reached the end yet?
|
||||
if x == @end_x && y == @end_y
|
||||
# Yes, we have!
|
||||
return path
|
||||
end
|
||||
return path if x == @end_x && y == @end_y
|
||||
|
||||
# Mark cell as visited.
|
||||
@visited[y][x] = true
|
||||
@visited[x][y] = true
|
||||
|
||||
# Left
|
||||
new_x = x - 1
|
||||
if move_valid?(new_x, y) && !@vertical_walls[y][new_x]
|
||||
enqueue_cell queue, path, new_x, y
|
||||
for dx, dy in DIRECTIONS
|
||||
if dx.nonzero?
|
||||
# Left / Right
|
||||
new_x = x + dx
|
||||
if move_valid?(new_x, y) && !@vertical_walls[ [x, new_x].min ][y]
|
||||
enqueue_cell(path, new_x, y)
|
||||
end
|
||||
else
|
||||
# Top / Bottom
|
||||
new_y = y + dy
|
||||
if move_valid?(x, new_y) && !@horizontal_walls[x][ [y, new_y].min ]
|
||||
enqueue_cell(path, x, new_y)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Right
|
||||
new_x = x + 1
|
||||
if move_valid?(new_x, y) && !@vertical_walls[y][x]
|
||||
enqueue_cell queue, path, new_x, y
|
||||
end
|
||||
|
||||
# Top
|
||||
new_y = y - 1
|
||||
if move_valid?(x, new_y) && !@horizontal_walls[new_y][x]
|
||||
enqueue_cell queue, path, x, new_y
|
||||
end
|
||||
|
||||
# Bottom
|
||||
new_y = y + 1
|
||||
if move_valid?(x, new_y) && !@horizontal_walls[y][x]
|
||||
enqueue_cell queue, path, x, new_y
|
||||
end
|
||||
|
||||
# No solution yet.
|
||||
return nil
|
||||
nil # No solution yet.
|
||||
end
|
||||
|
||||
# Enqueue a new coordinate to visit.
|
||||
def enqueue_cell(queue, path, x, y)
|
||||
# Copy the current path, add the new coordinates and enqueue
|
||||
# the new path.
|
||||
path = path.dup
|
||||
path << [x, y]
|
||||
queue << path
|
||||
def enqueue_cell(path, x, y)
|
||||
# Add new coordinates to the current path and enqueue the new path.
|
||||
@queue << path + [[x, y]]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue