Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
6
Task/Maze-solving/00-META.yaml
Normal file
6
Task/Maze-solving/00-META.yaml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
category:
|
||||
- Recursion
|
||||
- Puzzles
|
||||
from: http://rosettacode.org/wiki/Maze_solving
|
||||
note: Games
|
||||
9
Task/Maze-solving/00-TASK.txt
Normal file
9
Task/Maze-solving/00-TASK.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
;Task:
|
||||
For a maze generated by [[Maze generation|this task]], write a function
|
||||
that finds (and displays) the shortest path between two cells.
|
||||
|
||||
|
||||
Note that because these mazes are generated by the [[wp:Maze_generation_algorithm#Depth-first_search|Depth-first search]] algorithm, they contain no circular paths,
|
||||
and a simple depth-first tree search can be used.
|
||||
<br><br>
|
||||
|
||||
36
Task/Maze-solving/11l/maze-solving.11l
Normal file
36
Task/Maze-solving/11l/maze-solving.11l
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
F dijkstra(graph, source)
|
||||
V n = graph.len
|
||||
V dist = [Float.infinity] * n
|
||||
V previous = [-1] * n
|
||||
dist[source] = 0
|
||||
V Q = Array(0 .< n)
|
||||
L !Q.empty
|
||||
V u = min(Q, key' n -> @dist[n])
|
||||
Q.remove(u)
|
||||
I dist[u] == Float.infinity
|
||||
L.break
|
||||
L(v) 0 .< n
|
||||
I graph[u][v] & (v C Q)
|
||||
V alt = dist[u] + graph[u][v]
|
||||
I alt < dist[v]
|
||||
dist[v] = alt
|
||||
previous[v] = u
|
||||
R previous
|
||||
|
||||
F display_solution(predecessor)
|
||||
V cell = predecessor.len - 1
|
||||
L cell != 0
|
||||
print(cell, end' ‘<’)
|
||||
cell = predecessor[cell]
|
||||
print(0)
|
||||
|
||||
V graph = [
|
||||
[0,1,0,0,0,0],
|
||||
[1,0,1,0,1,0],
|
||||
[0,1,0,0,0,1],
|
||||
[0,0,0,0,1,0],
|
||||
[0,1,0,1,0,0],
|
||||
[0,0,1,0,0,0]
|
||||
]
|
||||
|
||||
display_solution(dijkstra(graph, 0))
|
||||
190
Task/Maze-solving/Action-/maze-solving.action
Normal file
190
Task/Maze-solving/Action-/maze-solving.action
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
DEFINE TOP="0"
|
||||
DEFINE RIGHT="1"
|
||||
DEFINE BOTTOM="2"
|
||||
DEFINE LEFT="3"
|
||||
DEFINE WIDTH="160"
|
||||
DEFINE HEIGHT="96"
|
||||
|
||||
DEFINE STACK_SIZE="5000"
|
||||
BYTE ARRAY stack(STACK_SIZE)
|
||||
INT stackSize
|
||||
|
||||
PROC InitStack()
|
||||
stackSize=0
|
||||
RETURN
|
||||
|
||||
BYTE FUNC IsEmpty()
|
||||
IF stackSize=0 THEN
|
||||
RETURN (1)
|
||||
FI
|
||||
RETURN (0)
|
||||
|
||||
BYTE FUNC IsFull()
|
||||
IF stackSize>=STACK_SIZE THEN
|
||||
RETURN (1)
|
||||
FI
|
||||
RETURN (0)
|
||||
|
||||
PROC Push(BYTE x,y)
|
||||
IF IsFull() THEN Break() RETURN FI
|
||||
stack(stackSize)=x stackSize==+1
|
||||
stack(stackSize)=y stackSize==+1
|
||||
RETURN
|
||||
|
||||
PROC Pop(BYTE POINTER x,y)
|
||||
IF IsEmpty() THEN Break() RETURN FI
|
||||
stackSize==-1 y^=stack(stackSize)
|
||||
stackSize==-1 x^=stack(stackSize)
|
||||
RETURN
|
||||
|
||||
PROC Push3(BYTE x,y,d)
|
||||
IF IsFull() THEN Break() RETURN FI
|
||||
stack(stackSize)=x stackSize==+1
|
||||
stack(stackSize)=y stackSize==+1
|
||||
stack(stackSize)=d stackSize==+1
|
||||
RETURN
|
||||
|
||||
PROC Pop3(BYTE POINTER x,y,d)
|
||||
IF IsEmpty() THEN Break() RETURN FI
|
||||
stackSize==-1 d^=stack(stackSize)
|
||||
stackSize==-1 y^=stack(stackSize)
|
||||
stackSize==-1 x^=stack(stackSize)
|
||||
RETURN
|
||||
|
||||
PROC FillScreen()
|
||||
BYTE POINTER ptr ;pointer to the screen memory
|
||||
INT screenSize=[3840]
|
||||
|
||||
ptr=PeekC(88)
|
||||
SetBlock(ptr,screenSize,$55)
|
||||
|
||||
Color=0
|
||||
Plot(0,HEIGHT-1) DrawTo(WIDTH-1,HEIGHT-1) DrawTo(WIDTH-1,0)
|
||||
RETURN
|
||||
|
||||
PROC GetNeighbors(BYTE x,y BYTE ARRAY n BYTE POINTER count)
|
||||
DEFINE WALL="1"
|
||||
|
||||
count^=0
|
||||
IF y>2 AND Locate(x,y-2)=WALL THEN
|
||||
n(count^)=TOP count^==+1
|
||||
FI
|
||||
IF x<WIDTH-3 AND Locate(x+2,y)=WALL THEN
|
||||
n(count^)=RIGHT count^==+1
|
||||
FI
|
||||
IF y<HEIGHT-3 AND Locate(x,y+2)=WALL THEN
|
||||
n(count^)=BOTTOM count^==+1
|
||||
FI
|
||||
IF x>2 AND Locate(x-2,y)=WALL THEN
|
||||
n(count^)=LEFT count^==+1
|
||||
FI
|
||||
RETURN
|
||||
|
||||
PROC DrawConnection(BYTE POINTER x,y BYTE dir)
|
||||
Plot(x^,y^)
|
||||
IF dir=TOP THEN
|
||||
y^==-2
|
||||
ELSEIF dir=RIGHT THEN
|
||||
x^==+2
|
||||
ELSEIF dir=BOTTOM THEN
|
||||
y^==+2
|
||||
ELSE
|
||||
x^==-2
|
||||
FI
|
||||
DrawTo(x^,y^)
|
||||
RETURN
|
||||
|
||||
PROC Maze(BYTE x,y)
|
||||
BYTE ARRAY stack,neighbors
|
||||
BYTE dir,nCount
|
||||
|
||||
FillScreen()
|
||||
|
||||
Color=2
|
||||
InitStack()
|
||||
Push(x,y)
|
||||
WHILE IsEmpty()=0
|
||||
DO
|
||||
Pop(@x,@y)
|
||||
GetNeighbors(x,y,neighbors,@nCount)
|
||||
IF nCount>0 THEN
|
||||
Push(x,y)
|
||||
dir=neighbors(Rand(nCount))
|
||||
DrawConnection(@x,@y,dir)
|
||||
Push(x,y)
|
||||
FI
|
||||
OD
|
||||
RETURN
|
||||
|
||||
BYTE FUNC IsConnection(BYTE x,y,dir)
|
||||
DEFINE WAY="2"
|
||||
IF dir=TOP AND y>2 AND Locate(x,y-1)=WAY THEN
|
||||
RETURN (1)
|
||||
ELSEIF dir=RIGHT AND x<WIDTH-3 AND Locate(x+1,y)=WAY THEN
|
||||
RETURN (1)
|
||||
ELSEIF dir=BOTTOM AND y<HEIGHT-3 AND Locate(x,y+1)=WAY THEN
|
||||
RETURN (1)
|
||||
ELSEIF dir=LEFT AND x>2 AND Locate(x-1,y)=WAY THEN
|
||||
RETURN (1)
|
||||
FI
|
||||
RETURN (0)
|
||||
|
||||
PROC Solve(BYTE x1,y1,x2,y2)
|
||||
BYTE dir,x,y,lastX,lastY,back
|
||||
|
||||
Color=3
|
||||
Plot(x1,y1)
|
||||
Plot(x2,y2)
|
||||
|
||||
InitStack()
|
||||
Push3(x1,y1,TOP)
|
||||
WHILE IsEmpty()=0
|
||||
DO
|
||||
Pop3(@x,@y,@dir)
|
||||
IF back THEN
|
||||
Color=2
|
||||
Plot(lastX,lastY)
|
||||
DrawTo(x,y)
|
||||
FI
|
||||
IF IsConnection(x,y,dir) THEN
|
||||
Color=3
|
||||
Push3(x,y,dir+1)
|
||||
DrawConnection(@x,@y,dir)
|
||||
IF x=x2 AND y=y2 THEN
|
||||
RETURN
|
||||
FI
|
||||
Push3(x,y,TOP)
|
||||
back=0
|
||||
ELSEIF dir<=LEFT THEN
|
||||
Push3(x,y,dir+1)
|
||||
back=0
|
||||
ELSE
|
||||
lastX=x
|
||||
lastY=y
|
||||
back=1
|
||||
FI
|
||||
OD
|
||||
RETURN
|
||||
|
||||
PROC Main()
|
||||
BYTE CH=$02FC,COLOR0=$02C4,COLOR1=$02C5,COLOR2=$02C6
|
||||
BYTE x,y,x2,y2
|
||||
|
||||
Graphics(7+16)
|
||||
COLOR0=$0A
|
||||
COLOR1=$04
|
||||
COLOR2=$A6
|
||||
|
||||
x=Rand((WIDTH RSH 1)-1) LSH 1+1
|
||||
y=Rand((HEIGHT RSH 1)-1) LSH 1+1
|
||||
Maze(x,y)
|
||||
|
||||
x=Rand((WIDTH RSH 1)-1) LSH 1+1
|
||||
y=Rand((HEIGHT RSH 1)-1) LSH 1+1
|
||||
x2=Rand((WIDTH RSH 1)-1) LSH 1+1
|
||||
y2=Rand((HEIGHT RSH 1)-1) LSH 1+1
|
||||
Solve(x,y,x2,y2)
|
||||
|
||||
DO UNTIL CH#$FF OD
|
||||
CH=$FF
|
||||
RETURN
|
||||
73
Task/Maze-solving/Ada/maze-solving.ada
Normal file
73
Task/Maze-solving/Ada/maze-solving.ada
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
with Ada.Text_IO;
|
||||
|
||||
procedure Maze_Solver is
|
||||
|
||||
X_Size: constant Natural := 45;
|
||||
Y_Size: constant Natural := 17;
|
||||
|
||||
subtype X_Range is Natural range 1 .. X_Size;
|
||||
subtype Y_Range is Natural range 1 .. Y_Size;
|
||||
|
||||
East: constant X_Range := 2;
|
||||
South: constant Y_Range := 1;
|
||||
|
||||
X_Start: constant X_Range := 3; -- start at the upper left
|
||||
Y_Start: constant Y_Range := 1;
|
||||
X_Finish: constant X_Range := X_Size-East; -- go to the lower right
|
||||
Y_Finish: constant Y_Range := Y_Size;
|
||||
|
||||
type Maze_Type is array (Y_Range) of String(X_Range);
|
||||
|
||||
function Solved(X: X_Range; Y: Y_Range) return Boolean is
|
||||
begin
|
||||
return (X = X_Finish) and (Y = Y_Finish);
|
||||
end Solved;
|
||||
|
||||
procedure Output_Maze(M: Maze_Type; Message: String := "") is
|
||||
begin
|
||||
if Message /= "" then
|
||||
Ada.Text_IO.Put_Line(Message);
|
||||
end if;
|
||||
for I in M'Range loop
|
||||
Ada.Text_IO.Put_Line(M(I));
|
||||
end loop;
|
||||
end Output_Maze;
|
||||
|
||||
procedure Search(M: in out Maze_Type; X: X_Range; Y:Y_Range) is
|
||||
begin
|
||||
M(Y)(X) := '*';
|
||||
if Solved(X, Y) then
|
||||
Output_Maze(M, "Solution found!");
|
||||
else
|
||||
if Integer(Y)-South >= 1 and then M(Y-South)(X) = ' ' then
|
||||
Search(M, X, Y-South);
|
||||
end if;
|
||||
if Integer(Y)+South <= Y_Size and then M(Y+South)(X) = ' ' then
|
||||
Search(M, X, Y+South);
|
||||
end if;
|
||||
if Integer(X)-East >= 1 and then M(Y)(X-East) = ' ' then
|
||||
Search(M, X-East, Y);
|
||||
end if;
|
||||
if Integer(Y)+East <= Y_Size and then M(Y)(X+East) = ' ' then
|
||||
Search(M, X+East, Y);
|
||||
end if;
|
||||
end if;
|
||||
M(Y)(X) := ' ';
|
||||
end Search;
|
||||
|
||||
Maze: Maze_Type;
|
||||
X: X_Range := X_Start;
|
||||
Y: Y_Range := Y_Start;
|
||||
|
||||
begin
|
||||
for I in 1 .. Y_Size loop
|
||||
Maze(I) := Ada.Text_IO.Get_Line;
|
||||
end loop;
|
||||
Maze(Y_Start)(X_Start) := ' '; -- Start from
|
||||
Maze(Y_Finish)(X_Finish) := ' '; -- Go_To
|
||||
Output_Maze(Maze, "The Maze:");
|
||||
Ada.Text_IO.New_Line;
|
||||
|
||||
Search(Maze, X, Y) ; -- Will output *all* Solutions.
|
||||
-- If there is no output, there is no solution.
|
||||
end Maze_Solver;
|
||||
185
Task/Maze-solving/AutoHotkey/maze-solving.ahk
Normal file
185
Task/Maze-solving/AutoHotkey/maze-solving.ahk
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
Width := 10, Height := 10 ; set grid size
|
||||
SleepTime := 0
|
||||
|
||||
gosub, Startup
|
||||
|
||||
Gui, +AlwaysOnTop
|
||||
Gui, font, s12, consolas
|
||||
Gui, add, edit, vEditGrid x10, % maze
|
||||
Gui, add, button, xs gStartup Default, Generate maze
|
||||
Gui, add, button, x+10 gSolve, Solve
|
||||
Gui, show,, maze
|
||||
GuiControl,, EditGrid, % maze ; show maze
|
||||
return
|
||||
|
||||
;-----------------------------------------------------------------------
|
||||
^Esc::
|
||||
GuiEscape:
|
||||
GuiClose:
|
||||
ExitApp
|
||||
return
|
||||
|
||||
;-----------------------------------------------------------------------
|
||||
Startup:
|
||||
oMaze := [] ; initialize
|
||||
Solved := false
|
||||
loop, % Height
|
||||
{
|
||||
row := A_Index
|
||||
loop, % Width ; create oMaze[row,column] borders
|
||||
col := A_Index, oMaze[row,col] := "LRTB" ; i.e. oMaze[2,5] := LRTB (add all borders)
|
||||
}
|
||||
Random, row, 1, % Height ; random row
|
||||
Random, col, 1, % Width ; random col
|
||||
grid := maze2text(oMaze) ; object to text
|
||||
GuiControl,, EditGrid, % Grid ; show Grid
|
||||
row := col := 1 ; reset to 1,1
|
||||
oMaze := Generate_maze(row, col, oMaze) ; generate maze starting from random row/column
|
||||
oMaze[1,1] .= "X" ; start from 1,1
|
||||
maze := maze2text(oMaze) ; object to text
|
||||
GuiControl,, EditGrid, % maze ; show maze
|
||||
GuiControl,, EditRoute ; clear route
|
||||
GuiControl, Enable, Solve
|
||||
return
|
||||
|
||||
;-----------------------------------------------------------------------
|
||||
Solve:
|
||||
GuiControl, Disable, Generate maze
|
||||
GuiControl, Disable, Solve
|
||||
loop % oRoute.MaxIndex()
|
||||
oRoute.pop()
|
||||
|
||||
oSolution := Solve(1, 1, oMaze) ; solve starting from 1,1
|
||||
oMaze := oSolution.1
|
||||
oRoute := oSolution.2
|
||||
Update(oMaze, oRoute)
|
||||
Solved := true
|
||||
GuiControl, Enable, Generate maze
|
||||
return
|
||||
|
||||
;-----------------------------------------------------------------------
|
||||
Update(oMaze, oRoute){
|
||||
global SleepTime
|
||||
GuiControl,, EditGrid, % maze2text(oMaze)
|
||||
Sleep, % SleepTime
|
||||
}
|
||||
|
||||
;-----------------------------------------------------------------------
|
||||
maze2text(oMaze){
|
||||
width := oMaze.1.MaxIndex()
|
||||
BLK := "█"
|
||||
for row, objRow in oMaze
|
||||
{
|
||||
for col, val in objRow ; add ceiling
|
||||
{
|
||||
ceiling := InStr(oMaze[row, col] , "x") && InStr(oMaze[row-1, col] , "x") ? "+ " BLK " " : "+ "
|
||||
grid .= (InStr(val, "T") ? "+---" : ceiling) (col = Width ? "+`n" : "")
|
||||
}
|
||||
for col, val in objRow ; add left wall
|
||||
{
|
||||
wall := SubStr(val, 0) = "X" ? BLK : " "
|
||||
grid .= (InStr(val, "L") ? "| " : " ") wall " " (col = Width ? "|`n" : "") ; add left wall if needed then outer right border
|
||||
}
|
||||
}
|
||||
Loop % Width
|
||||
Grid .= "+---" ; add bottom floor
|
||||
Grid .= "+" ; add right bottom corner
|
||||
return RegExReplace(grid , BLK " (?=" BLK ")" , BLK BLK BLK BLK) ; fill gaps
|
||||
}
|
||||
|
||||
;-----------------------------------------------------------------------
|
||||
Generate_maze(row, col, oMaze) {
|
||||
neighbors := row+1 "," col "`n" row-1 "," col "`n" row "," col+1 "`n" row "," col-1
|
||||
Sort, neighbors, random ; randomize neighbors list
|
||||
Loop, parse, neighbors, `n ; for each neighbor
|
||||
{
|
||||
rowX := StrSplit(A_LoopField, ",").1 ; this neighbor row
|
||||
colX := StrSplit(A_LoopField, ",").2 ; this neighbor column
|
||||
if !instr(oMaze[rowX,colX], "LRTB") || !oMaze[rowX, colX] ; if visited (has a missing border) or out of bounds
|
||||
continue ; skip
|
||||
|
||||
; remove borders
|
||||
if (row > rowX) ; Cell is below this neighbor
|
||||
oMaze[row,col] := StrReplace(oMaze[row,col], "T") , oMaze[rowX,colX] := StrReplace(oMaze[rowX,colX], "B")
|
||||
else if (row < rowX) ; Cell is above this neighbor
|
||||
oMaze[row,col] := StrReplace(oMaze[row,col], "B") , oMaze[rowX,colX] := StrReplace(oMaze[rowX,colX], "T")
|
||||
else if (col > colX) ; Cell is right of this neighbor
|
||||
oMaze[row,col] := StrReplace(oMaze[row,col], "L") , oMaze[rowX,colX] := StrReplace(oMaze[rowX,colX], "R")
|
||||
else if (col < colX) ; Cell is left of this neighbor
|
||||
oMaze[row,col] := StrReplace(oMaze[row,col], "R") , oMaze[rowX,colX] := StrReplace(oMaze[rowX,colX], "L")
|
||||
|
||||
Generate_maze(rowX, colX, oMaze) ; recurse for this neighbor
|
||||
}
|
||||
return, oMaze
|
||||
}
|
||||
|
||||
;-----------------------------------------------------------------------
|
||||
Solve(row, col, oMaze){
|
||||
static oRoute := []
|
||||
oNeighbor := [], targetrow := oMaze.MaxIndex(), targetCol := oMaze.1.MaxIndex()
|
||||
|
||||
;~ Update(oMaze, oRoute)
|
||||
oRoute.push(row ":" col) ; push current cell address to oRoute
|
||||
oMaze[row, col] .= "X" ; mark it visited "X"
|
||||
|
||||
if (row = targetrow) && (Col = targetCol) ; if solved
|
||||
return true ; return ture
|
||||
|
||||
; create list of Neighbors
|
||||
oNeighbor[row, col] := []
|
||||
if !InStr(oMaze[row, col], "R") ; if no Right border
|
||||
oNeighbor[row, col].push(row "," col+1) ; add neighbor
|
||||
if !InStr(oMaze[row, col], "B") ; if no Bottom border
|
||||
oNeighbor[row, col].push(row+1 "," col) ; add neighbor
|
||||
if !InStr(oMaze[row, col], "T") ; if no Top border
|
||||
oNeighbor[row, col].push(row-1 "," col) ; add neighbor
|
||||
if !InStr(oMaze[row, col], "L") ; if no Left border
|
||||
oNeighbor[row, col].push(row "," col-1) ; add neighbor
|
||||
|
||||
; recurese for each oNeighbor
|
||||
for each, neighbor in oNeighbor[row, col] ; for each neighbor
|
||||
{
|
||||
Update(oMaze, oRoute)
|
||||
startrow := StrSplit(neighbor, ",").1 ; this neighbor
|
||||
startCol := StrSplit(neighbor, ",").2 ; becomes starting point
|
||||
|
||||
if !InStr(oMaze[startrow, startCol], "X") ; if it was not visited
|
||||
if Solve(startrow, startCol, oMaze) ; recurse for current neighbor
|
||||
return [oMaze, oRoute] ; return solution if solved
|
||||
}
|
||||
oRoute.pop() ; no solution found, back track
|
||||
oMaze[row, Col] := StrReplace(oMaze[row, Col], "X") ; no solution found, back track
|
||||
;~ Update(oMaze, oRoute)
|
||||
}
|
||||
|
||||
;-----------------------------------------------------------------------
|
||||
#IfWinActive, maze
|
||||
Right::
|
||||
Left::
|
||||
Up::
|
||||
Down::
|
||||
if Solved
|
||||
return
|
||||
|
||||
if (A_ThisHotkey="Right") && (!InStr(oMaze[row,col], "R"))
|
||||
oMaze[row, col] := StrReplace(oMaze[row, col], "X") , col++
|
||||
if (A_ThisHotkey="Left") && (!InStr(oMaze[row,col], "L"))
|
||||
oMaze[row, col] := StrReplace(oMaze[row, col], "X") , col--
|
||||
if (A_ThisHotkey="Up") && (!InStr(oMaze[row,col], "T"))
|
||||
oMaze[row, col] := StrReplace(oMaze[row, col], "X") , row--
|
||||
if (A_ThisHotkey="Down") && (!InStr(oMaze[row,col], "B"))
|
||||
oMaze[row, col] := StrReplace(oMaze[row, col], "X") , row++
|
||||
|
||||
oMaze[row, col] .= "X"
|
||||
GuiControl,, EditGrid, % maze2text(oMaze)
|
||||
|
||||
if (col = Width) && (row = Height)
|
||||
{
|
||||
Solved := true
|
||||
oMaze[height, width] := StrReplace(oMaze[height, width], "X")
|
||||
SleepTime := 0
|
||||
gosub, solve
|
||||
return
|
||||
}
|
||||
return
|
||||
#IfWinActive
|
||||
86
Task/Maze-solving/BBC-BASIC/maze-solving.basic
Normal file
86
Task/Maze-solving/BBC-BASIC/maze-solving.basic
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
MazeWidth% = 11
|
||||
MazeHeight% = 9
|
||||
MazeCell% = 50
|
||||
|
||||
VDU 23,22,MazeWidth%*MazeCell%/2+3;MazeHeight%*MazeCell%/2+3;8,16,16,128
|
||||
VDU 23,23,3;0;0;0; : REM Line thickness
|
||||
OFF
|
||||
PROCgeneratemaze(Maze&(), MazeWidth%, MazeHeight%, MazeCell%)
|
||||
PROCsolvemaze(Path{()}, Maze&(), 0, MazeHeight%-1, MazeWidth%-1, 0, MazeCell%)
|
||||
END
|
||||
|
||||
DEF PROCsolvemaze(RETURN s{()}, m&(), x%, y%, dstx%, dsty%, s%)
|
||||
LOCAL h%, i%, n%, p%, q%, w%
|
||||
w% = DIM(m&(),1)
|
||||
h% = DIM(m&(),2)
|
||||
DIM s{(w%*h%) x%,y%}
|
||||
GCOL 3,14
|
||||
m&(x%,y%) OR= &80
|
||||
REPEAT
|
||||
FOR i% = 0 TO 3
|
||||
CASE i% OF
|
||||
WHEN 0: p% = x%-1 : q% = y%
|
||||
WHEN 1: p% = x%+1 : q% = y%
|
||||
WHEN 2: p% = x% : q% = y%-1
|
||||
WHEN 3: p% = x% : q% = y%+1
|
||||
ENDCASE
|
||||
IF p% >= 0 IF p% < w% IF q% >= 0 IF q% < h% IF m&(p%,q%) < &80 THEN
|
||||
IF p% > x% IF m&(p%,q%) AND 1 EXIT FOR
|
||||
IF q% > y% IF m&(p%,q%) AND 2 EXIT FOR
|
||||
IF x% > p% IF m&(x%,y%) AND 1 EXIT FOR
|
||||
IF y% > q% IF m&(x%,y%) AND 2 EXIT FOR
|
||||
ENDIF
|
||||
NEXT
|
||||
IF i% < 4 THEN
|
||||
m&(p%,q%) OR= &80
|
||||
s{(n%)}.x% = x%
|
||||
s{(n%)}.y% = y%
|
||||
n% += 1
|
||||
ELSE
|
||||
IF n% > 0 THEN
|
||||
n% -= 1
|
||||
p% = s{(n%)}.x%
|
||||
q% = s{(n%)}.y%
|
||||
ENDIF
|
||||
ENDIF
|
||||
LINE (x%+0.5)*s%,(y%+0.5)*s%,(p%+0.5)*s%,(q%+0.5)*s%
|
||||
x% = p%
|
||||
y% = q%
|
||||
UNTIL x%=dstx% AND y%=dsty%
|
||||
s{(n%)}.x% = x%
|
||||
s{(n%)}.y% = y%
|
||||
ENDPROC
|
||||
|
||||
DEF PROCgeneratemaze(RETURN m&(), w%, h%, s%)
|
||||
LOCAL x%, y%
|
||||
DIM m&(w%, h%)
|
||||
FOR y% = 0 TO h%
|
||||
LINE 0,y%*s%,w%*s%,y%*s%
|
||||
NEXT
|
||||
FOR x% = 0 TO w%
|
||||
LINE x%*s%,0,x%*s%,h%*s%
|
||||
NEXT
|
||||
GCOL 15
|
||||
PROCcell(m&(), RND(w%)-1, y% = RND(h%)-1, w%, h%, s%)
|
||||
ENDPROC
|
||||
|
||||
DEF PROCcell(m&(), x%, y%, w%, h%, s%)
|
||||
LOCAL i%, p%, q%, r%
|
||||
m&(x%,y%) OR= &40 : REM Mark visited
|
||||
r% = RND(4)
|
||||
FOR i% = r% TO r%+3
|
||||
CASE i% MOD 4 OF
|
||||
WHEN 0: p% = x%-1 : q% = y%
|
||||
WHEN 1: p% = x%+1 : q% = y%
|
||||
WHEN 2: p% = x% : q% = y%-1
|
||||
WHEN 3: p% = x% : q% = y%+1
|
||||
ENDCASE
|
||||
IF p% >= 0 IF p% < w% IF q% >= 0 IF q% < h% IF m&(p%,q%) < &40 THEN
|
||||
IF p% > x% m&(p%,q%) OR= 1 : LINE p%*s%,y%*s%+4,p%*s%,(y%+1)*s%-4
|
||||
IF q% > y% m&(p%,q%) OR= 2 : LINE x%*s%+4,q%*s%,(x%+1)*s%-4,q%*s%
|
||||
IF x% > p% m&(x%,y%) OR= 1 : LINE x%*s%,y%*s%+4,x%*s%,(y%+1)*s%-4
|
||||
IF y% > q% m&(x%,y%) OR= 2 : LINE x%*s%+4,y%*s%,(x%+1)*s%-4,y%*s%
|
||||
PROCcell(m&(), p%, q%, w%, h%, s%)
|
||||
ENDIF
|
||||
NEXT
|
||||
ENDPROC
|
||||
436
Task/Maze-solving/C++/maze-solving.cpp
Normal file
436
Task/Maze-solving/C++/maze-solving.cpp
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
using namespace std;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const int BMP_SIZE = 512, CELL_SIZE = 8;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
enum directions { NONE, NOR = 1, EAS = 2, SOU = 4, WES = 8 };
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
class myBitmap
|
||||
{
|
||||
public:
|
||||
myBitmap() : pen( NULL ) {}
|
||||
~myBitmap()
|
||||
{
|
||||
DeleteObject( pen );
|
||||
DeleteDC( hdc );
|
||||
DeleteObject( bmp );
|
||||
}
|
||||
|
||||
bool create( int w, int h )
|
||||
{
|
||||
BITMAPINFO bi;
|
||||
ZeroMemory( &bi, sizeof( bi ) );
|
||||
bi.bmiHeader.biSize = sizeof( bi.bmiHeader );
|
||||
bi.bmiHeader.biBitCount = sizeof( DWORD ) * 8;
|
||||
bi.bmiHeader.biCompression = BI_RGB;
|
||||
bi.bmiHeader.biPlanes = 1;
|
||||
bi.bmiHeader.biWidth = w;
|
||||
bi.bmiHeader.biHeight = -h;
|
||||
|
||||
HDC dc = GetDC( GetConsoleWindow() );
|
||||
bmp = CreateDIBSection( dc, &bi, DIB_RGB_COLORS, &pBits, NULL, 0 );
|
||||
if( !bmp ) return false;
|
||||
|
||||
hdc = CreateCompatibleDC( dc );
|
||||
SelectObject( hdc, bmp );
|
||||
ReleaseDC( GetConsoleWindow(), dc );
|
||||
width = w; height = h;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
ZeroMemory( pBits, width * height * sizeof( DWORD ) );
|
||||
}
|
||||
|
||||
void setPenColor( DWORD clr )
|
||||
{
|
||||
if( pen ) DeleteObject( pen );
|
||||
pen = CreatePen( PS_SOLID, 1, clr );
|
||||
SelectObject( hdc, pen );
|
||||
}
|
||||
|
||||
void saveBitmap( string path )
|
||||
{
|
||||
BITMAPFILEHEADER fileheader;
|
||||
BITMAPINFO infoheader;
|
||||
BITMAP bitmap;
|
||||
DWORD wb;
|
||||
|
||||
GetObject( bmp, sizeof( bitmap ), &bitmap );
|
||||
|
||||
DWORD* dwpBits = new DWORD[bitmap.bmWidth * bitmap.bmHeight];
|
||||
ZeroMemory( dwpBits, bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD ) );
|
||||
ZeroMemory( &infoheader, sizeof( BITMAPINFO ) );
|
||||
ZeroMemory( &fileheader, sizeof( BITMAPFILEHEADER ) );
|
||||
|
||||
infoheader.bmiHeader.biBitCount = sizeof( DWORD ) * 8;
|
||||
infoheader.bmiHeader.biCompression = BI_RGB;
|
||||
infoheader.bmiHeader.biPlanes = 1;
|
||||
infoheader.bmiHeader.biSize = sizeof( infoheader.bmiHeader );
|
||||
infoheader.bmiHeader.biHeight = bitmap.bmHeight;
|
||||
infoheader.bmiHeader.biWidth = bitmap.bmWidth;
|
||||
infoheader.bmiHeader.biSizeImage = bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD );
|
||||
|
||||
fileheader.bfType = 0x4D42;
|
||||
fileheader.bfOffBits = sizeof( infoheader.bmiHeader ) + sizeof( BITMAPFILEHEADER );
|
||||
fileheader.bfSize = fileheader.bfOffBits + infoheader.bmiHeader.biSizeImage;
|
||||
|
||||
GetDIBits( hdc, bmp, 0, height, ( LPVOID )dwpBits, &infoheader, DIB_RGB_COLORS );
|
||||
|
||||
HANDLE file = CreateFile( path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
|
||||
WriteFile( file, &fileheader, sizeof( BITMAPFILEHEADER ), &wb, NULL );
|
||||
WriteFile( file, &infoheader.bmiHeader, sizeof( infoheader.bmiHeader ), &wb, NULL );
|
||||
WriteFile( file, dwpBits, bitmap.bmWidth * bitmap.bmHeight * 4, &wb, NULL );
|
||||
CloseHandle( file );
|
||||
|
||||
delete [] dwpBits;
|
||||
}
|
||||
|
||||
HDC getDC() const { return hdc; }
|
||||
int getWidth() const { return width; }
|
||||
int getHeight() const { return height; }
|
||||
|
||||
private:
|
||||
HBITMAP bmp;
|
||||
HDC hdc;
|
||||
HPEN pen;
|
||||
void *pBits;
|
||||
int width, height;
|
||||
};
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
class mazeGenerator
|
||||
{
|
||||
public:
|
||||
mazeGenerator()
|
||||
{
|
||||
_world = 0;
|
||||
_bmp.create( BMP_SIZE, BMP_SIZE );
|
||||
_bmp.setPenColor( RGB( 0, 255, 0 ) );
|
||||
}
|
||||
|
||||
~mazeGenerator() { killArray(); }
|
||||
|
||||
BYTE* getMaze() const { return _world; }
|
||||
|
||||
void create( int side )
|
||||
{
|
||||
_s = side;
|
||||
generate();
|
||||
}
|
||||
|
||||
private:
|
||||
void generate()
|
||||
{
|
||||
killArray();
|
||||
_world = new BYTE[_s * _s];
|
||||
ZeroMemory( _world, _s * _s );
|
||||
_ptX = rand() % _s; _ptY = rand() % _s;
|
||||
carve();
|
||||
}
|
||||
|
||||
void carve()
|
||||
{
|
||||
while( true )
|
||||
{
|
||||
int d = getDirection();
|
||||
if( d < NOR ) return;
|
||||
|
||||
switch( d )
|
||||
{
|
||||
case NOR:
|
||||
_world[_ptX + _s * _ptY] |= NOR; _ptY--;
|
||||
_world[_ptX + _s * _ptY] = SOU | SOU << 4;
|
||||
break;
|
||||
case EAS:
|
||||
_world[_ptX + _s * _ptY] |= EAS; _ptX++;
|
||||
_world[_ptX + _s * _ptY] = WES | WES << 4;
|
||||
break;
|
||||
case SOU:
|
||||
_world[_ptX + _s * _ptY] |= SOU; _ptY++;
|
||||
_world[_ptX + _s * _ptY] = NOR | NOR << 4;
|
||||
break;
|
||||
case WES:
|
||||
_world[_ptX + _s * _ptY] |= WES; _ptX--;
|
||||
_world[_ptX + _s * _ptY] = EAS | EAS << 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int getDirection()
|
||||
{
|
||||
int d = 1 << rand() % 4;
|
||||
while( true )
|
||||
{
|
||||
for( int x = 0; x < 4; x++ )
|
||||
{
|
||||
if( testDir( d ) ) return d;
|
||||
d <<= 1;
|
||||
if( d > 8 ) d = 1;
|
||||
}
|
||||
d = ( _world[_ptX + _s * _ptY] & 0xf0 ) >> 4;
|
||||
if( !d ) return -1;
|
||||
switch( d )
|
||||
{
|
||||
case NOR: _ptY--; break;
|
||||
case EAS: _ptX++; break;
|
||||
case SOU: _ptY++; break;
|
||||
case WES: _ptX--; break;
|
||||
}
|
||||
|
||||
d = 1 << rand() % 4;
|
||||
}
|
||||
}
|
||||
|
||||
bool testDir( int d )
|
||||
{
|
||||
switch( d )
|
||||
{
|
||||
case NOR: return ( _ptY - 1 > -1 && !_world[_ptX + _s * ( _ptY - 1 )] );
|
||||
case EAS: return ( _ptX + 1 < _s && !_world[_ptX + 1 + _s * _ptY] );
|
||||
case SOU: return ( _ptY + 1 < _s && !_world[_ptX + _s * ( _ptY + 1 )] );
|
||||
case WES: return ( _ptX - 1 > -1 && !_world[_ptX - 1 + _s * _ptY] );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void killArray() { if( _world ) delete [] _world; }
|
||||
|
||||
BYTE* _world;
|
||||
int _s, _ptX, _ptY;
|
||||
myBitmap _bmp;
|
||||
};
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
class mazeSolver
|
||||
{
|
||||
public:
|
||||
mazeSolver()
|
||||
{
|
||||
_bmp.create( BMP_SIZE, BMP_SIZE );
|
||||
_pts = 0;
|
||||
}
|
||||
|
||||
~mazeSolver() { killPoints(); }
|
||||
|
||||
void solveIt( BYTE* maze, int size, int sX, int sY, int eX, int eY )
|
||||
{
|
||||
_lastDir = NONE;
|
||||
_world = maze; _s = size; _sx = sX; _sy = sY; _ex = eX; _ey = eY;
|
||||
|
||||
for( int y = 0; y < _s; y++ )
|
||||
for( int x = 0; x < _s; x++ )
|
||||
_world[x + _s * y] &= 0x0f;
|
||||
|
||||
_world[_sx + _s * _sy] |= NOR << 4;
|
||||
|
||||
killPoints();
|
||||
_pts = new BYTE[_s * _s];
|
||||
ZeroMemory( _pts, _s * _s );
|
||||
|
||||
findTheWay();
|
||||
|
||||
_sx = sX; _sy = sY;
|
||||
display();
|
||||
}
|
||||
|
||||
private:
|
||||
int invert( int d )
|
||||
{
|
||||
switch( d )
|
||||
{
|
||||
case NOR: return SOU;
|
||||
case SOU: return NOR;
|
||||
case WES: return EAS;
|
||||
case EAS: return WES;
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
|
||||
void updatePosition( int d )
|
||||
{
|
||||
switch( d )
|
||||
{
|
||||
case NOR: _sy--; break;
|
||||
case EAS: _sx++; break;
|
||||
case SOU: _sy++; break;
|
||||
case WES: _sx--;
|
||||
}
|
||||
}
|
||||
|
||||
void findTheWay()
|
||||
{
|
||||
while( true )
|
||||
{
|
||||
int d = getDirection();
|
||||
if( d < NOR ) return;
|
||||
_lastDir = invert( d );
|
||||
_world[_sx + _s * _sy] |= d;
|
||||
_pts[_sx + _s * _sy] = d;
|
||||
updatePosition( d );
|
||||
if( _sx == _ex && _sy == _ey ) return;
|
||||
_world[_sx + _s * _sy] |= _lastDir << 4;
|
||||
}
|
||||
}
|
||||
|
||||
int getDirection()
|
||||
{
|
||||
int d = 1 << rand() % 4;
|
||||
while( true )
|
||||
{
|
||||
for( int x = 0; x < 4; x++ )
|
||||
{
|
||||
if( testDirection( d ) ) return d;
|
||||
d <<= 1;
|
||||
if( d > 8 ) d = 1;
|
||||
}
|
||||
|
||||
d = ( _world[_sx + _s * _sy] & 0xf0 ) >> 4;
|
||||
if( !d ) return -1;
|
||||
_pts[_sx + _s * _sy] = 0;
|
||||
updatePosition( d );
|
||||
_lastDir = invert( d );
|
||||
d = 1 << rand() % 4;
|
||||
}
|
||||
}
|
||||
|
||||
bool testDirection( int d )
|
||||
{
|
||||
if( d == _lastDir || !( _world[_sx + _s * _sy] & d ) ) return false;
|
||||
switch( d )
|
||||
{
|
||||
case NOR:
|
||||
return _sy - 1 > -1 && !( _world[_sx + _s * ( _sy - 1 )] & 0xf0 );
|
||||
case EAS:
|
||||
return _sx + 1 < _s && !( _world[_sx + 1 + _s * _sy] & 0xf0 );
|
||||
case SOU:
|
||||
return _sy + 1 < _s && !( _world[_sx + _s * ( _sy + 1 )] & 0xf0 );
|
||||
case WES:
|
||||
return _sx - 1 > -1 && !( _world[_sx - 1 + _s * _sy] & 0xf0 );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void display()
|
||||
{
|
||||
_bmp.setPenColor( RGB( 0, 255, 0 ) );
|
||||
_bmp.clear();
|
||||
HDC dc = _bmp.getDC();
|
||||
for( int y = 0; y < _s; y++ )
|
||||
{
|
||||
int yy = y * _s;
|
||||
for( int x = 0; x < _s; x++ )
|
||||
{
|
||||
BYTE b = _world[x + yy];
|
||||
int nx = x * CELL_SIZE,
|
||||
ny = y * CELL_SIZE;
|
||||
|
||||
if( !( b & NOR ) )
|
||||
{
|
||||
MoveToEx( dc, nx, ny, NULL );
|
||||
LineTo( dc, nx + CELL_SIZE + 1, ny );
|
||||
}
|
||||
if( !( b & EAS ) )
|
||||
{
|
||||
MoveToEx( dc, nx + CELL_SIZE, ny, NULL );
|
||||
LineTo( dc, nx + CELL_SIZE, ny + CELL_SIZE + 1 );
|
||||
}
|
||||
if( !( b & SOU ) )
|
||||
{
|
||||
MoveToEx( dc, nx, ny + CELL_SIZE, NULL );
|
||||
LineTo( dc, nx + CELL_SIZE + 1, ny + CELL_SIZE );
|
||||
}
|
||||
if( !( b & WES ) )
|
||||
{
|
||||
MoveToEx( dc, nx, ny, NULL );
|
||||
LineTo( dc, nx, ny + CELL_SIZE + 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawEndPoints( dc );
|
||||
_bmp.setPenColor( RGB( 255, 0, 0 ) );
|
||||
|
||||
for( int y = 0; y < _s; y++ )
|
||||
{
|
||||
int yy = y * _s;
|
||||
for( int x = 0; x < _s; x++ )
|
||||
{
|
||||
BYTE d = _pts[x + yy];
|
||||
if( !d ) continue;
|
||||
|
||||
int nx = x * CELL_SIZE + 4,
|
||||
ny = y * CELL_SIZE + 4;
|
||||
|
||||
MoveToEx( dc, nx, ny, NULL );
|
||||
switch( d )
|
||||
{
|
||||
case NOR: LineTo( dc, nx, ny - CELL_SIZE - 1 ); break;
|
||||
case EAS: LineTo( dc, nx + CELL_SIZE + 1, ny ); break;
|
||||
case SOU: LineTo( dc, nx, ny + CELL_SIZE + 1 ); break;
|
||||
case WES: LineTo( dc, nx - CELL_SIZE - 1, ny ); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_bmp.saveBitmap( "f:\\rc\\maze_s.bmp" );
|
||||
BitBlt( GetDC( GetConsoleWindow() ), 10, 60, BMP_SIZE, BMP_SIZE, _bmp.getDC(), 0, 0, SRCCOPY );
|
||||
}
|
||||
|
||||
void drawEndPoints( HDC dc )
|
||||
{
|
||||
RECT rc;
|
||||
int x = 1 + _sx * CELL_SIZE, y = 1 + _sy * CELL_SIZE;
|
||||
SetRect( &rc, x, y, x + CELL_SIZE - 1, y + CELL_SIZE - 1 );
|
||||
FillRect( dc, &rc, ( HBRUSH )GetStockObject( WHITE_BRUSH ) );
|
||||
x = 1 + _ex * CELL_SIZE, y = 1 + _ey * CELL_SIZE;
|
||||
SetRect( &rc, x, y, x + CELL_SIZE - 1, y + CELL_SIZE - 1 );
|
||||
FillRect( dc, &rc, ( HBRUSH )GetStockObject( WHITE_BRUSH ) );
|
||||
}
|
||||
|
||||
void killPoints() { if( _pts ) delete [] _pts; }
|
||||
|
||||
BYTE* _world, *_pts;
|
||||
int _s, _sx, _sy, _ex, _ey, _lastDir;
|
||||
myBitmap _bmp;
|
||||
};
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
ShowWindow( GetConsoleWindow(), SW_MAXIMIZE );
|
||||
srand( GetTickCount() );
|
||||
|
||||
mazeGenerator mg;
|
||||
mazeSolver ms;
|
||||
int s;
|
||||
while( true )
|
||||
{
|
||||
cout << "Enter the maze size, an odd number bigger than 2 ( 0 to QUIT ): "; cin >> s;
|
||||
if( !s ) return 0;
|
||||
if( !( s & 1 ) ) s++;
|
||||
if( s >= 3 )
|
||||
{
|
||||
mg.create( s );
|
||||
int sx, sy, ex, ey;
|
||||
while( true )
|
||||
{
|
||||
sx = rand() % s; sy = rand() % s;
|
||||
ex = rand() % s; ey = rand() % s;
|
||||
if( ex != sx || ey != sy ) break;
|
||||
}
|
||||
ms.solveIt( mg.getMaze(), s, sx, sy, ex, ey );
|
||||
cout << endl;
|
||||
}
|
||||
system( "pause" );
|
||||
system( "cls" );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
106
Task/Maze-solving/Clojure/maze-solving.clj
Normal file
106
Task/Maze-solving/Clojure/maze-solving.clj
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
(ns small-projects.find-shortest-way
|
||||
(:require [clojure.string :as str]))
|
||||
|
||||
;Misk functions
|
||||
(defn cell-empty? [maze coords]
|
||||
(= :empty (get-in maze coords)))
|
||||
|
||||
(defn wall? [maze coords]
|
||||
(= :wall (get-in maze coords)))
|
||||
|
||||
(defn track? [maze coords]
|
||||
(= :track (get-in maze coords)))
|
||||
|
||||
(defn get-neighbours [maze [y x cell]]
|
||||
[[y (dec x)] [(inc y) x] [y (inc x)] [(dec y) x]])
|
||||
|
||||
(defn get-difference [coll1 filter-coll]
|
||||
(filter #(not (contains? filter-coll %)) coll1))
|
||||
|
||||
(defn get-empties [maze cell]
|
||||
(->> (get-neighbours maze cell)
|
||||
(filter (partial cell-empty? maze))))
|
||||
|
||||
(defn possible-ways [maze cell filter-coll]
|
||||
(-> (get-empties maze cell)
|
||||
(get-difference filter-coll)))
|
||||
|
||||
(defn replace-cells [maze coords v]
|
||||
(if (empty? coords)
|
||||
maze
|
||||
(recur (assoc-in maze (first coords) v) (rest coords) v)))
|
||||
|
||||
;Print and parse functions
|
||||
(def cell-code->str
|
||||
[" " " " " " " " "· " "╵ " "╴ " "┘ "
|
||||
" " " " " " " " "╶─" "└─" "──" "┴─"
|
||||
" " " " " " " " "╷ " "│ " "┐ " "┤ "
|
||||
" " " " " " " " "┌─" "├─" "┬─" "┼─"
|
||||
" " " " " " " " "■ " "╹ " "╸ " "┛ "
|
||||
" " " " " " " " "╺━" "┗━" "━━" "┻━"
|
||||
" " " " " " " " "╻ " "┃ " "┓ " "┫ "
|
||||
" " " " " " " " "┏━" "┣━" "┳━" "╋━"
|
||||
" "])
|
||||
|
||||
(defn get-cell-code [maze coords]
|
||||
(let [mode (if (track? maze coords) 1 0)
|
||||
check (if (zero? mode) wall? track?)]
|
||||
(transduce
|
||||
(comp
|
||||
(map (partial check maze))
|
||||
(keep-indexed (fn [idx test] (when test idx)))
|
||||
(map (partial bit-shift-left 1)))
|
||||
(completing bit-or)
|
||||
(bit-shift-left mode 5)
|
||||
(sort (conj (get-neighbours maze coords) coords)))))
|
||||
|
||||
(defn code->str [cell-code]
|
||||
(nth cell-code->str cell-code))
|
||||
|
||||
(defn maze->str-symbols [maze]
|
||||
(for [y (range (count maze))]
|
||||
(for [x (range (count (nth maze y)))]
|
||||
(code->str (get-cell-code maze [y x])))))
|
||||
|
||||
(defn maze->str [maze]
|
||||
(->> (maze->str-symbols maze)
|
||||
(map str/join)
|
||||
(str/join "\n")))
|
||||
|
||||
(defn parse-pretty-maze [maze-str]
|
||||
(->> (str/split-lines maze-str)
|
||||
(map (partial take-nth 2))
|
||||
(map (partial map #(if (= \space %) :empty :wall)))
|
||||
(map vec)
|
||||
(vec)))
|
||||
|
||||
;Core
|
||||
(defn find-new-border [maze border old-border]
|
||||
(apply conj (map (fn [cell]
|
||||
(zipmap (possible-ways maze cell (conj border old-border))
|
||||
(repeat cell)))
|
||||
(keys border))))
|
||||
|
||||
(defn backtrack [visited route]
|
||||
(let [cur-cell (get visited (first route))]
|
||||
(if (= cur-cell :start)
|
||||
route
|
||||
(recur visited (conj route cur-cell)))))
|
||||
|
||||
(defn breadth-first-search [maze start-cell end-cell]
|
||||
(loop [visited {start-cell :start}
|
||||
border {start-cell :start}
|
||||
old-border {start-cell :start}]
|
||||
(if (contains? old-border end-cell)
|
||||
(backtrack visited (list end-cell))
|
||||
(recur
|
||||
(conj visited border)
|
||||
(find-new-border maze border old-border)
|
||||
border))))
|
||||
|
||||
(def maze (parse-pretty-maze maze-str))
|
||||
|
||||
(def solved-maze
|
||||
(replace-cells maze (breadth-first-search maze [1 1] [19 19]) :track))
|
||||
|
||||
(println (maze->str solved-maze))
|
||||
42
Task/Maze-solving/D/maze-solving.d
Normal file
42
Task/Maze-solving/D/maze-solving.d
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import std.stdio, std.random, std.string, std.array, std.algorithm,
|
||||
std.file, std.conv;
|
||||
|
||||
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 @safe @nogc {
|
||||
if (s == end)
|
||||
return true;
|
||||
|
||||
foreach (immutable d; [V2(0, -cy), V2(+cx, 0), V2(0, +cy), V2(-cx, 0)])
|
||||
if (maze[s.y + (d.y / 2)][s.x + (d.x / 2)] == ' ' &&
|
||||
maze[s.y + d.y][s.x + d.x] == ' ') {
|
||||
//Would this help?
|
||||
// maze[s.y + (d.y / 2)][s.x + (d.x / 2)] = pathSymbol;
|
||||
maze[s.y + d.y][s.x + d.x] = pathSymbol;
|
||||
if (solveMaze(maze, V2(s.x + d.x, s.y + d.y), end))
|
||||
return true;
|
||||
maze[s.y + d.y][s.x + d.x] = ' ';
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void main() {
|
||||
auto maze = "maze.txt".File.byLine.map!(r => r.chomp.dup).array;
|
||||
immutable h = (maze.length.signed - 1) / cy;
|
||||
assert (h > 0);
|
||||
immutable w = (maze[0].length.signed - 1) / cx;
|
||||
|
||||
immutable start = V2(cx2 + cx * uniform(0, w), cy2 + cy * uniform(0, h));
|
||||
immutable end = V2(cx2 + cx * uniform(0, w), cy2 + cy * uniform(0, h));
|
||||
|
||||
maze[start.y][start.x] = pathSymbol;
|
||||
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);
|
||||
}
|
||||
55
Task/Maze-solving/Delphi/maze-solving.delphi
Normal file
55
Task/Maze-solving/Delphi/maze-solving.delphi
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
procedure SolveMaze(var AMaze: TMaze; const S, E: TPoint);
|
||||
var
|
||||
Route : TRoute;
|
||||
Position : TPoint;
|
||||
V : TPoint; // delta vector
|
||||
begin
|
||||
ClearVisited(AMaze);
|
||||
Position := S;
|
||||
Route := TStack<TPoint>.Create;
|
||||
with Position do
|
||||
try
|
||||
AMaze[x, y].Visited := True;
|
||||
repeat
|
||||
if (y > 0) and not AMaze[x, y-1].Visited and AMaze[x, y].PassTop then V := Point(0, -1) else
|
||||
if (x < mwidth-1) and not AMaze[x+1, y].Visited and AMaze[x+1, y].PassLeft then V := Point(1, 0) else
|
||||
if (y < mheight-1) and not AMaze[x, y+1].Visited and AMaze[x, y+1].PassTop then V := Point(0, 1) else
|
||||
if (x > 0) and not AMaze[x-1, y].Visited and AMaze[x, y].PassLeft then V := Point(-1, 0) else
|
||||
begin
|
||||
if Route.Count = 0 then Exit; // we are back at start so no way found
|
||||
Position := Route.Pop; // step back
|
||||
Continue;
|
||||
end;
|
||||
|
||||
Route.Push(Position); // save current position to route
|
||||
Offset(V); // move forward
|
||||
AMaze[x, y].Visited := True;
|
||||
until Position = E; // solved
|
||||
|
||||
ClearVisited(AMaze);
|
||||
while Route.Count > 0 do // Route to Maze
|
||||
with Route.Pop do
|
||||
AMaze[x, y].Visited := True;
|
||||
|
||||
finally
|
||||
Route.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure Main;
|
||||
var
|
||||
Maze: TMaze;
|
||||
S, E: TPoint;
|
||||
begin
|
||||
Randomize;
|
||||
PrepareMaze(Maze);
|
||||
S := Point(Random(mwidth), Random(mheight));
|
||||
E := Point(Random(mwidth), Random(mheight));
|
||||
SolveMaze(Maze, S, E);
|
||||
Write(MazeToString(Maze, S, E));
|
||||
ReadLn;
|
||||
end;
|
||||
|
||||
begin
|
||||
Main;
|
||||
end.
|
||||
262
Task/Maze-solving/EGL/maze-solving.egl
Normal file
262
Task/Maze-solving/EGL/maze-solving.egl
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
program MazeGenAndSolve
|
||||
|
||||
// First and last columns/rows are "dead" cells. Makes generating
|
||||
// a maze with border walls much easier. Therefore, a visible
|
||||
// 20x20 maze has a maze size of 22.
|
||||
mazeSize int = 22;
|
||||
|
||||
south boolean[][];
|
||||
west boolean[][];
|
||||
visited boolean[][];
|
||||
|
||||
// Solution variables
|
||||
solution Dictionary;
|
||||
done boolean;
|
||||
startingRow, startingCol, endingRow, endingCol int;
|
||||
|
||||
function main()
|
||||
initMaze();
|
||||
generateMaze();
|
||||
drawMaze(false); // Draw maze without solution
|
||||
|
||||
solveMaze();
|
||||
drawMaze(true); // Draw maze with solution
|
||||
end
|
||||
|
||||
private function initMaze()
|
||||
|
||||
visited = createBooleanArray(mazeSize, mazeSize, false);
|
||||
|
||||
// Initialize border cells as already visited
|
||||
for(col int from 1 to mazeSize)
|
||||
visited[col][1] = true;
|
||||
visited[col][mazeSize] = true;
|
||||
end
|
||||
for(row int from 1 to mazeSize)
|
||||
visited[1][row] = true;
|
||||
visited[mazeSize][row] = true;
|
||||
end
|
||||
|
||||
// Initialize all walls as present
|
||||
south = createBooleanArray(mazeSize, mazeSize, true);
|
||||
west = createBooleanArray(mazeSize, mazeSize, true);
|
||||
|
||||
end
|
||||
|
||||
private function createBooleanArray(col int in, row int in, initialState boolean in) returns(boolean[][])
|
||||
|
||||
newArray boolean[][] = new boolean[0][0];
|
||||
|
||||
for(i int from 1 to col)
|
||||
innerArray boolean[] = new boolean[0];
|
||||
for(j int from 1 to row)
|
||||
innerArray.appendElement(initialState);
|
||||
end
|
||||
newArray.appendElement(innerArray);
|
||||
end
|
||||
|
||||
return(newArray);
|
||||
|
||||
end
|
||||
|
||||
private function createIntegerArray(col int in, row int in, initialValue int in) returns(int[][])
|
||||
|
||||
newArray int[][] = new int[0][0];
|
||||
|
||||
for(i int from 1 to col)
|
||||
innerArray int[] = new int[0];
|
||||
for(j int from 1 to row)
|
||||
innerArray.appendElement(initialValue);
|
||||
end
|
||||
newArray.appendElement(innerArray);
|
||||
end
|
||||
|
||||
return(newArray);
|
||||
|
||||
end
|
||||
|
||||
private function generate(col int in, row int in)
|
||||
|
||||
// Mark cell as visited
|
||||
visited[col][row] = true;
|
||||
|
||||
// Keep going as long as there is an unvisited neighbor
|
||||
while(!visited[col][row + 1] || !visited[col + 1][row] ||
|
||||
!visited[col][row - 1] || !visited[col - 1][row])
|
||||
|
||||
while(true)
|
||||
r float = MathLib.random(); // Choose a random direction
|
||||
|
||||
case
|
||||
when(r < 0.25 && !visited[col][row + 1]) // Go south
|
||||
south[col][row] = false; // South wall down
|
||||
generate(col, row + 1);
|
||||
exit while;
|
||||
when(r >= 0.25 && r < 0.50 && !visited[col + 1][row]) // Go east
|
||||
west[col + 1][row] = false; // West wall of neighbor to the east down
|
||||
generate(col + 1, row);
|
||||
exit while;
|
||||
when(r >= 0.5 && r < 0.75 && !visited[col][row - 1]) // Go north
|
||||
south[col][row - 1] = false; // South wall of neighbor to the north down
|
||||
generate(col, row - 1);
|
||||
exit while;
|
||||
when(r >= 0.75 && r < 1.00 && !visited[col - 1][row]) // Go west
|
||||
west[col][row] = false; // West wall down
|
||||
generate(col - 1, row);
|
||||
exit while;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
private function generateMaze()
|
||||
|
||||
// Pick random start position (within the visible maze space)
|
||||
randomStartCol int = MathLib.floor((MathLib.random() *(mazeSize - 2)) + 2);
|
||||
randomStartRow int = MathLib.floor((MathLib.random() *(mazeSize - 2)) + 2);
|
||||
|
||||
generate(randomStartCol, randomStartRow);
|
||||
|
||||
end
|
||||
|
||||
private function drawMaze(solve boolean in)
|
||||
|
||||
line string;
|
||||
|
||||
// Iterate over wall arrays (skipping dead border cells as required).
|
||||
// Construct a row at a time and output to console.
|
||||
for(row int from 1 to mazeSize - 1)
|
||||
|
||||
if(row > 1)
|
||||
line = "";
|
||||
for(col int from 2 to mazeSize)
|
||||
if(west[col][row])
|
||||
line ::= cellTest(col, row, solve);
|
||||
else
|
||||
line ::= cellTest(col, row, solve);
|
||||
end
|
||||
end
|
||||
Syslib.writeStdout(line);
|
||||
end
|
||||
|
||||
line = "";
|
||||
for(col int from 2 to mazeSize - 1)
|
||||
if(south[col][row])
|
||||
line ::= "+---";
|
||||
else
|
||||
line ::= "+ ";
|
||||
end
|
||||
end
|
||||
line ::= "+";
|
||||
SysLib.writeStdout(line);
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
private function cellTest(col int in, row int in, solve boolean in) returns(string)
|
||||
|
||||
wall string;
|
||||
|
||||
// Determine cell wall structure. If in solve mode, show start, end and
|
||||
// solution markers.
|
||||
if(!solve)
|
||||
if(west[col][row])
|
||||
wall = "| ";
|
||||
else
|
||||
wall = " ";
|
||||
end
|
||||
else
|
||||
if(west[col][row])
|
||||
|
||||
case
|
||||
when(col == startingCol and row == startingRow)
|
||||
wall = "| S ";
|
||||
when(col == endingCol and row == endingRow)
|
||||
wall = "| E ";
|
||||
when(solution.containsKey("x=" + col + "y=" + row))
|
||||
wall = "| * ";
|
||||
otherwise
|
||||
wall = "| ";
|
||||
end
|
||||
|
||||
else
|
||||
case
|
||||
when(col == startingCol and row == startingRow)
|
||||
wall = " S ";
|
||||
when(col == endingCol and row == endingRow)
|
||||
wall = " E ";
|
||||
when(solution.containsKey("x=" + col + "y=" + row))
|
||||
wall = " * ";
|
||||
otherwise
|
||||
wall = " ";
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return(wall);
|
||||
end
|
||||
|
||||
private function solve(col int in, row int in)
|
||||
|
||||
if(col == 1 || row == 1 || col == mazeSize || row == mazeSize)
|
||||
return;
|
||||
end
|
||||
|
||||
if(done || visited[col][row])
|
||||
return;
|
||||
end
|
||||
|
||||
visited[col][row] = true;
|
||||
|
||||
solution["x=" + col + "y=" + row] = true;
|
||||
|
||||
// Reached the end point
|
||||
if(col == endingCol && row == endingRow)
|
||||
done = true;
|
||||
end
|
||||
|
||||
if(!south[col][row]) // Go South
|
||||
solve(col, row + 1);
|
||||
end
|
||||
if(!west[col + 1][row]) // Go East
|
||||
solve(col + 1, row);
|
||||
end
|
||||
if(!south[col][row - 1]) // Go North
|
||||
solve(col, row - 1);
|
||||
end
|
||||
if(!west[col][row]) // Go West
|
||||
solve(col - 1, row);
|
||||
end
|
||||
|
||||
if(done)
|
||||
return;
|
||||
end
|
||||
|
||||
solution.removeElement("x=" + col + "y=" + row);
|
||||
|
||||
end
|
||||
|
||||
private function solveMaze()
|
||||
for(col int from 1 to mazeSize)
|
||||
for(row int from 1 to mazeSize)
|
||||
visited[col][row] = false;
|
||||
end
|
||||
end
|
||||
|
||||
solution = new Dictionary(false, OrderingKind.byInsertion);
|
||||
done = false;
|
||||
|
||||
// Pick random start position on first visible row
|
||||
startingCol = MathLib.floor((MathLib.random() *(mazeSize - 2)) + 2);
|
||||
startingRow = 2;
|
||||
|
||||
// Pick random end position on last visible row
|
||||
endingCol = MathLib.floor((MathLib.random() *(mazeSize - 2)) + 2);
|
||||
endingRow = mazeSize - 1;
|
||||
|
||||
solve(startingCol, startingRow);
|
||||
end
|
||||
|
||||
end
|
||||
81
Task/Maze-solving/EasyLang/maze-solving.easy
Normal file
81
Task/Maze-solving/EasyLang/maze-solving.easy
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
size = 15
|
||||
n = 2 * size + 1
|
||||
f = 100 / (n - 0.5)
|
||||
len m[] n * n
|
||||
#
|
||||
background 000
|
||||
proc show_maze . .
|
||||
clear
|
||||
for i = 1 to len m[]
|
||||
if m[i] = 0
|
||||
x = (i - 1) mod n
|
||||
y = (i - 1) div n
|
||||
color 999
|
||||
move x * f - f / 2 y * f - f / 2
|
||||
rect f * 1.5 f * 1.5
|
||||
.
|
||||
.
|
||||
sleep 0.01
|
||||
.
|
||||
offs[] = [ 1 n -1 (-n) ]
|
||||
proc m_maze pos . .
|
||||
m[pos] = 0
|
||||
call show_maze
|
||||
d[] = [ 1 2 3 4 ]
|
||||
for i = 4 downto 1
|
||||
d = random i
|
||||
dir = offs[d[d]]
|
||||
d[d] = d[i]
|
||||
if m[pos + dir] = 1 and m[pos + 2 * dir] = 1
|
||||
m[pos + dir] = 0
|
||||
call m_maze pos + 2 * dir
|
||||
.
|
||||
.
|
||||
.
|
||||
endpos = n * n - 1
|
||||
proc make_maze . .
|
||||
for i = 1 to len m[]
|
||||
m[i] = 1
|
||||
.
|
||||
for i = 1 to n
|
||||
m[i] = 2
|
||||
m[n * i] = 2
|
||||
m[n * i - n + 1] = 2
|
||||
m[n * n - n + i] = 2
|
||||
.
|
||||
h = 2 * random 15 - n + n * 2 * random 15
|
||||
call m_maze h
|
||||
m[endpos] = 0
|
||||
.
|
||||
call make_maze
|
||||
call show_maze
|
||||
#
|
||||
proc mark pos col . .
|
||||
x = (pos - 1) mod n
|
||||
y = (pos - 1) div n
|
||||
color col
|
||||
move x * f + f / 4 y * f + f / 4
|
||||
circle f / 3.5
|
||||
.
|
||||
proc solve dir0 pos . found .
|
||||
call mark pos 900
|
||||
sleep 0.05
|
||||
if pos = endpos
|
||||
found = 1
|
||||
break 1
|
||||
.
|
||||
of = random 4 - 1
|
||||
for h = 1 to 4
|
||||
dir = (h + of) mod1 4
|
||||
posn = pos + offs[dir]
|
||||
if dir <> dir0 and m[posn] = 0 and found = 0
|
||||
call solve (dir + 1) mod 4 + 1 posn found
|
||||
if found = 0
|
||||
call mark posn 888
|
||||
sleep 0.08
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
sleep 1
|
||||
call solve 0 n + 2 found
|
||||
193
Task/Maze-solving/Emacs-Lisp/maze-solving.l
Normal file
193
Task/Maze-solving/Emacs-Lisp/maze-solving.l
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
(require 'cl-lib)
|
||||
|
||||
(cl-defstruct maze rows cols data)
|
||||
|
||||
(defmacro maze-pt (w r c)
|
||||
`(+ (* (mod ,r (maze-rows ,w)) (maze-cols ,w))
|
||||
(mod ,c (maze-cols ,w))))
|
||||
|
||||
(defmacro maze-ref (w r c)
|
||||
`(aref (maze-data ,w) (maze-pt ,w ,r ,c)))
|
||||
|
||||
(defun new-maze (rows cols)
|
||||
(setq rows (1+ rows)
|
||||
cols (1+ cols))
|
||||
(let ((m (make-maze :rows rows :cols cols :data (make-vector (* rows cols) nil))))
|
||||
|
||||
(dotimes (r rows)
|
||||
(dotimes (c cols)
|
||||
(setf (maze-ref m r c) (copy-sequence '(wall ceiling)))))
|
||||
|
||||
(dotimes (r rows)
|
||||
(maze-set m r (1- cols) 'visited))
|
||||
|
||||
(dotimes (c cols)
|
||||
(maze-set m (1- rows) c 'visited))
|
||||
|
||||
(maze-unset m 0 0 'ceiling) ;; Maze Entrance
|
||||
(maze-unset m (1- rows) (- cols 2) 'ceiling) ;; Maze Exit
|
||||
|
||||
m))
|
||||
|
||||
(defun maze-is-set (maze r c v)
|
||||
(member v (maze-ref maze r c)))
|
||||
|
||||
(defun maze-set (maze r c v)
|
||||
(let ((cell (maze-ref maze r c)))
|
||||
(when (not (member v cell))
|
||||
(setf (maze-ref maze r c) (cons v cell)))))
|
||||
|
||||
(defun maze-unset (maze r c v)
|
||||
(setf (maze-ref maze r c) (delete v (maze-ref maze r c))))
|
||||
|
||||
(defun print-maze (maze &optional marks)
|
||||
(dotimes (r (1- (maze-rows maze)))
|
||||
|
||||
(dotimes (c (1- (maze-cols maze)))
|
||||
(princ (if (maze-is-set maze r c 'ceiling) "+---" "+ ")))
|
||||
(princ "+")
|
||||
(terpri)
|
||||
|
||||
(dotimes (c (1- (maze-cols maze)))
|
||||
(princ (if (maze-is-set maze r c 'wall) "|" " "))
|
||||
(princ (if (member (cons r c) marks) " * " " ")))
|
||||
(princ "|")
|
||||
(terpri))
|
||||
|
||||
(dotimes (c (1- (maze-cols maze)))
|
||||
(princ (if (maze-is-set maze (1- (maze-rows maze)) c 'ceiling) "+---" "+ ")))
|
||||
(princ "+")
|
||||
(terpri))
|
||||
|
||||
(defun shuffle (lst)
|
||||
(sort lst (lambda (a b) (= 1 (random 2)))))
|
||||
|
||||
(defun to-visit (maze row col)
|
||||
(let (unvisited)
|
||||
(dolist (p '((0 . +1) (0 . -1) (+1 . 0) (-1 . 0)))
|
||||
(let ((r (+ row (car p)))
|
||||
(c (+ col (cdr p))))
|
||||
(unless (maze-is-set maze r c 'visited)
|
||||
(push (cons r c) unvisited))))
|
||||
unvisited))
|
||||
|
||||
(defun make-passage (maze r1 c1 r2 c2)
|
||||
(if (= r1 r2)
|
||||
(if (< c1 c2)
|
||||
(maze-unset maze r2 c2 'wall) ; right
|
||||
(maze-unset maze r1 c1 'wall)) ; left
|
||||
(if (< r1 r2)
|
||||
(maze-unset maze r2 c2 'ceiling) ; up
|
||||
(maze-unset maze r1 c1 'ceiling)))) ; down
|
||||
|
||||
(defun dig-maze (maze row col)
|
||||
(let (backup
|
||||
(run 0))
|
||||
(maze-set maze row col 'visited)
|
||||
(push (cons row col) backup)
|
||||
(while backup
|
||||
(setq run (1+ run))
|
||||
(when (> run (/ (+ row col) 3))
|
||||
(setq run 0)
|
||||
(setq backup (shuffle backup)))
|
||||
(setq row (caar backup)
|
||||
col (cdar backup))
|
||||
(let ((p (shuffle (to-visit maze row col))))
|
||||
(if p
|
||||
(let ((r (caar p))
|
||||
(c (cdar p)))
|
||||
(make-passage maze row col r c)
|
||||
(maze-set maze r c 'visited)
|
||||
(push (cons r c) backup))
|
||||
(pop backup)
|
||||
(setq backup (shuffle backup))
|
||||
(setq run 0))))))
|
||||
|
||||
(defun generate (rows cols)
|
||||
(let* ((m (new-maze rows cols)))
|
||||
(dig-maze m (random rows) (random cols))
|
||||
(print-maze m)))
|
||||
|
||||
(defun parse-ceilings (line)
|
||||
(let (rtn
|
||||
(i 1))
|
||||
(while (< i (length line))
|
||||
(push (eq ?- (elt line i)) rtn)
|
||||
(setq i (+ i 4)))
|
||||
(nreverse rtn)))
|
||||
|
||||
(defun parse-walls (line)
|
||||
(let (rtn
|
||||
(i 0))
|
||||
(while (< i (length line))
|
||||
(push (eq ?| (elt line i)) rtn)
|
||||
(setq i (+ i 4)))
|
||||
(nreverse rtn)))
|
||||
|
||||
(defun parse-maze (file-name)
|
||||
(let ((rtn)
|
||||
(lines (with-temp-buffer
|
||||
(insert-file-contents-literally file-name)
|
||||
(split-string (buffer-string) "\n" t))))
|
||||
(while lines
|
||||
(push (parse-ceilings (pop lines)) rtn)
|
||||
(push (parse-walls (pop lines)) rtn))
|
||||
(nreverse rtn)))
|
||||
|
||||
(defun read-maze (file-name)
|
||||
(let* ((raw (parse-maze file-name))
|
||||
(rows (1- (/ (length raw) 2)))
|
||||
(cols (length (car raw)))
|
||||
(maze (new-maze rows cols)))
|
||||
(dotimes (r rows)
|
||||
(let ((ceilings (pop raw)))
|
||||
(dotimes (c cols)
|
||||
(unless (pop ceilings)
|
||||
(maze-unset maze r c 'ceiling))))
|
||||
(let ((walls (pop raw)))
|
||||
(dotimes (c cols)
|
||||
(unless (pop walls)
|
||||
(maze-unset maze r c 'wall)))))
|
||||
maze))
|
||||
|
||||
(defun find-exits (maze row col)
|
||||
(let (exits)
|
||||
(dolist (p '((0 . +1) (0 . -1) (-1 . 0) (+1 . 0)))
|
||||
(let ((r (+ row (car p)))
|
||||
(c (+ col (cdr p))))
|
||||
(unless
|
||||
(cond
|
||||
((equal p '(0 . +1)) (maze-is-set maze r c 'wall))
|
||||
((equal p '(0 . -1)) (maze-is-set maze row col 'wall))
|
||||
((equal p '(+1 . 0)) (maze-is-set maze r c 'ceiling))
|
||||
((equal p '(-1 . 0)) (maze-is-set maze row col 'ceiling)))
|
||||
(push (cons r c) exits))))
|
||||
exits))
|
||||
|
||||
(defun drop-visited (maze points)
|
||||
(let (not-visited)
|
||||
(while points
|
||||
(unless (maze-is-set maze (caar points) (cdar points) 'visited)
|
||||
(push (car points) not-visited))
|
||||
(pop points))
|
||||
not-visited))
|
||||
|
||||
(defun solve-maze (maze)
|
||||
(let (solution
|
||||
(exit (cons (- (maze-rows maze) 2) (- (maze-cols maze) 2)))
|
||||
(pt (cons 0 0)))
|
||||
(while (not (equal pt exit))
|
||||
(maze-set maze (car pt) (cdr pt) 'visited)
|
||||
(let ((exits (drop-visited maze (find-exits maze (car pt) (cdr pt)))))
|
||||
(if (null exits)
|
||||
(setq pt (pop solution))
|
||||
(push pt solution)
|
||||
(setq pt (pop exits)))))
|
||||
(push pt solution)))
|
||||
|
||||
(defun solve (file-name)
|
||||
(let* ((maze (read-maze file-name))
|
||||
(solution (solve-maze maze)))
|
||||
(print-maze maze solution)))
|
||||
|
||||
(solve "maze.txt")
|
||||
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.
|
||||
73
Task/Maze-solving/Frege/maze-solving.frege
Normal file
73
Task/Maze-solving/Frege/maze-solving.frege
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
module MazeSolver where
|
||||
|
||||
import frege.IO
|
||||
import Data.Maybe
|
||||
|
||||
-- given two points, returns the average of them
|
||||
average :: (Int, Int) -> (Int, Int) -> (Int, Int)
|
||||
average (x, y) (x', y') = ((x + x') `div` 2, (y + y') `div` 2)
|
||||
|
||||
-- given a maze and a tuple of position and wall position, returns
|
||||
-- true if the wall position is not blocked (first position is unused)
|
||||
notBlocked :: [String] -> ((Int, Int), (Int, Int)) -> Bool
|
||||
notBlocked maze (_, (x, y)) = (' ' == String.charAt (maze !! y) x)
|
||||
|
||||
-- given a list, a position, and an element, returns a new list
|
||||
-- with the new element substituted at the position
|
||||
substitute :: [a] -> Int -> a -> [a]
|
||||
substitute orig pos el =
|
||||
let (before, after) = splitAt pos orig
|
||||
in before ++ [el] ++ tail after
|
||||
|
||||
-- like above, but for strings, since Frege strings are not
|
||||
-- lists of characters
|
||||
substituteString :: String -> Int -> String -> String
|
||||
substituteString orig pos el =
|
||||
let before = substr orig 0 pos
|
||||
after = strtail orig (pos + 1)
|
||||
in before ++ el ++ after
|
||||
|
||||
-- given a maze and a position, draw a '*' at that position in the maze
|
||||
draw :: [String] -> (Int, Int) -> [String]
|
||||
draw maze (x,y) = substitute maze y $ substituteString row x "*"
|
||||
where row = maze !! y
|
||||
|
||||
-- given a maze, a previous position, and a list of tuples of potential
|
||||
-- new positions and their wall positions, returns the solved maze, or
|
||||
-- None if it cannot be solved
|
||||
tryMoves :: [String] -> (Int, Int) -> [((Int, Int), (Int, Int))] -> Maybe [String]
|
||||
tryMoves _ _ [] = Nothing
|
||||
tryMoves maze prevPos ((newPos,wallPos):more) =
|
||||
case solve' maze newPos prevPos
|
||||
of Nothing -> tryMoves maze prevPos more
|
||||
Just maze' -> Just $ foldl draw maze' [newPos, wallPos]
|
||||
|
||||
-- given a maze, a new position, and a previous position, returns
|
||||
-- the solved maze, or None if it cannot be solved
|
||||
-- (assumes goal is upper-left corner of maze)
|
||||
solve' :: [String] -> (Int, Int) -> (Int, Int) -> Maybe [String]
|
||||
solve' maze (2, 1) _ = Just maze
|
||||
solve' maze (x, y) prevPos =
|
||||
let newPositions = [(x, y - 2), (x + 4, y), (x, y + 2), (x - 4, y)]
|
||||
notPrev pos' = pos' /= prevPos
|
||||
newPositions' = filter notPrev newPositions
|
||||
wallPositions = map (average (x,y)) newPositions'
|
||||
zipped = zip newPositions' wallPositions
|
||||
legalMoves = filter (notBlocked maze) zipped
|
||||
in tryMoves maze (x,y) legalMoves
|
||||
|
||||
-- given a maze, returns a solved maze, or None if it cannot be solved
|
||||
-- (starts at lower right corner and goes to upper left corner)
|
||||
solve :: [String] -> Maybe [String]
|
||||
solve maze = solve' (draw maze start) start (-1, -1)
|
||||
where startx = (length $ head maze) - 3
|
||||
starty = (length maze) - 2
|
||||
start = (startx, starty)
|
||||
|
||||
-- takes unsolved maze on standard input, prints solved maze on standard output
|
||||
main _ = do
|
||||
isin <- stdin
|
||||
isrin <- InputStreamReader.new isin
|
||||
brin <- BufferedReader.fromISR isrin
|
||||
lns <- BufferedReader.getlines brin
|
||||
printStr $ unlines $ fromMaybe ["can't solve"] $ solve lns
|
||||
163
Task/Maze-solving/Go/maze-solving.go
Normal file
163
Task/Maze-solving/Go/maze-solving.go
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
type maze struct {
|
||||
c2 [][]byte // cells by row
|
||||
h2 [][]byte // horizontal walls by row (ignore first row)
|
||||
v2 [][]byte // vertical walls by row (ignore first of each column)
|
||||
}
|
||||
|
||||
func newMaze(rows, cols int) *maze {
|
||||
c := make([]byte, rows*cols) // all cells
|
||||
h := bytes.Repeat([]byte{'-'}, rows*cols) // all horizontal walls
|
||||
v := bytes.Repeat([]byte{'|'}, rows*cols) // all vertical walls
|
||||
c2 := make([][]byte, rows) // cells by row
|
||||
h2 := make([][]byte, rows) // horizontal walls by row
|
||||
v2 := make([][]byte, rows) // vertical walls by row
|
||||
for i := range h2 {
|
||||
c2[i] = c[i*cols : (i+1)*cols]
|
||||
h2[i] = h[i*cols : (i+1)*cols]
|
||||
v2[i] = v[i*cols : (i+1)*cols]
|
||||
}
|
||||
return &maze{c2, h2, v2}
|
||||
}
|
||||
|
||||
func (m *maze) String() string {
|
||||
hWall := []byte("+---")
|
||||
hOpen := []byte("+ ")
|
||||
vWall := []byte("| ")
|
||||
vOpen := []byte(" ")
|
||||
rightCorner := []byte("+\n")
|
||||
rightWall := []byte("|\n")
|
||||
var b []byte
|
||||
for r, hw := range m.h2 {
|
||||
for _, h := range hw {
|
||||
if h == '-' || r == 0 {
|
||||
b = append(b, hWall...)
|
||||
} else {
|
||||
b = append(b, hOpen...)
|
||||
if h != '-' && h != 0 {
|
||||
b[len(b)-2] = h
|
||||
}
|
||||
}
|
||||
}
|
||||
b = append(b, rightCorner...)
|
||||
for c, vw := range m.v2[r] {
|
||||
if vw == '|' || c == 0 {
|
||||
b = append(b, vWall...)
|
||||
} else {
|
||||
b = append(b, vOpen...)
|
||||
if vw != '|' && vw != 0 {
|
||||
b[len(b)-4] = vw
|
||||
}
|
||||
}
|
||||
if m.c2[r][c] != 0 {
|
||||
b[len(b)-2] = m.c2[r][c]
|
||||
}
|
||||
}
|
||||
b = append(b, rightWall...)
|
||||
}
|
||||
for _ = range m.h2[0] {
|
||||
b = append(b, hWall...)
|
||||
}
|
||||
b = append(b, rightCorner...)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (m *maze) gen() {
|
||||
m.g2(rand.Intn(len(m.c2)), rand.Intn(len(m.c2[0])))
|
||||
}
|
||||
|
||||
const (
|
||||
up = iota
|
||||
dn
|
||||
rt
|
||||
lf
|
||||
)
|
||||
|
||||
func (m *maze) g2(r, c int) {
|
||||
m.c2[r][c] = ' '
|
||||
for _, dir := range rand.Perm(4) {
|
||||
switch dir {
|
||||
case up:
|
||||
if r > 0 && m.c2[r-1][c] == 0 {
|
||||
m.h2[r][c] = 0
|
||||
m.g2(r-1, c)
|
||||
}
|
||||
case lf:
|
||||
if c > 0 && m.c2[r][c-1] == 0 {
|
||||
m.v2[r][c] = 0
|
||||
m.g2(r, c-1)
|
||||
}
|
||||
case dn:
|
||||
if r < len(m.c2)-1 && m.c2[r+1][c] == 0 {
|
||||
m.h2[r+1][c] = 0
|
||||
m.g2(r+1, c)
|
||||
}
|
||||
case rt:
|
||||
if c < len(m.c2[0])-1 && m.c2[r][c+1] == 0 {
|
||||
m.v2[r][c+1] = 0
|
||||
m.g2(r, c+1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
const height = 4
|
||||
const width = 7
|
||||
m := newMaze(height, width)
|
||||
m.gen()
|
||||
m.solve(
|
||||
rand.Intn(height), rand.Intn(width),
|
||||
rand.Intn(height), rand.Intn(width))
|
||||
fmt.Print(m)
|
||||
}
|
||||
|
||||
func (m *maze) solve(ra, ca, rz, cz int) {
|
||||
var rSolve func(ra, ca, dir int) bool
|
||||
rSolve = func(r, c, dir int) bool {
|
||||
if r == rz && c == cz {
|
||||
m.c2[r][c] = 'F'
|
||||
return true
|
||||
}
|
||||
if dir != dn && m.h2[r][c] == 0 {
|
||||
if rSolve(r-1, c, up) {
|
||||
m.c2[r][c] = '^'
|
||||
m.h2[r][c] = '^'
|
||||
return true
|
||||
}
|
||||
}
|
||||
if dir != up && r+1 < len(m.h2) && m.h2[r+1][c] == 0 {
|
||||
if rSolve(r+1, c, dn) {
|
||||
m.c2[r][c] = 'v'
|
||||
m.h2[r+1][c] = 'v'
|
||||
return true
|
||||
}
|
||||
}
|
||||
if dir != lf && c+1 < len(m.v2[0]) && m.v2[r][c+1] == 0 {
|
||||
if rSolve(r, c+1, rt) {
|
||||
m.c2[r][c] = '>'
|
||||
m.v2[r][c+1] = '>'
|
||||
return true
|
||||
}
|
||||
}
|
||||
if dir != rt && m.v2[r][c] == 0 {
|
||||
if rSolve(r, c-1, lf) {
|
||||
m.c2[r][c] = '<'
|
||||
m.v2[r][c] = '<'
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
rSolve(ra, ca, -1)
|
||||
m.c2[ra][ca] = 'S'
|
||||
}
|
||||
68
Task/Maze-solving/Haskell/maze-solving.hs
Normal file
68
Task/Maze-solving/Haskell/maze-solving.hs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#!/usr/bin/runhaskell
|
||||
|
||||
import Data.Maybe (fromMaybe)
|
||||
|
||||
-- given two points, returns the average of them
|
||||
average :: (Int, Int) -> (Int, Int) -> (Int, Int)
|
||||
average (x, y) (x_, y_) = ((x + x_) `div` 2, (y + y_) `div` 2)
|
||||
|
||||
-- given a maze and a tuple of position and wall position, returns
|
||||
-- true if the wall position is not blocked (first position is unused)
|
||||
notBlocked :: [String] -> ((Int, Int), (Int, Int)) -> Bool
|
||||
notBlocked maze (_, (x, y)) = ' ' == (maze !! y) !! x
|
||||
|
||||
-- given a list, a position, and an element, returns a new list
|
||||
-- with the new element substituted at the position
|
||||
-- (it seems such a function should exist in the standard library;
|
||||
-- I must be missing it)
|
||||
substitute :: [a] -> Int -> a -> [a]
|
||||
substitute orig pos el =
|
||||
let (before, after) = splitAt pos orig
|
||||
in before ++ [el] ++ tail after
|
||||
|
||||
-- given a maze and a position, draw a '*' at that position in the maze
|
||||
draw :: [String] -> (Int, Int) -> [String]
|
||||
draw maze (x, y) =
|
||||
let row = maze !! y
|
||||
in substitute maze y $ substitute row x '*'
|
||||
|
||||
-- given a maze, a previous position, and a list of tuples of potential
|
||||
-- new positions and their wall positions, returns the solved maze, or
|
||||
-- None if it cannot be solved
|
||||
tryMoves :: [String]
|
||||
-> (Int, Int)
|
||||
-> [((Int, Int), (Int, Int))]
|
||||
-> Maybe [String]
|
||||
tryMoves _ _ [] = Nothing
|
||||
tryMoves maze prevPos ((newPos, wallPos):more) =
|
||||
case solve_ maze newPos prevPos of
|
||||
Nothing -> tryMoves maze prevPos more
|
||||
Just maze_ -> Just $ foldl draw maze_ [newPos, wallPos]
|
||||
|
||||
-- given a maze, a new position, and a previous position, returns
|
||||
-- the solved maze, or None if it cannot be solved
|
||||
-- (assumes goal is upper-left corner of maze)
|
||||
solve_ :: [String] -> (Int, Int) -> (Int, Int) -> Maybe [String]
|
||||
solve_ maze (2, 1) _ = Just maze
|
||||
solve_ maze pos@(x, y) prevPos =
|
||||
let newPositions = [(x, y - 2), (x + 4, y), (x, y + 2), (x - 4, y)]
|
||||
notPrev pos_ = pos_ /= prevPos
|
||||
newPositions_ = filter notPrev newPositions
|
||||
wallPositions = map (average pos) newPositions_
|
||||
zipped = zip newPositions_ wallPositions
|
||||
legalMoves = filter (notBlocked maze) zipped
|
||||
in tryMoves maze pos legalMoves
|
||||
|
||||
-- given a maze, returns a solved maze, or None if it cannot be solved
|
||||
-- (starts at lower right corner and goes to upper left corner)
|
||||
solve :: [String] -> Maybe [String]
|
||||
solve maze = solve_ (draw maze start) start (-1, -1)
|
||||
where
|
||||
startx = length (head maze) - 3
|
||||
starty = length maze - 2
|
||||
start = (startx, starty)
|
||||
|
||||
-- takes unsolved maze on standard input, prints solved maze on standard output
|
||||
main =
|
||||
let main_ = unlines . fromMaybe ["can_t solve"] . solve . lines
|
||||
in interact main_
|
||||
13
Task/Maze-solving/Icon/maze-solving-1.icon
Normal file
13
Task/Maze-solving/Icon/maze-solving-1.icon
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
procedure main(A)
|
||||
/mh := \A[1] | 12
|
||||
/mw := \A[2] | 16
|
||||
mz := DisplayMaze(GenerateMaze(mh,mw))
|
||||
WriteImage(mz.filename) # save file
|
||||
WAttrib(mz.window,"canvas=normal") # show it
|
||||
until Event() == &lpress # wait for left mouse press
|
||||
Solver(mz.maze)
|
||||
DisplayMazeSolution(mz)
|
||||
WriteImage(mz.filename ?:= (="maze-", "maze-solved-" || tab(0)))
|
||||
until Event() == &lpress # wait
|
||||
close(mz.window)
|
||||
end
|
||||
37
Task/Maze-solving/Icon/maze-solving-2.icon
Normal file
37
Task/Maze-solving/Icon/maze-solving-2.icon
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
procedure Solver(r,c)
|
||||
static maze,h,w,rd
|
||||
|
||||
if type(r) == "list" then { # ------------------- Top Level (r == maze)
|
||||
h := *(maze := r) # height
|
||||
w := *maze[1] # width
|
||||
every r := 1 to h & c := 1 to w do # remove breadcrumbs
|
||||
maze[r,c] := iand(maze[r,c],NORTH+EAST+SOUTH+WEST+START+FINISH)
|
||||
every ((r := 1 | h) & (c := 1 to w)) | # search perimiter
|
||||
((r := 1 to h) & (c := 1 | w)) do
|
||||
if iand(maze[r,c],START) > 0 then break # until start found
|
||||
Solver(r,c) # recurse through maze
|
||||
return 1(.maze,maze := &null) # return maze and reset
|
||||
}
|
||||
else # ------------------- Recurse way through maze
|
||||
if iand(x := maze[r,c],SEEN) = 0 then { # in bounds and not seen?
|
||||
(iand(x,FINISH) > 0, maze[r,c] +:= PATH, return ) # at finish? - done!
|
||||
maze[r,c] +:= SEEN # drop bread crumb
|
||||
(iand(x,NORTH) > 0, Solver(r-1,c), maze[r,c] +:= PATH, return)
|
||||
(iand(x,EAST) > 0, Solver(r,c+1), maze[r,c] +:= PATH, return)
|
||||
(iand(x,SOUTH) > 0, Solver(r+1,c), maze[r,c] +:= PATH, return)
|
||||
(iand(x,WEST) > 0, Solver(r,c-1), maze[r,c] +:= PATH, return)
|
||||
}
|
||||
end
|
||||
|
||||
procedure DisplayMazeSolution(mz) #: draw marked PATH
|
||||
&window := mz.window
|
||||
maze := mz.maze
|
||||
WAttrib("dx="||(dxy:=BORDER+CELL/2),"dy="||dxy)
|
||||
every (r := 1 to *maze) & (c := 1 to *maze[1]) do {
|
||||
if fg ~=== "blue" then Fg(fg := "blue")
|
||||
if iand(maze[r,c],START) > 0 then Fg(fg := "red")
|
||||
if iand(maze[r,c],PATH) > 0 then
|
||||
FillCircle(x := CELL*(c-1),y := CELL*(r-1),rad := CELL/5)
|
||||
}
|
||||
return mz
|
||||
end
|
||||
130
Task/Maze-solving/Icon/maze-solving-3.icon
Normal file
130
Task/Maze-solving/Icon/maze-solving-3.icon
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
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),&null,0) # 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, parent, len, val)
|
||||
|
||||
method getLoc(); return loc; end
|
||||
method getParent(); return \parent; end
|
||||
method getLen(); return len; 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 | (len <= bestMouse.getLen()) then { # Keep going?
|
||||
mark(maze, r,c)
|
||||
unlock(region[r,c])
|
||||
return Position(r,c)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
initially (m, l, p, n)
|
||||
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
|
||||
parent := p
|
||||
len := n+1
|
||||
val := maze[loc.r,loc.c] | fail # Fail if outside maze
|
||||
insert(qMice, self)
|
||||
thread {
|
||||
if atEnd() then {
|
||||
critical bestMouseLock:
|
||||
if /bestMouse | (len < bestMouse.getLen()) then bestMouse := self
|
||||
}
|
||||
else { # Spawn more mice to look for finish
|
||||
QMouse(maze, goNorth(), self, len)
|
||||
QMouse(maze, goSouth(), self, len)
|
||||
QMouse(maze, goEast(), self, len)
|
||||
QMouse(maze, goWest(), self, len)
|
||||
}
|
||||
|
||||
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 path := \bestMouse then { # Mark it in maze
|
||||
repeat {
|
||||
loc := path.getLoc()
|
||||
maze[loc.r,loc.c] +:= PATH
|
||||
path := \path.getParent() | break
|
||||
}
|
||||
return
|
||||
}
|
||||
end
|
||||
|
||||
procedure waitForCompletion()
|
||||
critical qMiceEmpty: while *qMice > 0 do wait(qMiceEmpty)
|
||||
end
|
||||
95
Task/Maze-solving/J/maze-solving.j
Normal file
95
Task/Maze-solving/J/maze-solving.j
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
maze=:4 :0
|
||||
assert.0<:n=.<:x*y
|
||||
horiz=. 0$~x,y-1
|
||||
verti=. 0$~(x-1),y
|
||||
path=.,:here=. ?x,y
|
||||
unvisited=.0 (<here+1)} 0,0,~|:0,0,~1$~y,x
|
||||
while.n do.
|
||||
neighbors=. here+"1 (,-)=0 1
|
||||
neighbors=. neighbors #~ (<"1 neighbors+1) {unvisited
|
||||
if.#neighbors do.
|
||||
n=.n-1
|
||||
next=. ({~ ?@#) neighbors
|
||||
unvisited=.0 (<next+1)} unvisited
|
||||
if.{.next=here
|
||||
do. horiz=.1 (<-:here+next-0 1)} horiz
|
||||
else. verti=. 1 (<-:here+next-1 0)} verti end.
|
||||
path=.path,here=.next
|
||||
else.
|
||||
here=.{:path
|
||||
path=.}:path
|
||||
end.
|
||||
end.
|
||||
horiz;verti
|
||||
)
|
||||
|
||||
NB. source Dijkstra_equal_weights graph
|
||||
NB.
|
||||
NB. + +---+---+
|
||||
NB. | 0 1 2 | (sample cell numbers)
|
||||
NB. +---+ + +
|
||||
NB. | 3 4 | 5
|
||||
NB. +---+---+---+
|
||||
NB.
|
||||
NB. graph =: 1;0 2 4;1 5;4;1 3;2
|
||||
NB. The graph is a vector of boxed vectors of neighbors.
|
||||
|
||||
Dijkstra_equal_weights =: 4 : 0
|
||||
dist =. previous =. #&_ n =. # graph =. y [ source =. x
|
||||
dist =. 0 source } dist
|
||||
Q =. 0
|
||||
while. #Q do.
|
||||
u =. {.Q
|
||||
Q =. }.Q
|
||||
if. _ = u{dist do. break. end.
|
||||
for_v. >u{graph do.
|
||||
if. -. v e. previous do.
|
||||
alt =. >: u { dist
|
||||
if. alt < v { dist do.
|
||||
dist =. alt v } dist
|
||||
previous =. u v } previous
|
||||
if. v e. Q do.
|
||||
echo 'belch'
|
||||
else.
|
||||
Q =. Q,v
|
||||
end.
|
||||
end.
|
||||
end.
|
||||
end.
|
||||
end.
|
||||
dist;previous
|
||||
)
|
||||
|
||||
path =: 3 : 0
|
||||
p =. <:#y
|
||||
while. _ > {:p do.
|
||||
p =. p,y{~{:p
|
||||
end.
|
||||
|.}:p
|
||||
)
|
||||
|
||||
solve=:3 :0
|
||||
NB. convert walls to graph
|
||||
shape =. }.@$@:>
|
||||
ew =. (,.&0 ,: 0&,.)@>@{. NB. east west doors
|
||||
ns =. (, &0 ,: 0&, )@>@{:
|
||||
cell_offsets =. 1 _1 1 _1 * 2 # 1 , {:@shape
|
||||
cell_numbers =. i.@shape
|
||||
neighbors =. (cell_numbers +"_ _1 cell_offsets *"_1 (ew , ns))y
|
||||
graph =. (|:@(,/"_1) <@-."1 0 ,@i.@shape)neighbors NB. list of boxed neighbors
|
||||
NB. solve it
|
||||
path , > {: 0 Dijkstra_equal_weights graph
|
||||
)
|
||||
|
||||
display=:3 :0
|
||||
size=. >.&$&>/y
|
||||
text=. (}:1 3$~2*1+{:size)#"1":size$<' '
|
||||
'hdoor vdoor'=. 2 4&*&.>&.> (#&,{@;&i./@$)&.> y
|
||||
' ' (a:-.~0 1;0 2; 0 3;(2 1-~$text);(1 4&+&.> hdoor),,vdoor+&.>"0/2 1;2 2;2 3)} text
|
||||
:
|
||||
a=. display y
|
||||
size=. >.&$&>/y
|
||||
columns=. {: size
|
||||
cells =. <"1(1 2&p.@<.@(%&columns) ,. 2 4&p.@(columns&|))x
|
||||
'o' cells } a NB. exercise, replace cells with a gerund to draw arrows on the path.
|
||||
)
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
135
Task/Maze-solving/JavaScript/maze-solving.js
Normal file
135
Task/Maze-solving/JavaScript/maze-solving.js
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
var ctx, wid, hei, cols, rows, maze, stack = [], start = {x:-1, y:-1}, end = {x:-1, y:-1}, grid = 8;
|
||||
function drawMaze() {
|
||||
for( var i = 0; i < cols; i++ ) {
|
||||
for( var j = 0; j < rows; j++ ) {
|
||||
switch( maze[i][j] ) {
|
||||
case 0: ctx.fillStyle = "black"; break;
|
||||
case 1: ctx.fillStyle = "green"; break;
|
||||
case 2: ctx.fillStyle = "red"; break;
|
||||
case 3: ctx.fillStyle = "yellow"; break;
|
||||
case 4: ctx.fillStyle = "#500000"; break;
|
||||
}
|
||||
ctx.fillRect( grid * i, grid * j, grid, grid );
|
||||
}
|
||||
}
|
||||
}
|
||||
function getFNeighbours( sx, sy, a ) {
|
||||
var n = [];
|
||||
if( sx - 1 > 0 && maze[sx - 1][sy] == a ) {
|
||||
n.push( { x:sx - 1, y:sy } );
|
||||
}
|
||||
if( sx + 1 < cols - 1 && maze[sx + 1][sy] == a ) {
|
||||
n.push( { x:sx + 1, y:sy } );
|
||||
}
|
||||
if( sy - 1 > 0 && maze[sx][sy - 1] == a ) {
|
||||
n.push( { x:sx, y:sy - 1 } );
|
||||
}
|
||||
if( sy + 1 < rows - 1 && maze[sx][sy + 1] == a ) {
|
||||
n.push( { x:sx, y:sy + 1 } );
|
||||
}
|
||||
return n;
|
||||
}
|
||||
function solveMaze() {
|
||||
if( start.x == end.x && start.y == end.y ) {
|
||||
for( var i = 0; i < cols; i++ ) {
|
||||
for( var j = 0; j < rows; j++ ) {
|
||||
switch( maze[i][j] ) {
|
||||
case 2: maze[i][j] = 3; break;
|
||||
case 4: maze[i][j] = 0; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
drawMaze();
|
||||
return;
|
||||
}
|
||||
var neighbours = getFNeighbours( start.x, start.y, 0 );
|
||||
if( neighbours.length ) {
|
||||
stack.push( start );
|
||||
start = neighbours[0];
|
||||
maze[start.x][start.y] = 2;
|
||||
} else {
|
||||
maze[start.x][start.y] = 4;
|
||||
start = stack.pop();
|
||||
}
|
||||
|
||||
drawMaze();
|
||||
requestAnimationFrame( solveMaze );
|
||||
}
|
||||
function getCursorPos( event ) {
|
||||
var rect = this.getBoundingClientRect();
|
||||
var x = Math.floor( ( event.clientX - rect.left ) / grid ),
|
||||
y = Math.floor( ( event.clientY - rect.top ) / grid );
|
||||
if( maze[x][y] ) return;
|
||||
if( start.x == -1 ) {
|
||||
start = { x: x, y: y };
|
||||
} else {
|
||||
end = { x: x, y: y };
|
||||
maze[start.x][start.y] = 2;
|
||||
solveMaze();
|
||||
}
|
||||
}
|
||||
function getNeighbours( sx, sy, a ) {
|
||||
var n = [];
|
||||
if( sx - 1 > 0 && maze[sx - 1][sy] == a && sx - 2 > 0 && maze[sx - 2][sy] == a ) {
|
||||
n.push( { x:sx - 1, y:sy } ); n.push( { x:sx - 2, y:sy } );
|
||||
}
|
||||
if( sx + 1 < cols - 1 && maze[sx + 1][sy] == a && sx + 2 < cols - 1 && maze[sx + 2][sy] == a ) {
|
||||
n.push( { x:sx + 1, y:sy } ); n.push( { x:sx + 2, y:sy } );
|
||||
}
|
||||
if( sy - 1 > 0 && maze[sx][sy - 1] == a && sy - 2 > 0 && maze[sx][sy - 2] == a ) {
|
||||
n.push( { x:sx, y:sy - 1 } ); n.push( { x:sx, y:sy - 2 } );
|
||||
}
|
||||
if( sy + 1 < rows - 1 && maze[sx][sy + 1] == a && sy + 2 < rows - 1 && maze[sx][sy + 2] == a ) {
|
||||
n.push( { x:sx, y:sy + 1 } ); n.push( { x:sx, y:sy + 2 } );
|
||||
}
|
||||
return n;
|
||||
}
|
||||
function createArray( c, r ) {
|
||||
var m = new Array( c );
|
||||
for( var i = 0; i < c; i++ ) {
|
||||
m[i] = new Array( r );
|
||||
for( var j = 0; j < r; j++ ) {
|
||||
m[i][j] = 1;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
function createMaze() {
|
||||
var neighbours = getNeighbours( start.x, start.y, 1 ), l;
|
||||
if( neighbours.length < 1 ) {
|
||||
if( stack.length < 1 ) {
|
||||
drawMaze(); stack = [];
|
||||
start.x = start.y = -1;
|
||||
document.getElementById( "canvas" ).addEventListener( "mousedown", getCursorPos, false );
|
||||
return;
|
||||
}
|
||||
start = stack.pop();
|
||||
} else {
|
||||
var i = 2 * Math.floor( Math.random() * ( neighbours.length / 2 ) )
|
||||
l = neighbours[i]; maze[l.x][l.y] = 0;
|
||||
l = neighbours[i + 1]; maze[l.x][l.y] = 0;
|
||||
start = l
|
||||
stack.push( start )
|
||||
}
|
||||
drawMaze();
|
||||
requestAnimationFrame( createMaze );
|
||||
}
|
||||
function createCanvas( w, h ) {
|
||||
var canvas = document.createElement( "canvas" );
|
||||
wid = w; hei = h;
|
||||
canvas.width = wid; canvas.height = hei;
|
||||
canvas.id = "canvas";
|
||||
ctx = canvas.getContext( "2d" );
|
||||
ctx.fillStyle = "black"; ctx.fillRect( 0, 0, wid, hei );
|
||||
document.body.appendChild( canvas );
|
||||
}
|
||||
function init() {
|
||||
cols = 73; rows = 53;
|
||||
createCanvas( grid * cols, grid * rows );
|
||||
maze = createArray( cols, rows );
|
||||
start.x = Math.floor( Math.random() * ( cols / 2 ) );
|
||||
start.y = Math.floor( Math.random() * ( rows / 2 ) );
|
||||
if( !( start.x & 1 ) ) start.x++; if( !( start.y & 1 ) ) start.y++;
|
||||
maze[start.x][start.y] = 0;
|
||||
createMaze();
|
||||
}
|
||||
80
Task/Maze-solving/Julia/maze-solving.julia
Normal file
80
Task/Maze-solving/Julia/maze-solving.julia
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
"""
|
||||
+ +---+---+
|
||||
| 1 2 3 |
|
||||
+---+ + +
|
||||
| 4 5 | 6
|
||||
+---+---+---+
|
||||
|
||||
julia> const graph = [
|
||||
0 1 0 0 0 0;
|
||||
1 0 1 0 1 0;
|
||||
0 1 0 0 0 1;
|
||||
0 0 0 0 1 0;
|
||||
0 1 0 1 0 0;
|
||||
0 0 1 0 0 0]
|
||||
|
||||
julia> dist, path = dijkstra(graph, 1)
|
||||
(Dict(4=>3,2=>1,3=>2,5=>2,6=>3,1=>0), Dict(4=>5,2=>1,3=>2,5=>2,6=>3,1=>0))
|
||||
|
||||
julia> printpath(path, 6) # Display solution of the maze
|
||||
1 -> 2 -> 3 -> 6
|
||||
|
||||
"""
|
||||
function dijkstra(graph, source::Int=1)
|
||||
# ensure that the adjacency matrix is squared
|
||||
@assert size(graph, 1) == size(graph, 2)
|
||||
inf = typemax(Int64)
|
||||
n = size(graph, 1)
|
||||
|
||||
Q = IntSet(1:n) # Set of unvisited nodes
|
||||
dist = Dict(n => inf for n in Q) # Unknown distance function from source to v
|
||||
prev = Dict(n => 0 for n in Q) # Previous node in optimal path from source
|
||||
dist[source] = 0 # Distance from source to source
|
||||
|
||||
function _minimumdist(nodes) # Find the less distant node among nodes
|
||||
kmin, vmin = nothing, inf
|
||||
for (k, v) in dist
|
||||
if k ∈ nodes && v ≤ vmin
|
||||
kmin, vmin = k, v
|
||||
end
|
||||
end
|
||||
return kmin
|
||||
end
|
||||
# Until all nodes are visited...
|
||||
while !isempty(Q)
|
||||
u = _minimumdist(Q) # Vertex in Q with smallest dist[]
|
||||
pop!(Q, u)
|
||||
if dist[u] == inf break end # All remaining vertices are inaccessible from source
|
||||
for v in 1:n # Each neighbor v of u
|
||||
if graph[u, v] != 0 && v ∈ Q # where v has not yet been visited
|
||||
alt = dist[u] + graph[u, v]
|
||||
if alt < dist[v] # Relax (u, v, a)
|
||||
dist[v] = alt
|
||||
prev[v] = u
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return dist, prev
|
||||
end
|
||||
|
||||
function printpath(prev::Dict, target::Int)
|
||||
path = "$target"
|
||||
while prev[target] != 0
|
||||
target = prev[target]
|
||||
path = "$target -> " * path
|
||||
end
|
||||
println(path)
|
||||
end
|
||||
|
||||
const graph = [
|
||||
0 1 0 0 0 0;
|
||||
1 0 1 0 1 0;
|
||||
0 1 0 0 0 1;
|
||||
0 0 0 0 1 0;
|
||||
0 1 0 1 0 0;
|
||||
0 0 1 0 0 0]
|
||||
|
||||
dist, path = dijkstra(graph)
|
||||
printpath(path, 6)
|
||||
117
Task/Maze-solving/Kotlin/maze-solving.kotlin
Normal file
117
Task/Maze-solving/Kotlin/maze-solving.kotlin
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
// Version 1.2.31
|
||||
|
||||
import java.io.File
|
||||
|
||||
typealias Maze = List<CharArray>
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
fun decimateHorizontally(lines: List<String>): Maze {
|
||||
val width = (lines[0].length + 1) / 2
|
||||
val c = List(lines.size) { CharArray(width) }
|
||||
for (i in 0 until lines.size) {
|
||||
for (j in 0 until width) c[i][j] = lines[i][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.
|
||||
*/
|
||||
fun solveMazeRecursively(maze: Maze, x: Int, y: Int, d: Int): Boolean {
|
||||
var ok = false
|
||||
var i = 0
|
||||
while (i < 4 && !ok) {
|
||||
if (i != d) {
|
||||
// 0 = up, 1 = right, 2 = down, 3 = left
|
||||
when(i) {
|
||||
0 -> if (maze[y - 1][x] == ' ') ok = solveMazeRecursively (maze, x, y - 2, 2)
|
||||
1 -> if (maze[y][x + 1] == ' ') ok = solveMazeRecursively (maze, x + 2, y, 3)
|
||||
2 -> if (maze[y + 1][x] == ' ') ok = solveMazeRecursively (maze, x, y + 2, 0)
|
||||
3 -> if (maze[y][x - 1] == ' ') ok = solveMazeRecursively (maze, x - 2, y, 1)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
// 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] = '*'
|
||||
when (d) {
|
||||
0 -> maze[y - 1][x] = '*'
|
||||
1 -> maze[y][x + 1] = '*'
|
||||
2 -> maze[y + 1][x] = '*'
|
||||
3 -> maze[y][x - 1] = '*'
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
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.
|
||||
*/
|
||||
fun solveMaze(maze: Maze) =
|
||||
solveMazeRecursively(maze, maze[0].size - 2, maze.size - 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.
|
||||
*/
|
||||
fun expandHorizontally(maze: Maze): Array<String> {
|
||||
val tmp = CharArray(3)
|
||||
val lines = Array<String>(maze.size) { "" }
|
||||
for (i in 0 until maze.size) {
|
||||
val sb = StringBuilder(maze[i].size * 2)
|
||||
for (j in 0 until maze[i].size) {
|
||||
if (j % 2 == 0)
|
||||
sb.append(maze[i][j])
|
||||
else {
|
||||
for (k in 0..2) tmp[k] = 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#Kotlin
|
||||
* in a file whose name is specified as a command-line argument.
|
||||
*/
|
||||
fun main(args: Array<String>) {
|
||||
if (args.size != 1) {
|
||||
println("The maze file to be read should be passed as a single command line argument.")
|
||||
return
|
||||
}
|
||||
val f = File(args[0])
|
||||
if (!f.exists()) {
|
||||
println("Sorry ${args[0]} does not exist.")
|
||||
return
|
||||
}
|
||||
val lines = f.readLines(Charsets.US_ASCII)
|
||||
val maze = decimateHorizontally(lines)
|
||||
solveMaze(maze)
|
||||
val solvedLines = expandHorizontally(maze)
|
||||
println(solvedLines.joinToString("\n"))
|
||||
}
|
||||
1
Task/Maze-solving/Mathematica/maze-solving.math
Normal file
1
Task/Maze-solving/Mathematica/maze-solving.math
Normal file
|
|
@ -0,0 +1 @@
|
|||
HighlightGraph[maze, PathGraph@FindShortestPath[maze, 1, 273]]
|
||||
157
Task/Maze-solving/Nim/maze-solving.nim
Normal file
157
Task/Maze-solving/Nim/maze-solving.nim
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
import random, strutils
|
||||
|
||||
type
|
||||
|
||||
Direction {.pure.} = enum None, Up, Left, Down, Right
|
||||
|
||||
Maze = object
|
||||
cells: seq[string]
|
||||
hwalls: seq[string]
|
||||
vwalls: seq[string]
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# Maze creation.
|
||||
|
||||
func initMaze(rows, cols: Positive): Maze =
|
||||
## Initialize a maze description.
|
||||
var h = repeat('-', cols)
|
||||
var v = repeat("|", cols)
|
||||
for i in 0..<rows:
|
||||
result.cells.add newString(cols)
|
||||
result.hwalls.add h
|
||||
result.vwalls.add v
|
||||
|
||||
|
||||
proc gen(maze: var Maze; r, c: Natural) =
|
||||
## Generate a maze starting from point (r, c).
|
||||
|
||||
maze.cells[r][c] = ' '
|
||||
var dirs = [Up, Left, Down, Right]
|
||||
dirs.shuffle()
|
||||
for dir in dirs:
|
||||
case dir
|
||||
of None:
|
||||
discard
|
||||
of Up:
|
||||
if r > 0 and maze.cells[r-1][c] == '\0':
|
||||
maze.hwalls[r][c] = chr(0)
|
||||
maze.gen(r-1, c)
|
||||
of Left:
|
||||
if c > 0 and maze.cells[r][c-1] == '\0':
|
||||
maze.vwalls[r][c] = chr(0)
|
||||
maze.gen(r, c-1)
|
||||
of Down:
|
||||
if r < maze.cells.high and maze.cells[r+1][c] == '\0':
|
||||
maze.hwalls[r+1][c] = chr(0)
|
||||
maze.gen(r+1, c)
|
||||
of Right:
|
||||
if c < maze.cells[0].high and maze.cells[r][c+1] == '\0':
|
||||
maze.vwalls[r][c+1] = chr(0)
|
||||
maze.gen(r, c+1)
|
||||
|
||||
|
||||
proc gen(maze: var Maze) =
|
||||
## Generate a maze, choosing a random starting point.
|
||||
maze.gen(rand(maze.cells.high), rand(maze.cells[0].high))
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# Maze solving.
|
||||
|
||||
proc solve(maze: var Maze; ra, ca, rz, cz: Natural) =
|
||||
## Solve a maze by finding the path from point (ra, ca) to point (rz, cz).
|
||||
|
||||
proc rsolve(maze: var Maze; r, c: Natural; dir: Direction): bool {.discardable.} =
|
||||
## Recursive solver.
|
||||
|
||||
if r == rz and c == cz:
|
||||
maze.cells[r][c] = 'F'
|
||||
return true
|
||||
|
||||
if dir != Down and maze.hwalls[r][c] == '\0':
|
||||
if maze.rSolve(r-1, c, Up):
|
||||
maze.cells[r][c] = '^'
|
||||
maze.hwalls[r][c] = '^'
|
||||
return true
|
||||
|
||||
if dir != Up and r < maze.hwalls.high and maze.hwalls[r+1][c] == '\0':
|
||||
if maze.rSolve(r+1, c, Down):
|
||||
maze.cells[r][c] = 'v'
|
||||
maze.hwalls[r+1][c] = 'v'
|
||||
return true
|
||||
|
||||
if dir != Left and c < maze.vwalls[0].high and maze.vwalls[r][c+1] == '\0':
|
||||
if maze.rSolve(r, c+1, Right):
|
||||
maze.cells[r][c] = '>'
|
||||
maze.vwalls[r][c+1] = '>'
|
||||
return true
|
||||
|
||||
if dir != Right and maze.vwalls[r][c] == '\0':
|
||||
if maze.rSolve(r, c-1, Left):
|
||||
maze.cells[r][c] = '<'
|
||||
maze.vwalls[r][c] = '<'
|
||||
return true
|
||||
|
||||
|
||||
maze.rsolve(ra, ca, None)
|
||||
maze.cells[ra][ca] = 'S'
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# Maze display.
|
||||
|
||||
func `$`(maze: Maze): string =
|
||||
## Return the string representation fo a maze.
|
||||
|
||||
const
|
||||
HWall = "+---"
|
||||
HOpen = "+ "
|
||||
VWall = "| "
|
||||
VOpen = " "
|
||||
RightCorner = "+\n"
|
||||
RightWall = "|\n"
|
||||
|
||||
for r, hw in maze.hwalls:
|
||||
|
||||
for h in hw:
|
||||
if h == '-' or r == 0:
|
||||
result.add HWall
|
||||
else:
|
||||
result.add HOpen
|
||||
if h notin {'-', '\0'}: result[^2] = h
|
||||
result.add RightCorner
|
||||
|
||||
for c, vw in maze.vwalls[r]:
|
||||
if vw == '|' or c == 0:
|
||||
result.add VWall
|
||||
else:
|
||||
result.add VOpen
|
||||
if vw notin {'|', '\0'}: result[^4] = vw
|
||||
if maze.cells[r][c] != '\0': result[^2] = maze.cells[r][c]
|
||||
result.add RightWall
|
||||
|
||||
for _ in 1..maze.hwalls[0].len:
|
||||
result.add HWall
|
||||
result.add RightCorner
|
||||
|
||||
|
||||
#———————————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
when isMainModule:
|
||||
|
||||
const
|
||||
Width = 8
|
||||
Height = 8
|
||||
|
||||
randomize()
|
||||
var maze = initMaze(Width, Height)
|
||||
maze.gen()
|
||||
var ra, rz = rand(Width - 1)
|
||||
var ca, cz = rand(Height - 1)
|
||||
while rz == ra and cz == ca:
|
||||
# Make sur starting and ending points are different.
|
||||
rz = rand(Width - 1)
|
||||
cz = rand(Height - 1)
|
||||
maze.solve(ra, ca , rz, cz)
|
||||
echo maze
|
||||
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";
|
||||
}
|
||||
65
Task/Maze-solving/Phix/maze-solving.phix
Normal file
65
Task/Maze-solving/Phix/maze-solving.phix
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
(phixonline)-->
|
||||
<span style="color: #000080;font-style:italic;">--
|
||||
-- demo\rosetta\Maze_solving.exw
|
||||
-- =============================
|
||||
--</span>
|
||||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">w</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">11</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">h</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">8</span>
|
||||
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">wall</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"+"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">w</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">),</span><span style="color: #008000;">"---"</span><span style="color: #0000FF;">)&</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #000000;">cell</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"|"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">w</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">),</span><span style="color: #008000;">" ? "</span><span style="color: #0000FF;">)&</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #000000;">grid</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">wall</span><span style="color: #0000FF;">,</span><span style="color: #000000;">h</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">),</span><span style="color: #000000;">cell</span><span style="color: #0000FF;">),</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">)</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">amaze</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">grid</span><span style="color: #0000FF;">[</span><span style="color: #000000;">y</span><span style="color: #0000FF;">][</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">' '</span> <span style="color: #000080;font-style:italic;">-- mark cell visited</span>
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">p</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">shuffle</span><span style="color: #0000FF;">({{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">-</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">2</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">+</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">-</span><span style="color: #000000;">2</span><span style="color: #0000FF;">}})</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">nx</span><span style="color: #0000FF;">></span><span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #000000;">nx</span><span style="color: #0000FF;"><</span><span style="color: #000000;">w</span><span style="color: #0000FF;">*</span><span style="color: #000000;">4</span> <span style="color: #008080;">and</span> <span style="color: #000000;">ny</span><span style="color: #0000FF;">></span><span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #000000;">ny</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">2</span><span style="color: #0000FF;">*</span><span style="color: #000000;">h</span> <span style="color: #008080;">and</span> <span style="color: #000000;">grid</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">][</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'?'</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">mx</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">+</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span>
|
||||
<span style="color: #000000;">grid</span><span style="color: #0000FF;">[(</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">][</span><span style="color: #000000;">mx</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">mx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">' '</span> <span style="color: #000080;font-style:italic;">-- knock down wall</span>
|
||||
<span style="color: #000000;">amaze</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">dx</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">dy</span> <span style="color: #000080;font-style:italic;">-- door location (in a wall!)</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">solve_maze</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">p</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">-</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">2</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">+</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">-</span><span style="color: #000000;">2</span><span style="color: #0000FF;">}}</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">d</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">d</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">wx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">wy</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">+</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,(</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">}</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">grid</span><span style="color: #0000FF;">[</span><span style="color: #000000;">wy</span><span style="color: #0000FF;">][</span><span style="color: #000000;">wx</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">' '</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">grid</span><span style="color: #0000FF;">[</span><span style="color: #000000;">wy</span><span style="color: #0000FF;">][</span><span style="color: #000000;">wx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"-:-:"</span><span style="color: #0000FF;">[</span><span style="color: #000000;">d</span><span style="color: #0000FF;">]</span> <span style="color: #000080;font-style:italic;">-- mark path</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">wx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">wy</span><span style="color: #0000FF;">}={</span><span style="color: #000000;">dx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dy</span><span style="color: #0000FF;">}</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #004600;">true</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">grid</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">][</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">' '</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">grid</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">][</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'o'</span> <span style="color: #000080;font-style:italic;">-- mark cell</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">solve_maze</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #004600;">true</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">grid</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">][</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">' '</span> <span style="color: #000080;font-style:italic;">-- unmark cell</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">grid</span><span style="color: #0000FF;">[</span><span style="color: #000000;">wy</span><span style="color: #0000FF;">][</span><span style="color: #000000;">wx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">' '</span> <span style="color: #000080;font-style:italic;">-- unmark path</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #004600;">false</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">heads</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- toin coss 50:50 true(1)/false(0)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{(</span><span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">w</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">4</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">h</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">2</span><span style="color: #0000FF;">}</span>
|
||||
<span style="color: #000000;">amaze</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000080;font-style:italic;">-- mark start pos</span>
|
||||
<span style="color: #000000;">grid</span><span style="color: #0000FF;">[</span><span style="color: #000000;">y</span><span style="color: #0000FF;">][</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'*'</span>
|
||||
<span style="color: #000080;font-style:italic;">-- add a random door (heads=rhs/lhs, tails=top/btm)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">heads</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">dy</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dx</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">h</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">heads</span><span style="color: #0000FF;">()*</span><span style="color: #000000;">w</span><span style="color: #0000FF;">*</span><span style="color: #000000;">4</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}</span>
|
||||
<span style="color: #000000;">grid</span><span style="color: #0000FF;">[</span><span style="color: #000000;">dy</span><span style="color: #0000FF;">][</span><span style="color: #000000;">dx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">' '</span>
|
||||
<span style="color: #008080;">else</span>
|
||||
<span style="color: #0000FF;">{</span><span style="color: #000000;">dy</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dx</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">heads</span><span style="color: #0000FF;">()*</span><span style="color: #000000;">h</span><span style="color: #0000FF;">*</span><span style="color: #000000;">2</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">w</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">4</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}</span>
|
||||
<span style="color: #000000;">grid</span><span style="color: #0000FF;">[</span><span style="color: #000000;">dy</span><span style="color: #0000FF;">][</span><span style="color: #000000;">dx</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">dx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">' '</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">solve_maze</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #000000;">grid</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">))</span>
|
||||
<!--
|
||||
106
Task/Maze-solving/Picat/maze-solving.picat
Normal file
106
Task/Maze-solving/Picat/maze-solving.picat
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
main =>
|
||||
Maze0 = ["+---+---+---+---+---+---+---+---+",
|
||||
"| | | | |",
|
||||
"+ + + +---+ + +---+ +",
|
||||
"| | | | | |",
|
||||
"+---+---+ + +---+---+ + +",
|
||||
"| | | | |",
|
||||
"+---+ + + +---+---+---+ +",
|
||||
"| | | | |",
|
||||
"+ + + +---+---+---+ + +",
|
||||
"| | | | | |",
|
||||
"+ + + +---+ +---+---+ +",
|
||||
"| | | | | |",
|
||||
"+ +---+---+ +---+---+---+ +",
|
||||
"| | | |",
|
||||
"+ +---+ +---+ + +---+ +",
|
||||
"| | | |",
|
||||
"+---+---+---+---+---+---+---+---+"],
|
||||
MaxR = len(Maze0) div 2,
|
||||
MaxC = len(Maze0[1]) div 4,
|
||||
Maze = new_array(MaxR,MaxC),
|
||||
foreach (R in 1..MaxR, C in 1..MaxC)
|
||||
Maze[R,C] = 0
|
||||
end,
|
||||
fill_maze(Maze0,Maze,1),
|
||||
solve_maze(Maze,(1,1),(MaxR,MaxC),Cost,Plan),
|
||||
OutputMaze = new_array(MaxR,MaxC),
|
||||
foreach ((R,C) in Plan)
|
||||
OutputMaze[R,C] = '*'
|
||||
end,
|
||||
output_maze(Maze0,OutputMaze,1).
|
||||
|
||||
fill_maze([Line1,Line2|Maze0],Maze,R) =>
|
||||
fill_maze_cols(Line1,Maze,R,1),
|
||||
fill_maze_cols(Line2,Maze,R,1),
|
||||
fill_maze(Maze0,Maze,R+1).
|
||||
fill_maze(_,_,_) => true.
|
||||
|
||||
fill_maze_cols(['+',' ',' ',' '|Line],Maze,R,C) =>
|
||||
Maze[R,C] := Maze[R,C] \/ 4, % up
|
||||
Maze[R-1,C] := Maze[R-1,C] \/ 8, % down
|
||||
fill_maze_cols(Line,Maze,R,C+1).
|
||||
fill_maze_cols([' ',' ',' ',' '|Line],Maze,R,C) =>
|
||||
Maze[R,C] := Maze[R,C] \/ 1, % left
|
||||
Maze[R,C-1] := Maze[R,C-1] \/ 2, % right
|
||||
fill_maze_cols(Line,Maze,R,C+1).
|
||||
fill_maze_cols([_,_,_,_|Line],Maze,R,C) =>
|
||||
fill_maze_cols(Line,Maze,R,C+1).
|
||||
fill_maze_cols(_,_,_,_) => true.
|
||||
|
||||
table (+,+,+,min,-)
|
||||
solve_maze(_Maze,FPos,FPos,Cost,Plan) =>
|
||||
Cost = 0,
|
||||
Plan = [FPos].
|
||||
solve_maze(Maze,Pos@(R,C),FPos,Cost,Plan) ?=>
|
||||
Maze[R,C] /\ 1 == 1, % left
|
||||
solve_maze(Maze,(R,C-1),FPos,Cost1,Plan1),
|
||||
Plan = [Pos|Plan1],
|
||||
Cost = Cost1+1.
|
||||
solve_maze(Maze,Pos@(R,C),FPos,Cost,Plan) ?=>
|
||||
Maze[R,C] /\ 2 == 2, % right
|
||||
solve_maze(Maze,(R,C+1),FPos,Cost1,Plan1),
|
||||
Plan = [Pos|Plan1],
|
||||
Cost = Cost1+1.
|
||||
solve_maze(Maze,Pos@(R,C),FPos,Cost,Plan) ?=>
|
||||
Maze[R,C] /\ 4 == 4, % up
|
||||
solve_maze(Maze,(R-1,C),FPos,Cost1,Plan1),
|
||||
Plan = [Pos|Plan1],
|
||||
Cost = Cost1+1.
|
||||
solve_maze(Maze,Pos@(R,C),FPos,Cost,Plan) ?=>
|
||||
Maze[R,C] /\ 8 == 8, % down
|
||||
solve_maze(Maze,(R+1,C),FPos,Cost1,Plan1),
|
||||
Plan = [Pos|Plan1],
|
||||
Cost = Cost1+1.
|
||||
|
||||
output_maze([Line1,Line2|Maze0],Maze,R) =>
|
||||
output_maze_cols(Line1,Maze,R,1),
|
||||
output_maze_cols(Line2,Maze,R,1),
|
||||
output_maze(Maze0,Maze,R+1).
|
||||
output_maze([Line],_,_) => println(Line).
|
||||
|
||||
output_maze_cols([' ',' ',' ',' '|Line],Maze,R,C) =>
|
||||
if Maze[R,C] == '*' then
|
||||
print(" * ")
|
||||
else
|
||||
print(" ")
|
||||
end,
|
||||
output_maze_cols(Line,Maze,R,C+1).
|
||||
output_maze_cols(['|',' ',' ',' '|Line],Maze,R,C) =>
|
||||
if Maze[R,C] == '*' then
|
||||
print("| * ")
|
||||
else
|
||||
print("| ")
|
||||
end,
|
||||
output_maze_cols(Line,Maze,R,C+1).
|
||||
output_maze_cols(['+',' ',' ',' '|Line],Maze,R,C) =>
|
||||
if Maze[R,C] == '*' && Maze[R-1,C] == '*' then
|
||||
print("+ * ")
|
||||
else
|
||||
print("+ ")
|
||||
end,
|
||||
output_maze_cols(Line,Maze,R,C+1).
|
||||
output_maze_cols([C1,C2,C3,C4|Line],Maze,R,C) =>
|
||||
printf("%c%c%c%c",C1,C3,C3,C4),
|
||||
output_maze_cols(Line,Maze,R,C+1).
|
||||
output_maze_cols(Line,_,_,_) => println(Line).
|
||||
16
Task/Maze-solving/PicoLisp/maze-solving.l
Normal file
16
Task/Maze-solving/PicoLisp/maze-solving.l
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
(de shortestPath (Goal This Maze)
|
||||
(let (Path NIL Best NIL Dir " > ")
|
||||
(recur (This Path Dir)
|
||||
(when (and This (not (: mark)))
|
||||
(push 'Path (cons This Dir))
|
||||
(if (== Goal This)
|
||||
(unless (and Best (>= (length Path) (length Best)))
|
||||
(setq Best Path) )
|
||||
(=: mark T)
|
||||
(recurse (: west) Path " > ")
|
||||
(recurse (: east) Path " < ")
|
||||
(recurse (: south) Path " \^ ")
|
||||
(recurse (: north) Path " v ")
|
||||
(=: mark NIL) ) ) )
|
||||
(disp Maze 0
|
||||
'((Fld) (if (asoq Fld Best) (cdr @) " ")) ) ) )
|
||||
147
Task/Maze-solving/Prolog/maze-solving.pro
Normal file
147
Task/Maze-solving/Prolog/maze-solving.pro
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
:- dynamic cell/2.
|
||||
:- dynamic maze/3.
|
||||
:- dynamic path/1.
|
||||
|
||||
maze_solve(Lig,Col) :-
|
||||
retractall(cell(_,_)),
|
||||
retractall(maze(_,_,_)),
|
||||
retractall(path(_)),
|
||||
|
||||
% initialisation of the neighbours of the cells
|
||||
forall(between(0, Lig, I),
|
||||
( forall(between(0, Col, J), assert(maze(I, J, []))))),
|
||||
|
||||
% creation of the window of the maze
|
||||
new(D, window('Maze')),
|
||||
forall(between(0,Lig, I),
|
||||
(XL is 50, YL is I * 30 + 50,
|
||||
XR is Col * 30 + 50,
|
||||
new(L, line(XL, YL, XR, YL)),
|
||||
send(D, display, L))),
|
||||
|
||||
forall(between(0,Col, I),
|
||||
(XT is 50 + I * 30, YT is 50,
|
||||
YB is Lig * 30 + 50,
|
||||
new(L, line(XT, YT, XT, YB)),
|
||||
send(D, display, L))),
|
||||
|
||||
SX is Col * 30 + 100,
|
||||
SY is Lig * 30 + 100,
|
||||
send(D, size, new(_, size(SX, SY))),
|
||||
L0 is random(Lig),
|
||||
C0 is random(Col),
|
||||
assert(cell(L0, C0)),
|
||||
\+search(D, Lig, Col, L0, C0),
|
||||
send(D, open),
|
||||
|
||||
% we look for a path from cell(0, 0) to cell(Lig-1, Col-1)
|
||||
% creation of the entrance
|
||||
erase_line(D, -1, 0, 0, 0),
|
||||
|
||||
% creation of the exit
|
||||
Lig1 is Lig-1,
|
||||
Col1 is Col-1,
|
||||
erase_line(D, Lig1, Col1, Lig, Col1),
|
||||
|
||||
% seraching the path
|
||||
assert(path([[0, 0], [-1, 0]])),
|
||||
walk(Lig, Col),
|
||||
path(P),
|
||||
display_path(D, P).
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
walk(Lig, Col) :-
|
||||
path([[L, C] | _R]),
|
||||
L is Lig - 1,
|
||||
C is Col - 1,
|
||||
retract(path(P)),
|
||||
assert(path([[Lig, C]|P])).
|
||||
|
||||
walk(Lig, Col) :-
|
||||
retract(path([[L, C] | R])),
|
||||
maze(L, C, Edge),
|
||||
member([L1, C1], Edge),
|
||||
\+member([L1, C1], R),
|
||||
assert(path([[L1,C1], [L, C] | R])),
|
||||
walk(Lig, Col).
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
display_path(_, []).
|
||||
|
||||
display_path(D, [[L, C] | R]):-
|
||||
new(B, box(10,10)),
|
||||
send(B, fill_pattern, new(_, colour(@default, 0,0,0))),
|
||||
X is C * 30 + 60,
|
||||
Y is L * 30 + 60,
|
||||
send(D, display, B, point(X,Y)),
|
||||
display_path(D, R).
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
search(D, Lig, Col, L, C) :-
|
||||
Dir is random(4),
|
||||
nextcell(Dir, Lig, Col, L, C, L1, C1),
|
||||
assert(cell(L1,C1)),
|
||||
assert(cur(L1,C1)),
|
||||
|
||||
retract(maze(L, C, Edge)),
|
||||
assert(maze(L, C, [[L1, C1] | Edge])),
|
||||
retract(maze(L1, C1, Edge1)),
|
||||
assert(maze(L1, C1, [[L, C] | Edge1])),
|
||||
|
||||
erase_line(D, L, C, L1, C1),
|
||||
search(D, Lig, Col, L1, C1).
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
erase_line(D, L, C, L, C1) :-
|
||||
( C < C1 -> C2 = C1; C2 = C),
|
||||
XT is C2 * 30 + 50,
|
||||
YT is L * 30 + 51, YR is (L+1) * 30 + 50,
|
||||
new(Line, line(XT, YT, XT, YR)),
|
||||
send(Line, colour, white),
|
||||
send(D, display, Line).
|
||||
|
||||
erase_line(D, L, C, L1, C) :-
|
||||
XT is 51 + C * 30, XR is 50 + (C + 1) * 30,
|
||||
( L < L1 -> L2 is L1; L2 is L),
|
||||
YT is L2 * 30 + 50,
|
||||
new(Line, line(XT, YT, XR, YT)),
|
||||
send(Line, colour, white),
|
||||
send(D, display, Line).
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
nextcell(Dir, Lig, Col, L, C, L1, C1) :-
|
||||
next(Dir, Lig, Col, L, C, L1, C1);
|
||||
( Dir1 is (Dir+3) mod 4,
|
||||
next(Dir1, Lig, Col, L, C, L1, C1));
|
||||
( Dir2 is (Dir+1) mod 4,
|
||||
next(Dir2, Lig, Col, L, C, L1, C1));
|
||||
( Dir3 is (Dir+2) mod 4,
|
||||
next(Dir3, Lig, Col, L, C, L1, C1)).
|
||||
|
||||
% 0 => northward
|
||||
next(0, _Lig, _Col, L, C, L1, C) :-
|
||||
L > 0,
|
||||
L1 is L - 1,
|
||||
\+cell(L1, C).
|
||||
|
||||
% 1 => rightward
|
||||
next(1, _Lig, Col, L, C, L, C1) :-
|
||||
C < Col - 1,
|
||||
C1 is C + 1,
|
||||
\+cell(L, C1).
|
||||
|
||||
% 2 => southward
|
||||
next(2, Lig, _Col, L, C, L1, C) :-
|
||||
L < Lig - 1,
|
||||
L1 is L + 1,
|
||||
\+cell(L1, C).
|
||||
|
||||
% 3 => leftward
|
||||
next(2, _Lig, _Col, L, C, L, C1) :-
|
||||
C > 0,
|
||||
C1 is C - 1,
|
||||
\+cell(L, C1).
|
||||
110
Task/Maze-solving/PureBasic/maze-solving.basic
Normal file
110
Task/Maze-solving/PureBasic/maze-solving.basic
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
;code from the maze generation task is place here in its entirety before the rest of the code
|
||||
|
||||
Procedure displayMazePath(Array maze(2), List Path.POINT())
|
||||
Protected x, y, vWall.s, hWall.s
|
||||
Protected mazeWidth = ArraySize(maze(), 1), mazeHeight = ArraySize(maze(), 2)
|
||||
Protected Dim mazeOutput.mazeOutput(mazeHeight)
|
||||
Protected Dim mazeRow.mazeOutput(0)
|
||||
Static pathChars.s = "@^>v<"
|
||||
|
||||
For y = 0 To mazeHeight
|
||||
makeDisplayMazeRow(mazeRow(), maze(), y): mazeOutput(y) = mazeRow(0)
|
||||
Next
|
||||
|
||||
If ListSize(path())
|
||||
FirstElement(path())
|
||||
Protected prevPath.POINT = path()
|
||||
|
||||
While NextElement(path())
|
||||
x = path()\x - prevPath\x
|
||||
y = path()\y - prevPath\y
|
||||
Select x
|
||||
Case -1: dirTaken = #dir_W
|
||||
Case 1: dirTaken = #dir_E
|
||||
Default
|
||||
If y < 0
|
||||
dirTaken = #dir_N
|
||||
Else
|
||||
dirTaken = #dir_S
|
||||
EndIf
|
||||
EndSelect
|
||||
hWall = mazeOutput(prevPath\y)\hWall
|
||||
mazeOutput(prevPath\y)\hWall = Left(hWall, prevPath\x * #cellDWidth + 2) + Mid(pathChars, dirTaken + 1, 1) + Right(hWall, Len(hWall) - (prevPath\x * #cellDWidth + 3))
|
||||
prevPath = path()
|
||||
Wend
|
||||
hWall = mazeOutput(prevPath\y)\hWall
|
||||
mazeOutput(prevPath\y)\hWall = Left(hWall, prevPath\x * #cellDWidth + 2) + Mid(pathChars, #dir_ID + 1, 1) + Right(hWall, Len(hWall) - (prevPath\x * #cellDWidth + 3))
|
||||
|
||||
For y = 0 To mazeHeight
|
||||
PrintN(mazeOutput(y)\vWall): PrintN(mazeOutput(y)\hWall)
|
||||
Next
|
||||
EndIf
|
||||
EndProcedure
|
||||
|
||||
Procedure solveMaze(Array maze(2), *start.POINT, *finish.POINT, List Path.POINT())
|
||||
Protected mazeWidth = ArraySize(maze(), 1), mazeHeight = ArraySize(maze(), 2)
|
||||
Dim visited(mazeWidth + 1, mazeHeight + 1) ;includes padding for easy border detection
|
||||
|
||||
Protected i
|
||||
;mark outside border as already visited (off limits)
|
||||
For i = 1 To mazeWidth
|
||||
visited(i, 0) = #True: visited(i, mazeHeight + 1) = #True
|
||||
Next
|
||||
For i = 1 To mazeHeight
|
||||
visited(0, i) = #True: visited(mazeWidth + 1, i) = #True
|
||||
Next
|
||||
|
||||
Protected x = *start\x, y = *start\y, nextCellDir
|
||||
visited(x + offset(#visited, #dir_ID)\x, y + offset(#visited, #dir_ID)\y) = #True
|
||||
|
||||
ClearList(path())
|
||||
Repeat
|
||||
If x = *finish\x And y = *finish\y
|
||||
AddElement(path())
|
||||
path()\x = x: path()\y = y
|
||||
Break ;success
|
||||
EndIf
|
||||
|
||||
nextCellDir = #firstDir - 1
|
||||
For i = #firstDir To #numDirs
|
||||
If Not visited(x + offset(#visited, i)\x, y + offset(#visited, i)\y)
|
||||
If maze(x + offset(#wall, i)\x, y + offset(#wall, i)\y) & wallvalue(i) <> #Null
|
||||
nextCellDir = i: Break ;exit for/next search
|
||||
EndIf
|
||||
EndIf
|
||||
Next
|
||||
|
||||
If nextCellDir >= #firstDir
|
||||
visited(x + offset(#visited, nextCellDir)\x, y + offset(#visited, nextCellDir)\y) = #True
|
||||
|
||||
AddElement(path())
|
||||
path()\x = x: path()\y = y
|
||||
|
||||
x + offset(#maze, nextCellDir)\x: y + offset(#maze, nextCellDir)\y
|
||||
ElseIf ListSize(path()) > 0
|
||||
x = path()\x: y = path()\y
|
||||
DeleteElement(path())
|
||||
Else
|
||||
Break
|
||||
EndIf
|
||||
ForEver
|
||||
|
||||
EndProcedure
|
||||
|
||||
;demonstration
|
||||
If OpenConsole()
|
||||
Define.POINT start, finish
|
||||
start\x = Random(mazeWidth - 1): start\y = Random(mazeHeight - 1)
|
||||
finish\x = Random(mazeWidth - 1): finish\y = Random(mazeHeight - 1)
|
||||
NewList Path.POINT()
|
||||
solveMaze(maze(), start, finish, path())
|
||||
If ListSize(path()) > 0
|
||||
PrintN("Solution found for path between (" + Str(start\x) + ", " + Str(start\y) + ") and (" + Str(finish\x) + ", " + Str(finish\y) + ")")
|
||||
displayMazePath(maze(), path())
|
||||
Else
|
||||
PrintN("No solution found for path between (" + Str(start\x) + ", " + Str(start\y) + ") and (" + Str(finish\x) + ", " + Str(finish\y) + ")")
|
||||
EndIf
|
||||
|
||||
Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
|
||||
CloseConsole()
|
||||
EndIf
|
||||
50
Task/Maze-solving/Python/maze-solving.py
Normal file
50
Task/Maze-solving/Python/maze-solving.py
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# python 3
|
||||
|
||||
def Dijkstra(Graph, source):
|
||||
'''
|
||||
+ +---+---+
|
||||
| 0 1 2 |
|
||||
+---+ + +
|
||||
| 3 4 | 5
|
||||
+---+---+---+
|
||||
|
||||
>>> graph = ( # or ones on the diagonal
|
||||
... (0,1,0,0,0,0,),
|
||||
... (1,0,1,0,1,0,),
|
||||
... (0,1,0,0,0,1,),
|
||||
... (0,0,0,0,1,0,),
|
||||
... (0,1,0,1,0,0,),
|
||||
... (0,0,1,0,0,0,),
|
||||
... )
|
||||
...
|
||||
>>> Dijkstra(graph, 0)
|
||||
([0, 1, 2, 3, 2, 3], [1e+140, 0, 1, 4, 1, 2])
|
||||
>>> display_solution([1e+140, 0, 1, 4, 1, 2])
|
||||
5<2<1<0
|
||||
'''
|
||||
# Graph[u][v] is the weight from u to v (however 0 means infinity)
|
||||
infinity = float('infinity')
|
||||
n = len(graph)
|
||||
dist = [infinity]*n # Unknown distance function from source to v
|
||||
previous = [infinity]*n # Previous node in optimal path from source
|
||||
dist[source] = 0 # Distance from source to source
|
||||
Q = list(range(n)) # All nodes in the graph are unoptimized - thus are in Q
|
||||
while Q: # The main loop
|
||||
u = min(Q, key=lambda n:dist[n]) # vertex in Q with smallest dist[]
|
||||
Q.remove(u)
|
||||
if dist[u] == infinity:
|
||||
break # all remaining vertices are inaccessible from source
|
||||
for v in range(n): # each neighbor v of u
|
||||
if Graph[u][v] and (v in Q): # where v has not yet been visited
|
||||
alt = dist[u] + Graph[u][v]
|
||||
if alt < dist[v]: # Relax (u,v,a)
|
||||
dist[v] = alt
|
||||
previous[v] = u
|
||||
return dist,previous
|
||||
|
||||
def display_solution(predecessor):
|
||||
cell = len(predecessor)-1
|
||||
while cell:
|
||||
print(cell,end='<')
|
||||
cell = predecessor[cell]
|
||||
print(0)
|
||||
16
Task/Maze-solving/Racket/maze-solving-1.rkt
Normal file
16
Task/Maze-solving/Racket/maze-solving-1.rkt
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
;; Returns a path connecting two given cells in the maze
|
||||
;; find-path :: Maze Cell Cell -> (Listof Cell)
|
||||
(define (find-path m p1 p2)
|
||||
(match-define (maze N M tbl) m)
|
||||
(define (alternatives p prev) (remove prev (connections tbl p)))
|
||||
(define (dead-end? p prev) (empty? (alternatives p prev)))
|
||||
(define ((next-turn route) p)
|
||||
(define prev (car route))
|
||||
(cond
|
||||
[(equal? p p2) (cons p2 route)]
|
||||
[(dead-end? p prev) '()]
|
||||
[else (append-map (next-turn (cons p route))
|
||||
(alternatives p prev))]))
|
||||
(reverse
|
||||
(append-map (next-turn (list p1))
|
||||
(alternatives p1 (list p1)))))
|
||||
18
Task/Maze-solving/Racket/maze-solving-2.rkt
Normal file
18
Task/Maze-solving/Racket/maze-solving-2.rkt
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
;; Reads the maze from the textual form
|
||||
;; read-maze :: File-path -> Maze
|
||||
(define (read-maze file)
|
||||
(define tbl (make-hash))
|
||||
(with-input-from-file file
|
||||
(λ ()
|
||||
; the first line gives us the width of the maze
|
||||
(define N (/ (- (string-length (read-line)) 1) 4))
|
||||
; while reading other lines we get the height of the maze
|
||||
(define M
|
||||
(for/sum ([h (in-lines)] [v (in-lines)] [j (in-naturals)])
|
||||
(for ([i (in-range N)])
|
||||
(when (eq? #\space (string-ref h (* 4 (+ 1 i))))
|
||||
(connect! tbl (list i j) (list (+ i 1) j)))
|
||||
(when (eq? #\space (string-ref v (+ 1 (* 4 i))))
|
||||
(connect! tbl (list i j) (list i (+ j 1)))))
|
||||
1))
|
||||
(maze N M tbl))))
|
||||
22
Task/Maze-solving/Racket/maze-solving-3.rkt
Normal file
22
Task/Maze-solving/Racket/maze-solving-3.rkt
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
;; Shows a maze with a path connecting two given cells
|
||||
(define (show-path m p1 p2)
|
||||
(match-define (maze N M tbl) m)
|
||||
(define route (find-path m p1 p2))
|
||||
(for ([i N]) (display "+---"))
|
||||
(displayln "+")
|
||||
(for ([j M])
|
||||
(display "|")
|
||||
(for ([i (- N 0)])
|
||||
(if (member (list i j) route)
|
||||
(display " *")
|
||||
(display " "))
|
||||
(if (connected? tbl (list i j) (list (+ 1 i) j))
|
||||
(display " ")
|
||||
(display " |")))
|
||||
(newline)
|
||||
(for ([i N])
|
||||
(if (connected? tbl (list i j) (list i (+ j 1)))
|
||||
(display "+ ")
|
||||
(display "+---")))
|
||||
(displayln "+"))
|
||||
(newline))
|
||||
130
Task/Maze-solving/Raku/maze-solving.raku
Normal file
130
Task/Maze-solving/Raku/maze-solving.raku
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
constant mapping = :OPEN(' '),
|
||||
:N< ╵ >,
|
||||
:E< ╶ >,
|
||||
:NE< └ >,
|
||||
:S< ╷ >,
|
||||
:NS< │ >,
|
||||
:ES< ┌ >,
|
||||
:NES< ├ >,
|
||||
:W< ╴ >,
|
||||
:NW< ┘ >,
|
||||
:EW< ─ >,
|
||||
:NEW< ┴ >,
|
||||
:SW< ┐ >,
|
||||
:NSW< ┤ >,
|
||||
:ESW< ┬ >,
|
||||
:NESW< ┼ >,
|
||||
:TODO< x >,
|
||||
:TRIED< · >;
|
||||
|
||||
enum Sym (mapping.map: *.key);
|
||||
my @ch = mapping.map: *.value;
|
||||
|
||||
enum Direction <DeadEnd Up Right Down Left>;
|
||||
|
||||
sub gen_maze ( $X,
|
||||
$Y,
|
||||
$start_x = (^$X).pick * 2 + 1,
|
||||
$start_y = (^$Y).pick * 2 + 1 )
|
||||
{
|
||||
my @maze;
|
||||
push @maze, $[ flat ES, -N, (ESW, EW) xx $X - 1, SW ];
|
||||
push @maze, $[ flat (NS, TODO) xx $X, NS ];
|
||||
for 1 ..^ $Y {
|
||||
push @maze, $[ flat NES, EW, (NESW, EW) xx $X - 1, NSW ];
|
||||
push @maze, $[ flat (NS, TODO) xx $X, NS ];
|
||||
}
|
||||
push @maze, $[ flat NE, (EW, NEW) xx $X - 1, -NS, NW ];
|
||||
@maze[$start_y][$start_x] = OPEN;
|
||||
|
||||
my @stack;
|
||||
my $current = [$start_x, $start_y];
|
||||
loop {
|
||||
if my $dir = pick_direction( $current ) {
|
||||
@stack.push: $current;
|
||||
$current = move( $dir, $current );
|
||||
}
|
||||
else {
|
||||
last unless @stack;
|
||||
$current = @stack.pop;
|
||||
}
|
||||
}
|
||||
return @maze;
|
||||
|
||||
sub pick_direction([$x,$y]) {
|
||||
my @neighbors =
|
||||
(Up if @maze[$y - 2][$x]),
|
||||
(Down if @maze[$y + 2][$x]),
|
||||
(Left if @maze[$y][$x - 2]),
|
||||
(Right if @maze[$y][$x + 2]);
|
||||
@neighbors.pick or DeadEnd;
|
||||
}
|
||||
|
||||
sub move ($dir, @cur) {
|
||||
my ($x,$y) = @cur;
|
||||
given $dir {
|
||||
when Up { @maze[--$y][$x] = OPEN; @maze[$y][$x-1] -= E; @maze[$y--][$x+1] -= W; }
|
||||
when Down { @maze[++$y][$x] = OPEN; @maze[$y][$x-1] -= E; @maze[$y++][$x+1] -= W; }
|
||||
when Left { @maze[$y][--$x] = OPEN; @maze[$y-1][$x] -= S; @maze[$y+1][$x--] -= N; }
|
||||
when Right { @maze[$y][++$x] = OPEN; @maze[$y-1][$x] -= S; @maze[$y+1][$x++] -= N; }
|
||||
}
|
||||
@maze[$y][$x] = 0;
|
||||
[$x,$y];
|
||||
}
|
||||
}
|
||||
|
||||
sub display (@maze) {
|
||||
for @maze -> @y {
|
||||
for @y.rotor(2) -> ($w, $c) {
|
||||
print @ch[abs $w];
|
||||
if $c >= 0 { print @ch[$c] x 3 }
|
||||
else { print ' ', @ch[abs $c], ' ' }
|
||||
}
|
||||
say @ch[@y[*-1]];
|
||||
}
|
||||
}
|
||||
|
||||
sub solve (@maze is copy, @from = [1, 1], @to = [@maze[0] - 2, @maze - 2]) {
|
||||
my ($x, $y) = @from;
|
||||
my ($xto, $yto) = @to;
|
||||
my @stack;
|
||||
|
||||
sub drop-crumb($x,$y,$c) { @maze[$y][$x] = -$c }
|
||||
drop-crumb($x,$y,N);
|
||||
|
||||
loop {
|
||||
my $dir = pick_direction([$x,$y]);
|
||||
if $dir {
|
||||
($x, $y) = move($dir, [$x,$y]);
|
||||
return @maze if $x == $xto and $y == $yto;
|
||||
}
|
||||
else {
|
||||
@maze[$y][$x] = -TRIED;
|
||||
($x,$y) = @stack.pop;
|
||||
@maze[$y][$x] = -TRIED;
|
||||
($x,$y) = @stack.pop;
|
||||
}
|
||||
}
|
||||
|
||||
sub pick_direction([$x,$y]) {
|
||||
my @neighbors =
|
||||
(Up unless @maze[$y - 1][$x]),
|
||||
(Down unless @maze[$y + 1][$x]),
|
||||
(Left unless @maze[$y][$x - 1]),
|
||||
(Right unless @maze[$y][$x + 1]);
|
||||
@neighbors.pick or DeadEnd;
|
||||
}
|
||||
|
||||
sub move ($dir, @cur) {
|
||||
my ($x,$y) = @cur;
|
||||
given $dir {
|
||||
when Up { for ^2 { push @stack, $[$x,$y--]; drop-crumb $x,$y,S; } }
|
||||
when Down { for ^2 { push @stack, $[$x,$y++]; drop-crumb $x,$y,N; } }
|
||||
when Left { for ^2 { push @stack, $[$x--,$y]; drop-crumb $x,$y,E; } }
|
||||
when Right { for ^2 { push @stack, $[$x++,$y]; drop-crumb $x,$y,W; } }
|
||||
}
|
||||
$x,$y;
|
||||
}
|
||||
}
|
||||
|
||||
display solve gen_maze( 29, 19 );
|
||||
25
Task/Maze-solving/Red/maze-solving.red
Normal file
25
Task/Maze-solving/Red/maze-solving.red
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
Red ["Maze solver"]
|
||||
|
||||
do %mazegen.red
|
||||
print [
|
||||
"start:" start: random size - 1x1
|
||||
"end:" end: random size - 1x1
|
||||
]
|
||||
isnew?: function [pos] [not find visited pos]
|
||||
open?: function [pos d] [
|
||||
o: pos/y * size/x + pos/x + 1
|
||||
0 = pick walls/:o d
|
||||
]
|
||||
expand: function [pos][
|
||||
either any [
|
||||
all [pos/x > 0 isnew? p: pos - 1x0 open? p 1]
|
||||
all [pos/x < (size/x - 1) isnew? p: pos + 1x0 open? pos 1]
|
||||
all [pos/y > 0 isnew? p: pos - 0x1 open? p 2]
|
||||
all [pos/y < (size/y - 1) isnew? p: pos + 0x1 open? pos 2]
|
||||
][append visited p insert path p][remove path]
|
||||
path/1
|
||||
]
|
||||
path: reduce [start]
|
||||
visited: []
|
||||
until [end = expand path/1]
|
||||
print reverse path
|
||||
75
Task/Maze-solving/Ruby/maze-solving.rb
Normal file
75
Task/Maze-solving/Ruby/maze-solving.rb
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
class Maze
|
||||
# Solve via breadth-first algorithm.
|
||||
# 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
|
||||
|
||||
# Clean up.
|
||||
reset_visiting_state
|
||||
|
||||
# Enqueue start position.
|
||||
@queue = []
|
||||
enqueue_cell([], @start_x, @start_y)
|
||||
|
||||
# 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
|
||||
# Get the next path.
|
||||
path = @queue.shift
|
||||
# The cell to visit is the last entry in the path.
|
||||
x, y = path.last
|
||||
|
||||
# Have we reached the end yet?
|
||||
return path if x == @end_x && y == @end_y
|
||||
|
||||
# Mark cell as visited.
|
||||
@visited[x][y] = true
|
||||
|
||||
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
|
||||
|
||||
nil # No solution yet.
|
||||
end
|
||||
|
||||
# Enqueue a new coordinate to visit.
|
||||
def enqueue_cell(path, x, y)
|
||||
# Add new coordinates to the current path and enqueue the new path.
|
||||
@queue << path + [[x, y]]
|
||||
end
|
||||
end
|
||||
|
||||
# Demonstration:
|
||||
maze = Maze.new 20, 10
|
||||
maze.solve
|
||||
maze.print
|
||||
253
Task/Maze-solving/Rust/maze-solving.rust
Normal file
253
Task/Maze-solving/Rust/maze-solving.rust
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
use rand::{thread_rng, Rng, rngs::ThreadRng};
|
||||
|
||||
const WIDTH: usize = 16;
|
||||
const HEIGHT: usize = 16;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
struct Cell {
|
||||
col: usize,
|
||||
row: usize,
|
||||
}
|
||||
|
||||
impl Cell {
|
||||
fn from(col: usize, row: usize) -> Cell {
|
||||
Cell {col, row}
|
||||
}
|
||||
}
|
||||
|
||||
struct Maze {
|
||||
cells: [[bool; HEIGHT]; WIDTH], //cell visited/non visited
|
||||
walls_h: [[bool; WIDTH]; HEIGHT + 1], //horizontal walls existing/removed
|
||||
walls_v: [[bool; WIDTH + 1]; HEIGHT], //vertical walls existing/removed
|
||||
thread_rng: ThreadRng, //Random numbers generator
|
||||
}
|
||||
|
||||
impl Maze {
|
||||
|
||||
///Inits the maze, with all the cells unvisited and all the walls active
|
||||
fn new() -> Maze {
|
||||
Maze {
|
||||
cells: [[true; HEIGHT]; WIDTH],
|
||||
walls_h: [[true; WIDTH]; HEIGHT + 1],
|
||||
walls_v: [[true; WIDTH + 1]; HEIGHT],
|
||||
thread_rng: thread_rng(),
|
||||
}
|
||||
}
|
||||
|
||||
///Randomly chooses the starting cell
|
||||
fn first(&mut self) -> Cell {
|
||||
Cell::from(self.thread_rng.gen_range(0, WIDTH), self.thread_rng.gen_range(0, HEIGHT))
|
||||
}
|
||||
|
||||
///Opens the enter and exit doors
|
||||
fn open_doors(&mut self) {
|
||||
let from_top: bool = self.thread_rng.gen();
|
||||
let limit = if from_top { WIDTH } else { HEIGHT };
|
||||
let door = self.thread_rng.gen_range(0, limit);
|
||||
let exit = self.thread_rng.gen_range(0, limit);
|
||||
if from_top {
|
||||
self.walls_h[0][door] = false;
|
||||
self.walls_h[HEIGHT][exit] = false;
|
||||
} else {
|
||||
self.walls_v[door][0] = false;
|
||||
self.walls_v[exit][WIDTH] = false;
|
||||
}
|
||||
}
|
||||
|
||||
///Removes a wall between the two Cell arguments
|
||||
fn remove_wall(&mut self, cell1: &Cell, cell2: &Cell) {
|
||||
if cell1.row == cell2.row {
|
||||
self.walls_v[cell1.row][if cell1.col > cell2.col { cell1.col } else { cell2.col }] = false;
|
||||
} else {
|
||||
self.walls_h[if cell1.row > cell2.row { cell1.row } else { cell2.row }][cell1.col] = false;
|
||||
};
|
||||
}
|
||||
|
||||
///Returns a random non-visited neighbor of the Cell passed as argument
|
||||
fn neighbor(&mut self, cell: &Cell) -> Option<Cell> {
|
||||
self.cells[cell.col][cell.row] = false;
|
||||
let mut neighbors = Vec::new();
|
||||
if cell.col > 0 && self.cells[cell.col - 1][cell.row] { neighbors.push(Cell::from(cell.col - 1, cell.row)); }
|
||||
if cell.row > 0 && self.cells[cell.col][cell.row - 1] { neighbors.push(Cell::from(cell.col, cell.row - 1)); }
|
||||
if cell.col < WIDTH - 1 && self.cells[cell.col + 1][cell.row] { neighbors.push(Cell::from(cell.col + 1, cell.row)); }
|
||||
if cell.row < HEIGHT - 1 && self.cells[cell.col][cell.row + 1] { neighbors.push(Cell::from(cell.col, cell.row + 1)); }
|
||||
if neighbors.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let next = neighbors.get(self.thread_rng.gen_range(0, neighbors.len())).unwrap();
|
||||
self.remove_wall(cell, next);
|
||||
Some(*next)
|
||||
}
|
||||
}
|
||||
|
||||
///Builds the maze (runs the Depth-first search algorithm)
|
||||
fn build(&mut self) {
|
||||
let mut cell_stack: Vec<Cell> = Vec::new();
|
||||
let mut next = self.first();
|
||||
loop {
|
||||
while let Some(cell) = self.neighbor(&next) {
|
||||
cell_stack.push(cell);
|
||||
next = cell;
|
||||
}
|
||||
match cell_stack.pop() {
|
||||
Some(cell) => next = cell,
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///MAZE SOLVING: Find the starting cell of the solution
|
||||
fn solution_first(&self) -> Option<Cell> {
|
||||
for (i, wall) in self.walls_h[0].iter().enumerate() {
|
||||
if !wall {
|
||||
return Some(Cell::from(i, 0));
|
||||
}
|
||||
}
|
||||
for (i, wall) in self.walls_v.iter().enumerate() {
|
||||
if !wall[0] {
|
||||
return Some(Cell::from(0, i));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
///MAZE SOLVING: Find the last cell of the solution
|
||||
fn solution_last(&self) -> Option<Cell> {
|
||||
for (i, wall) in self.walls_h[HEIGHT].iter().enumerate() {
|
||||
if !wall {
|
||||
return Some(Cell::from(i, HEIGHT - 1));
|
||||
}
|
||||
}
|
||||
for (i, wall) in self.walls_v.iter().enumerate() {
|
||||
if !wall[WIDTH] {
|
||||
return Some(Cell::from(WIDTH - 1, i));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
///MAZE SOLVING: Get the next candidate cell
|
||||
fn solution_next(&mut self, cell: &Cell) -> Option<Cell> {
|
||||
self.cells[cell.col][cell.row] = false;
|
||||
let mut neighbors = Vec::new();
|
||||
if cell.col > 0 && self.cells[cell.col - 1][cell.row] && !self.walls_v[cell.row][cell.col] { neighbors.push(Cell::from(cell.col - 1, cell.row)); }
|
||||
if cell.row > 0 && self.cells[cell.col][cell.row - 1] && !self.walls_h[cell.row][cell.col] { neighbors.push(Cell::from(cell.col, cell.row - 1)); }
|
||||
if cell.col < WIDTH - 1 && self.cells[cell.col + 1][cell.row] && !self.walls_v[cell.row][cell.col + 1] { neighbors.push(Cell::from(cell.col + 1, cell.row)); }
|
||||
if cell.row < HEIGHT - 1 && self.cells[cell.col][cell.row + 1] && !self.walls_h[cell.row + 1][cell.col] { neighbors.push(Cell::from(cell.col, cell.row + 1)); }
|
||||
if neighbors.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let next = neighbors.get(self.thread_rng.gen_range(0, neighbors.len())).unwrap();
|
||||
Some(*next)
|
||||
}
|
||||
}
|
||||
|
||||
///MAZE SOLVING: solve the maze
|
||||
///Uses self.cells to store the solution cells (true)
|
||||
fn solve(&mut self) {
|
||||
self.cells = [[true; HEIGHT]; WIDTH];
|
||||
let mut solution: Vec<Cell> = Vec::new();
|
||||
let mut next = self.solution_first().unwrap();
|
||||
solution.push(next);
|
||||
let last = self.solution_last().unwrap();
|
||||
'main: loop {
|
||||
while let Some(cell) = self.solution_next(&next) {
|
||||
solution.push(cell);
|
||||
if cell == last {
|
||||
break 'main;
|
||||
}
|
||||
next = cell;
|
||||
}
|
||||
solution.pop().unwrap();
|
||||
next = *solution.last().unwrap();
|
||||
}
|
||||
self.cells = [[false; HEIGHT]; WIDTH];
|
||||
for cell in solution {
|
||||
self.cells[cell.col][cell.row] = true;
|
||||
}
|
||||
}
|
||||
|
||||
///MAZE SOLVING: Ask if cell is part of the solution (cells[col][row] == true)
|
||||
fn is_solution(&self, col: usize, row: usize) -> bool {
|
||||
self.cells[col][row]
|
||||
}
|
||||
|
||||
///Displays a wall
|
||||
///MAZE SOLVING: Leave space for printing '*' if cell is part of the solution
|
||||
/// (only when painting vertical walls)
|
||||
///
|
||||
// fn paint_wall(h_wall: bool, active: bool) {
|
||||
// if h_wall {
|
||||
// print!("{}", if active { "+---" } else { "+ " });
|
||||
// } else {
|
||||
// print!("{}", if active { "| " } else { " " });
|
||||
// }
|
||||
// }
|
||||
fn paint_wall(h_wall: bool, active: bool, with_solution: bool) {
|
||||
if h_wall {
|
||||
print!("{}", if active { "+---" } else { "+ " });
|
||||
} else {
|
||||
print!("{}{}", if active { "|" } else { " " }, if with_solution { "" } else { " " });
|
||||
}
|
||||
}
|
||||
|
||||
///MAZE SOLVING: Paint * if cell is part of the solution
|
||||
fn paint_solution(is_part: bool) {
|
||||
print!("{}", if is_part { " * " } else {" "});
|
||||
}
|
||||
|
||||
///Displays a final wall for a row
|
||||
fn paint_close_wall(h_wall: bool) {
|
||||
if h_wall { println!("+") } else { println!() }
|
||||
}
|
||||
|
||||
///Displays a whole row of walls
|
||||
///MAZE SOLVING: Displays a whole row of walls and, optionally, the included solution cells.
|
||||
// fn paint_row(&self, h_walls: bool, index: usize) {
|
||||
// let iter = if h_walls { self.walls_h[index].iter() } else { self.walls_v[index].iter() };
|
||||
// for &wall in iter {
|
||||
// Maze::paint_wall(h_walls, wall);
|
||||
// }
|
||||
// Maze::paint_close_wall(h_walls);
|
||||
// }
|
||||
fn paint_row(&self, h_walls: bool, index: usize, with_solution: bool) {
|
||||
let iter = if h_walls { self.walls_h[index].iter() } else { self.walls_v[index].iter() };
|
||||
for (col, &wall) in iter.enumerate() {
|
||||
Maze::paint_wall(h_walls, wall, with_solution);
|
||||
if !h_walls && with_solution && col < WIDTH {
|
||||
Maze::paint_solution(self.is_solution(col, index));
|
||||
}
|
||||
}
|
||||
Maze::paint_close_wall(h_walls);
|
||||
}
|
||||
|
||||
///Paints the maze
|
||||
///MAZE SOLVING: Displaying the solution is an option
|
||||
// fn paint(&self) {
|
||||
// for i in 0 .. HEIGHT {
|
||||
// self.paint_row(true, i);
|
||||
// self.paint_row(false, i);
|
||||
// }
|
||||
// self.paint_row(true, HEIGHT);
|
||||
// }
|
||||
fn paint(&self, with_solution: bool) {
|
||||
for i in 0 .. HEIGHT {
|
||||
self.paint_row(true, i, with_solution);
|
||||
self.paint_row(false, i, with_solution);
|
||||
}
|
||||
self.paint_row(true, HEIGHT, with_solution);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut maze = Maze::new();
|
||||
maze.build();
|
||||
maze.open_doors();
|
||||
|
||||
println!("The maze:");
|
||||
maze.paint(false);
|
||||
|
||||
maze.solve();
|
||||
println!("The maze, solved:");
|
||||
maze.paint(true);
|
||||
}
|
||||
56
Task/Maze-solving/Tcl/maze-solving.tcl
Normal file
56
Task/Maze-solving/Tcl/maze-solving.tcl
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
oo::define maze {
|
||||
method solve {} {
|
||||
### Initialization of visited matrix and location/path queue
|
||||
set visited [lrepeat $x [lrepeat $y 0]]
|
||||
set queue {0 0 {}}
|
||||
|
||||
### Loop to do the searching ###
|
||||
while 1 {
|
||||
# Check for running out of path; an error in maze construction
|
||||
if {[llength $queue] == 0} {
|
||||
error "cannot reach finish"
|
||||
}
|
||||
# Visit the next square from the queue
|
||||
set queue [lassign $queue cx cy path]
|
||||
if {[lindex $visited $cx $cy]} continue
|
||||
lset visited $cx $cy 1
|
||||
lappend path $cx $cy
|
||||
# Check for reaching the goal
|
||||
if {$cx == $x-1 && $cy == $y-1} break
|
||||
# Add the square in each direction to the queue if a move there is legal
|
||||
foreach {dx dy} {0 1 1 0 0 -1 -1 0} {
|
||||
set nx [expr {$cx + $dx}]; set ny [expr {$cy + $dy}]
|
||||
if {
|
||||
$nx >= 0 && $nx < $x && $ny >= 0 && $ny < $y
|
||||
&& ($dx && idx($verti, min($cx,$nx), $cy) ||
|
||||
$dy && idx($horiz, $cx, min($cy,$ny)))
|
||||
} then {
|
||||
lappend queue $nx $ny $path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
### Loop to set up the path rendering ###
|
||||
# (-2,-2) is just a marker that isn't next to the maze at all, so
|
||||
# guaranteeing the use of the last 'else' clause
|
||||
foreach {cx cy} $path {nx ny} [concat [lrange $path 2 end] -2 -2] {
|
||||
if {$nx-$cx == 1} {
|
||||
lset content $cx $cy "v"
|
||||
} elseif {$nx-$cx == -1} {
|
||||
lset content $cx $cy "^"
|
||||
} elseif {$ny-$cy == -1} {
|
||||
lset content $cx $cy "<"
|
||||
} else {
|
||||
lset content $cx $cy ">"
|
||||
}
|
||||
}
|
||||
|
||||
### Return the path ###
|
||||
return $path
|
||||
}
|
||||
}
|
||||
|
||||
# Do the solution (we ignore the returned path here...)
|
||||
m solve
|
||||
# Print it out
|
||||
puts [m view]
|
||||
119
Task/Maze-solving/Wren/maze-solving.wren
Normal file
119
Task/Maze-solving/Wren/maze-solving.wren
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
import "os" for Process
|
||||
import "/ioutil" for File, FileUtil
|
||||
|
||||
/*
|
||||
* 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
|
||||
* character list, because we'll want mutability when drawing the solution later.
|
||||
*/
|
||||
var decimateHorizontally = Fn.new { |lines|
|
||||
var width = ((lines[0].count + 1)/2).floor
|
||||
var c = List.filled(lines.count, null)
|
||||
for (i in 0...lines.count) {
|
||||
c[i] = List.filled(width, null)
|
||||
for (j in 0...width) c[i][j] = lines[i][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.
|
||||
*/
|
||||
var solveMazeRecursively // recursive function
|
||||
solveMazeRecursively = Fn.new { |maze, x, y, d|
|
||||
var ok = false
|
||||
var i = 0
|
||||
while (i < 4 && !ok) {
|
||||
if (i != d) {
|
||||
// 0 = up, 1 = right, 2 = down, 3 = left
|
||||
if (i == 0) {
|
||||
if (maze[y - 1][x] == " ") ok = solveMazeRecursively.call(maze, x, y - 2, 2)
|
||||
} else if (i == 1) {
|
||||
if (maze[y][x + 1] == " ") ok = solveMazeRecursively.call(maze, x + 2, y, 3)
|
||||
} else if (i == 2) {
|
||||
if (maze[y + 1][x] == " ") ok = solveMazeRecursively.call(maze, x, y + 2, 0)
|
||||
} else if (i == 3) {
|
||||
if (maze[y][x - 1] == " ") ok = solveMazeRecursively.call(maze, x - 2, y, 1)
|
||||
}
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
// 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] = "*"
|
||||
if (d == 0) {
|
||||
maze[y - 1][x] = "*"
|
||||
} else if (d == 1) {
|
||||
maze[y][x + 1] = "*"
|
||||
} else if (d == 2) {
|
||||
maze[y + 1][x] = "*"
|
||||
} else if (d == 3) {
|
||||
maze[y][x - 1] = "*"
|
||||
}
|
||||
}
|
||||
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.
|
||||
*/
|
||||
var solveMaze = Fn.new { |maze|
|
||||
solveMazeRecursively.call(maze, maze[0].count - 2, maze.count - 2, -1)
|
||||
}
|
||||
|
||||
/*
|
||||
* Opposite of decimateHorizontally(). Adds extra characters to make
|
||||
* the maze "look right", and converts each line from a char list to a
|
||||
* string at the same time.
|
||||
*/
|
||||
var expandHorizontally = Fn.new { |maze|
|
||||
var tmp = List.filled(3, " ")
|
||||
var lines = List.filled(maze.count, null)
|
||||
for (i in 0...maze.count) {
|
||||
var sb = ""
|
||||
for (j in 0...maze[i].count) {
|
||||
if (j % 2 == 0) {
|
||||
sb = sb + maze[i][j]
|
||||
} else {
|
||||
for (k in 0..2) tmp[k] = maze[i][j]
|
||||
if (tmp[1] == "*") {
|
||||
tmp[0] = " "
|
||||
tmp[2] = " "
|
||||
}
|
||||
sb = sb + tmp.join()
|
||||
}
|
||||
}
|
||||
lines[i] = sb
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
/*
|
||||
* Accepts a maze as generated by:
|
||||
* http://rosettacode.org/wiki/Maze_generation#Wren
|
||||
* in a file whose name is specified as a command-line argument.
|
||||
*/
|
||||
var args = Process.arguments
|
||||
if (args.count != 1) {
|
||||
System.print("The maze file to be read should be passed as a single command line argument.")
|
||||
return
|
||||
}
|
||||
if (!File.exists(args[0])) {
|
||||
System.print("Sorry %(args[0]) does not exist.")
|
||||
return
|
||||
}
|
||||
var lines = FileUtil.readLines(args[0]).where { |l| l != "" }.toList
|
||||
var maze = decimateHorizontally.call(lines)
|
||||
solveMaze.call(maze)
|
||||
var solvedLines = expandHorizontally.call(maze)
|
||||
System.print(solvedLines.join("\n"))
|
||||
43
Task/Maze-solving/Zkl/maze-solving.zkl
Normal file
43
Task/Maze-solving/Zkl/maze-solving.zkl
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
ver,hor:=make_maze(); // see above link for this code
|
||||
|
||||
fcn munge(a,b){ String(a[0,2],b,a[3,*]) } // "+---" --> "+-*-"
|
||||
|
||||
fcn solveMaze(ver,hor, a,b, u,v, w,h){
|
||||
if (a==u and b==v) return(True);
|
||||
|
||||
sh:=hor[b][a]; sv:=ver[b][a];
|
||||
hor[b][a]=munge(sh,"*"); ver[b][a]=munge(sv,"*"); // drop breadcrumb
|
||||
|
||||
foreach dx,dy in (T( T(0,-1),T(1,0),T(0,1),T(-1,0) )){
|
||||
x:=a+dx; y:=b+dy; hy:=hor[y]; vy:=ver[y];
|
||||
if ( (0<=x<w) and (0<=y<h) and // (x,y) in bounds
|
||||
(dx==0 or (dx== 1 and vy[x]==" ") or // horizontal
|
||||
(dx==-1 and vy[a][0]==" " and vy[x][2]!="*")) and
|
||||
(dy==0 or (dy== 1 and hy[x]=="+ ") or // vertical
|
||||
(dy==-1 and hor[b][a][1]==" " and hy[x][2]!="*"))
|
||||
)
|
||||
{
|
||||
sh:=hy[x];
|
||||
if(solveMaze(ver,hor, x,y, u,v, w,h)){
|
||||
hy[x]=sh; // remove splat on wall but not floor while backing out
|
||||
return(True);
|
||||
}
|
||||
}
|
||||
}
|
||||
hor[b][a]=sh; ver[b][a]=sv; // pick up breadcrumb when backtracking
|
||||
return(False);
|
||||
}
|
||||
|
||||
w:=(hor[0].len() - 1); h:=(hor.len() - 1);
|
||||
startx:=(0).random(w); starty:=(0).random(h);
|
||||
endx :=(0).random(w); endy :=(0).random(h);
|
||||
|
||||
sh:=hor[starty][startx];
|
||||
if (not solveMaze(ver,hor, startx,starty, endx,endy, w,h))
|
||||
println("No solution path found.");
|
||||
else{
|
||||
hor[starty][startx]=sh;
|
||||
ver[starty][startx]=munge(ver[starty][startx],"S");
|
||||
ver[endy][endx] =munge(ver[endy][endx],"E");
|
||||
foreach a,b in (hor.zip(ver)) { println(a.concat(),"\n",b.concat()) }
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue