-
Notifications
You must be signed in to change notification settings - Fork 20
/
maze.sml
109 lines (98 loc) · 2.79 KB
/
maze.sml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
(* Maze generator in SML
* Joe Wingbermuehle
* 2010-10-09
*)
(* Signature of the maze generator. *)
signature MAZE =
sig
type t
val show : t -> unit
val generate : t -> unit
val initialize : int * int -> t
end
(* Structure used for generating mazes. *)
structure Maze :> MAZE =
struct
(* The maze type. *)
type t = int * int * int Array.array
(* Get the array offset from the x and y coordinates. *)
fun index(m, x, y) =
let
val (width, _, _) = m
in
y * width + x
end
(* Display a maze. *)
fun show m =
let
val (width, height, a) = m
fun display 0 = print " "
| display _ = print "[]"
fun show_xy(x, y) =
if x < width then (
display(Array.sub(a, index(m, x, y)));
show_xy(x + 1, y)
) else (
print "\n";
if y + 1 < height then
show_xy(0, y + 1)
else
()
)
in
show_xy(0, 0)
end
(* Start carving a maze at x, y. *)
fun carve(r, m, x, y) =
let
val (width, height, a) = m
fun get_update 0 = (1, 0)
| get_update 1 = (0, 1)
| get_update 2 = (0-1, 0)
| get_update _ = (0, 0-1)
fun move(dir, cnt) =
let
val (dx, dy) = get_update(dir)
val (x1, y1) = (x + dx, y + dy)
val (x2, y2) = (x1 + dx, y1 + dy)
val offset1 = index(m, x1, y1)
val offset2 = index(m, x2, y2)
in
if x2 > 0 andalso x2 < width andalso y2 > 0 andalso y2 < height
andalso Array.sub(a, offset1) = 1
andalso Array.sub(a, offset2) = 1 then (
Array.update(a, offset1, 0);
Array.update(a, offset2, 0);
carve(r, m, x2, y2)
) else ();
if cnt < 3 then move((dir + 1) mod 4, cnt + 1) else ()
end
val dir = Random.randNat r mod 4
in
move(dir, 0)
end
(* Generate a random maze. *)
fun generate m =
let
val (width, height, a) = m
val date = Date.fromTimeUniv (Time.now ())
val r = Random.rand(Date.minute date, Date.second date)
in
Array.update(a, index(m, 1, 1), 0);
carve(r, m, 1, 1);
Array.update(a, index(m, 1, 0), 0);
Array.update(a, index(m, width - 2, height - 1), 0)
end
(* Initialize an empty maze. *)
fun initialize(width, height) =
(width, height, Array.array(width * height, 1))
end
(* Generate and dispaly a random maze. *)
val () =
let
val m = Maze.initialize(39, 23)
in
Maze.generate m;
Maze.show m;
OS.Process.exit 0
end