September 2017 Update
This commit is contained in:
parent
bba7bfd280
commit
ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions
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
|
||||
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))
|
||||
|
|
@ -13,6 +13,8 @@ bool solveMaze(char[][] maze, in V2 s, in V2 end) pure nothrow @safe @nogc {
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#!/usr/bin/runhaskell
|
||||
|
||||
import Data.Maybe
|
||||
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)
|
||||
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)
|
||||
|
|
@ -22,41 +22,47 @@ substitute orig pos el =
|
|||
|
||||
-- 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 $ substitute row x '*'
|
||||
where row = maze !! y
|
||||
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 :: [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]
|
||||
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 =
|
||||
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
|
||||
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)
|
||||
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 = interact main'
|
||||
where main' x = unlines $ fromMaybe ["can't solve"] $ solve $ lines x
|
||||
main =
|
||||
let main_ = unlines . fromMaybe ["can_t solve"] . solve . lines
|
||||
in interact main_
|
||||
|
|
|
|||
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();
|
||||
}
|
||||
58
Task/Maze-solving/Phix/maze-solving.phix
Normal file
58
Task/Maze-solving/Phix/maze-solving.phix
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
constant w = 11, h = 8
|
||||
|
||||
sequence wall = join(repeat("+",w+1),"---")&"\n",
|
||||
cell = join(repeat("|",w+1)," ? ")&"\n",
|
||||
grid = split(join(repeat(wall,h+1),cell),'\n')
|
||||
|
||||
procedure amaze(integer x, integer y)
|
||||
grid[y][x] = ' ' -- mark cell visited
|
||||
sequence p = shuffle({{x-4,y},{x,y+2},{x+4,y},{x,y-2}})
|
||||
for i=1 to length(p) do
|
||||
integer {nx,ny} = p[i]
|
||||
if nx>1 and nx<w*4 and ny>1 and ny<=2*h and grid[ny][nx]='?' then
|
||||
integer mx = (x+nx)/2
|
||||
grid[(y+ny)/2][mx-1..mx+1] = ' ' -- knock down wall
|
||||
amaze(nx,ny)
|
||||
end if
|
||||
end for
|
||||
end procedure
|
||||
|
||||
integer dx,dy -- door location (in a wall!)
|
||||
|
||||
function solve_maze(integer x, y)
|
||||
sequence p = {{x-4,y},{x,y+2},{x+4,y},{x,y-2}}
|
||||
for d=1 to length(p) do
|
||||
integer {nx,ny} = p[d]
|
||||
integer {wx,wy} = {(x+nx)/2,(y+ny)/2}
|
||||
if grid[wy][wx]=' ' then
|
||||
grid[wy][wx] = "-:-:"[d] -- mark path
|
||||
if {wx,wy}={dx,dy} then return true end if
|
||||
if grid[ny][nx]=' ' then
|
||||
grid[ny][nx] = 'o' -- mark cell
|
||||
if solve_maze(nx,ny) then return true end if
|
||||
grid[ny][nx] = ' ' -- unmark cell
|
||||
end if
|
||||
grid[wy][wx] = ' ' -- unmark path
|
||||
end if
|
||||
end for
|
||||
return false
|
||||
end function
|
||||
|
||||
function heads()
|
||||
return rand(2)=1 -- toin coss 50:50 true(1)/false(0)
|
||||
end function
|
||||
|
||||
integer {x,y} = {(rand(w)*4)-1,rand(h)*2}
|
||||
amaze(x,y)
|
||||
-- mark start pos
|
||||
grid[y][x] = '*'
|
||||
-- add a random door (heads=rhs/lhs, tails=top/btm)
|
||||
if heads() then
|
||||
{dy,dx} = {rand(h)*2,heads()*w*4+1}
|
||||
grid[dy][dx] = ' '
|
||||
else
|
||||
{dy,dx} = {heads()*h*2+1,rand(w)*4-1}
|
||||
grid[dy][dx-1..dx+1] = ' '
|
||||
end if
|
||||
{} = solve_maze(x,y)
|
||||
puts(1,join(grid,'\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