Last active
March 19, 2017 11:46
-
-
Save SteveGilham/ccb8d6a8ac5e6aec77d8070e1e100f6d to your computer and use it in GitHub Desktop.
Building a sidewinder maze as per https://jeremybytes.blogspot.co.uk/2017/03/approaching-function-programming.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open System.Linq | |
type Cell = North | East | West | Root | |
type Connected = { exit: Cell; West : Connected option; South : Connected option; East : Connected option } | |
let rows = 10 | |
let cols = 10 | |
let rand = System.Random() | |
let row () = Seq.append (Enumerable.Repeat(East, cols - 1)) (Seq.singleton Root) |> Seq.toList | |
let placeholder() = Enumerable.Repeat({ exit=Root; South=None; West=None; East=None}, cols) |> Seq.toList | |
let maingrid() = Enumerable.Repeat(placeholder(), rows - 1) |> Seq.toList | |
let key x = | |
match x.exit with | |
| North -> "N" | |
| East -> "E" | |
| West -> "W" | |
| _ -> "X" | |
let linked x = | |
match x.South with | |
| None -> " " | |
| _ -> "V" | |
let rec slice l cuts = | |
match cuts with | |
| [] -> [] | |
| (x::xs) -> let (head, tail) = List.splitAt x l | |
head :: (slice tail xs) | |
// grow from the bottom up | |
let g = maingrid() |> List.scan (fun accum r -> let links = accum | |
|> List.map (fun cell -> match cell.exit with | |
| North -> Some cell | |
| _ -> None) | |
let runs = r | |
|> List.map (fun cell -> rand.Next(2)) | |
|> List.scan ( + ) 0 | |
|> List.tail | |
|> List.groupBy id | |
|> List.sortBy fst | |
|> List.map (fun (k, s) -> let l = Seq.length s | |
let cut = rand.Next(l - 1) | |
(l, [cut; 1; l - (cut+1)])) | |
let relinks = slice links (runs |> List.map fst) | |
let matched = List.zip relinks (runs |> List.map snd) | |
|> List.map (fun (link,cuts) -> let (e::n::w::[]) = slice link cuts | |
let e' = e | |
|> List.scan (fun accum cell -> Some { exit=East; South=cell; West=accum; East=None }) None | |
|> List.tail | |
|> List.map Option.get | |
let w' = w | |
|> List.rev | |
|> List.scan (fun accum cell -> Some { exit=West; South=cell; East=accum; West=None }) None | |
|> List.tail | |
|> List.map Option.get | |
|> List.rev | |
List.concat [e'; | |
[{exit=North; South=List.head n; East=List.tryHead w'; West = List.tryLast e'}]; | |
w']) | |
List.concat matched ) (placeholder()) | |
|> List.tail | |
|> List.rev | |
let toprow = g | |
|> List.head | |
|> List.zip <| row () | |
|> List.scan (fun accum (cell, exit) -> let s = match cell.exit with | |
| North -> Some cell | |
| _ -> None | |
Some { exit=exit; South=s; West=accum; East=None }) None | |
|> List.tail | |
|> List.map Option.get | |
let grid = toprow :: g;; | |
grid |> List.iter (fun r -> printf "+" | |
Seq.iter (fun cell -> match cell.exit with | |
| North -> printf " " | |
| _ -> printf "---" | |
printf "+") r | |
printfn "" | |
printf "| %s%s" (linked <| Seq.head r) (match (Seq.head r).East with | |
| None -> " " | |
| _ -> ">") | |
r |> Seq.pairwise | |
|> Seq.iter (fun cells -> let l = match (fst cells).exit, (snd cells).exit with | |
| (_, West) | |
| (East, _) -> (" ") // (East, West) never happens | |
| _ -> "|" | |
let x,y = match (snd cells).West, (snd cells).East with | |
| (Some _, Some _) -> ("<", ">") | |
| (Some _, _) -> ("<", " ") | |
| (_, Some _) -> (" ", ">") | |
| _ -> (" ", " ") | |
printf "%s%s%s%s" l x (linked <| snd cells) y) | |
printfn "|") | |
grid |> List.head |> (fun r -> printf "+" | |
Seq.iter (fun cell -> printf "---+") r | |
printfn "" ) | |
;; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment