-
Notifications
You must be signed in to change notification settings - Fork 0
/
dungeon.mar
182 lines (161 loc) · 4.9 KB
/
dungeon.mar
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
import stdlib.mar
import ui.mar
fun left(p: Point, n: Int): Point { Point { x = p.x - n, y = p.y } }
fun right(p: Point, n: Int): Point { Point { x = p.x + n, y = p.y } }
fun above(p: Point, n: Int): Point { Point { x = p.x, y = p.y - n } }
fun below(p: Point, n: Int): Point { Point { x = p.x, y = p.y + n } }
| Level
struct Level {
tiles: Matrix[Tile],
player: Point,
}
enum Tile { free, wall }
fun get(level: Level, point: Point): Tile {
level.tiles.get_maybe(point) or Tile.wall
}
fun set(level: Level, point: Point, tile: Tile) {
if level.tiles.&.get_maybe_ref(point) is some(t) then t.* = tile
}
| Level Generation
fun generate_level(random: &Random): Level {
var level = Level {
tiles = filled_matrix(40 @ 30, Tile.wall),
player = 1 @ 1,
}
for i in 0..20 do
loop {
var x = random.next_int(2..{level.tiles.width - 2})
var y = random.next_int(2..{level.tiles.height - 2})
var w = random.next_int(1..10)
var h = random.next_int(1..7)
println("Placing room at {x} {y} ({w} * {h})")
for xx in x..+w do
for yy in y..+h do
level.set(xx @ yy, Tile.free)
break
}
{ | Place the player.
var placed = false
var i = 0
loop {
if placed then break
for j in 0..i do
if level.get(j @ {i - j}) is free then {
level.player = j @ {i - j}
placed = true
break
}
i = i + 1
}
}
{ | Make sure the rooms are reachable by using a flood fill.
var reachable = filled_matrix(level.tiles.size(), false)
var queue = queue[Point]()
queue.&.push_back(level.player)
loop {
var pos = queue.&.pop_front_maybe() or break
if not({0 @ 0}.by(level.tiles.size()).contains(pos)) then continue
if level.get(pos) is wall then continue
if reachable.get(pos) then continue
reachable.&.set(pos, true)
for direction in list(0 @ 1, 0 @ {0-1}, 1 @ 0, {0-1} @ 0) do
queue.&.push_back(pos + direction)
}
for y in 0..level.tiles.height do {
for x in 0..level.tiles.width do
stdout."{if reachable.get(x @ y) then "x" else "_"}"
stdout."\n"
}
var distance = filled_matrix(level.tiles.size(), level.tiles.size().x)
var queue = queue[Tuple2[Point, Int]]()
for y in 0..level.tiles.height do
for x in 0..level.tiles.width do
if reachable.get(x @ y) then
queue.&.push_back(tuple(x @ y, 0))
loop {
var data = queue.&.pop_front_maybe() or break
var point = data.a
var dist = data.b
if not({0 @ 0}.by(level.tiles.size()).contains(point)) then continue
if distance.get(point) <= dist then continue
distance.&.set(point, dist)
for direction in list(0 @ 1, 0 @ {0-1}, 1 @ 0, {0-1} @ 0) do
queue.&.push_back(tuple(point + direction, dist + 1))
}
for y in 0..level.tiles.height do {
for x in 0..level.tiles.width do
stdout."{distance.get(x @ y)} "
stdout."\n"
}
}
exit(0)
level
}
| Gameplay
fun move(level: &Level, direction: Point) {
var new_pos = level.player + direction
loop {
switch level.get(new_pos + direction)
case free break
case wall return {} | can't move
}
level.player = new_pos
}
fun move_left(level: &Level) { level.move({0-1} @ 0 ) }
fun move_right(level: &Level) { level.move(1 @ 0 ) }
fun move_up(level: &Level) { level.move(0 @ {0-1}) }
fun move_down(level: &Level) { level.move(0 @ 1 ) }
| Rendering
var box_color = color(16#1a94ff)
var ground_color = color(16#f2f2f7)
var wall_color = color(16#1c1c1e)
fun draw(texture: &Texture, level: Level) {
var offset = 10 @ 10
var grid = 10
texture.&.fill(wall_color)
for y in 0..level.tiles.height do {
for x in 0..level.tiles.width do {
var color =
switch level.get(x @ y)
case free ground_color
case wall wall_color
texture.&.draw({{x @ y} * grid + offset}.by(grid @ grid), color)
}
}
texture.&.draw(
{level.player * grid + offset + {1 @ 1}}.by({grid - 2} @ {grid - 2}),
color(255, 0, 0))
}
fun write[W](writer: W, level: Level) {
for y in {0-1}..{level.tiles.height + 1} do {
for x in {0-5}..{level.tiles.width + 5} do
writer."{
if level.player == {x @ y} then
"+"
else
switch level.get(x @ y) case free " " case wall "▓"
}"
writer."\n"
}
}
fun main(): Never {
var random = random_number_generator(10)
var level = generate_level(random.&)
var screen = screen_texture()
loop {
eprintln("Drawing level")
println(level)
screen.&.draw(level)
screen.show()
if get_pressed_key() is some(key) then
switch key
case w level.&.move_up()
case a level.&.move_left()
case s level.&.move_down()
case d level.&.move_right()
case q break
default eprintln("Pressed key: {key.debug()}")
}
println("Thanks for playing!")
exit(0)
}