/
ghost.opa
106 lines (94 loc) · 3.44 KB
/
ghost.opa
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
@client Ghost = {{
draw_one(ctx:Canvas.context, g:Ghost.t) =
w = base_size
do Canvas.save(ctx)
do Canvas.set_fill_style(ctx, {color=g.color})
(center_x, center_y) = Base.center(g.base)
do Canvas.translate(ctx, center_x, center_y)
do Canvas.begin_path(ctx)
do Canvas.move_to(ctx, w/2, 0)
do Canvas.quadratic_curve_to(ctx, w/2, -w/2, 0, -w/2)
do Canvas.quadratic_curve_to(ctx, -w/2, -w/2, -w/2, 0)
do Canvas.line_to(ctx, -w/2, w/2)
do Canvas.line_to(ctx, -w/6, w/3)
do Canvas.line_to(ctx, 0, w/2)
do Canvas.line_to(ctx, w/6, w/3)
do Canvas.line_to(ctx, w/2, w/2)
do Canvas.fill(ctx)
do Canvas.clear_rect(ctx, -w/4, -w/4, w/2, w/4)
do Canvas.set_fill_style(ctx, {color=(g.eye_color)})
dx =
base = g.eye_steps
step =
if g.eye_step > base/2 then base - g.eye_step
else g.eye_step
(w*step)/(2*base)
do Canvas.fill_rect(ctx, dx-w/4, -w/4, w/4, w/4)
do Canvas.restore(ctx)
void
@private build_move_options(b:Base.t, no_back) =
all_options = [] : list(Base.direction)
|> (if Wall.at(b.pos.x+1, b.pos.y) then identity
else List.add({right}, _))
|> (if Wall.at(b.pos.x-1, b.pos.y) then identity
else List.add({left}, _))
|> (if Wall.at(b.pos.x, b.pos.y+1) then identity
else List.add({down}, _))
|> (if Wall.at(b.pos.x, b.pos.y-1) then identity
else List.add({up}, _))
if List.length(all_options) == 1 then all_options
else if no_back then
back = Base.Dir.back(b.dir)
List.filter(x -> x!=back, all_options)
else all_options
@private move_one_generic(g:Ghost.t, move_fun) =
cur_step = g.base.cur_step + 1
cur_step =
if cur_step >= g.base.max_steps then 0
else cur_step
g = {g with eye_step = mod(g.eye_step+1, g.eye_steps)}
if cur_step != 0 then {g with base = {g.base with ~cur_step}}
else
(dx, dy) = Base.Dir.deltas(g.base.dir)
pos = {
x = g.base.pos.x + dx
y = g.base.pos.y + dy
}
g = {g with base = {g.base with ~pos}}
dirs = move_fun(g.base)
dir = List.get(Random.int(List.length(dirs)), dirs) ? {down}
{g with base = {g.base with ~dir ~cur_step} }
@private move_one_dumb(ghost:Ghost.t) =
move_one_generic(ghost, build_move_options(_, true))
@private move_one_guard(ghost:Ghost.t, bp:Base.t) =
move_fun(bg) =
opts = build_move_options(bg, false)
can_see(dir) =
if bg.pos.x != bp.pos.x && bg.pos.y != bp.pos.y then false
else if bg.pos.x == bp.pos.x && bg.pos.y > bp.pos.y
&& dir == {up} then true
else if bg.pos.x == bp.pos.x && bg.pos.y < bp.pos.y
&& dir == {down} then true
else if bg.pos.y == bp.pos.y && bg.pos.x > bp.pos.x
&& dir == {left} then true
else if bg.pos.y == bp.pos.y && bg.pos.x < bp.pos.x
&& dir == {right} then true
else false
bias = List.filter(can_see, opts)
if bias == [] then
if List.length(opts) == 1 then opts
else
back = Base.Dir.back(bg.dir)
List.filter(x -> x!=back, opts)
else bias
move_one_generic(ghost, move_fun)
move(g) =
ghosts = List.map(
ghost -> match ghost.ai with
| {dumb} -> move_one_dumb(ghost)
| {guard} -> move_one_guard(ghost, g.pacman.base),
g.ghosts)
{g with ~ghosts}
draw(g, ctx:Canvas.context) =
List.iter(draw_one(ctx, _), g.ghosts)
}}