-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathsnake.ml
More file actions
229 lines (201 loc) · 5.12 KB
/
snake.ml
File metadata and controls
229 lines (201 loc) · 5.12 KB
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
(**
* Very simple snake game.
* L3 - 2013/2014 - Université de Perpignan Via Domitia
* @author Nicolas Cami
* @date April, 2014
*)
open Graphics;;
exception Lose;;
exception Win;;
Random.self_init ();;
Graphics.open_graph " 640x480";;
let width,height = 640,480;;
let gridSize = 16;;
let cellSize = [|640/gridSize;480/gridSize|];;
type direction = Top | Right | Down | Left;;
type cell = Full | Empty;;
type world = { mutable grid : cell array array ;
size : int };;
type snake = { mutable pos : (int * int) array ;
mutable dir : direction };;
(**
* Make the program sleep for n seconds.
*)
let sleep n =
let start = Unix.gettimeofday() in
let rec delay t =
try
ignore (Unix.select [] [] [] t)
with Unix.Unix_error(Unix.EINTR, _, _) ->
let now = Unix.gettimeofday() in
let remaining = start +. n -. now in
if remaining > 0.0 then delay remaining in
delay n;;
(**
* Initialize an empty grid and snake position.
*)
let initialize size =
{ grid = Array.make_matrix size size Empty ;
size = size },
{ pos = [|(size/2,size/2);(size/2,size/2+1)|] ;
dir = Top };;
(**
* Check if the snake eat hitself.
*)
let rec bite (x,y) snake i =
if i = Array.length snake.pos then
false
else
let a,b = snake.pos.(i) in
if a=x && b=y then
true
else
bite (x,y) (snake) (i+1);;
(**
* Add an apple to the grid.
*)
let addApple snake world x y =
if not (bite (x,y) (snake) (0)) then
world.grid.(x).(y) <- Full;;
(**
* Add n random apples to the grid.
*)
let rec addRandomApple snake world n =
if n > 0 then
begin
addApple snake world (Random.int world.size) (Random.int world.size);
addRandomApple snake world (n-1);
end
else
();;
(**
* Display a rectangle.
*)
let displayCell i j couleur =
Graphics.set_color couleur;
Graphics.fill_rect (i*cellSize.(0)) (j*cellSize.(1)) cellSize.(0) cellSize.(1);;
(**
* Display an apple.
*)
let displayApple i j =
Graphics.set_color 0xff0000;
Graphics.fill_ellipse (i*cellSize.(0)+cellSize.(0)/2) (j*cellSize.(1)+cellSize.(1)/2) (cellSize.(0)/2) (cellSize.(1)/2);
Graphics.set_color 0x00ff00;
Graphics.fill_arc (i*cellSize.(0)+cellSize.(0)/2) (j*cellSize.(1)+cellSize.(1)/2) (cellSize.(0)/3) (cellSize.(1)/5) 180 210;
Graphics.fill_arc (i*cellSize.(0)+cellSize.(0)/2) (j*cellSize.(1)+cellSize.(1)/2) (cellSize.(0)/3) (cellSize.(1)/5) 100 150;;
(**
* Display the whole grid.
*)
let displayWorld world =
for i=0 to world.size-1 do
for j=0 to world.size-1 do
if world.grid.(i).(j) = Full then
begin
displayCell i j 0xffffff;
displayApple i j;
end
else
displayCell i j 0xffffff
done
done;;
(**
* Display the snake.
*)
let displaySnake snake =
for i=0 to Array.length snake.pos -1 do
let x,y = snake.pos.(i) in
if i = Array.length snake.pos -1 then
displayCell x y 0xaaff44
else
displayCell x y 0x55ff55
done;;
(**
* Display grid and snake.
*)
let display snake world =
displayWorld world;
displaySnake snake;;
(**
* Check key pressed and execute related action.
*)
let action snake k =
match k with
'z' -> snake.dir <- Top
| 'q' -> snake.dir <- Left
| 's' -> snake.dir <- Down
| 'd' -> snake.dir <- Right
| _ -> ();;
(**
* Check if the snake eat an apple.
*)
let eatApple world (x,y) =
if world.grid.(x).(y) = Full then
begin
world.grid.(x).(y) <- Empty;
true;
end
else
false;;
(**
* Move all snake parts.
*)
let moveSnake (x,y) dx dy world snake =
let nx,ny = x+dx,y+dy in
if(nx<0 || nx>world.size || ny<0 || ny>world.size || bite (nx,ny) (snake) (0)) then
raise Lose
else if Array.length snake.pos >= 10 then
raise Win
else
(nx,ny);;
(**
* Move the snake, and execute actions.
*)
let run snake world =
match snake.dir with
Right ->
let n = moveSnake snake.pos.(Array.length snake.pos -1) (1) (0) (world) (snake) in
if eatApple world n then
Array.append snake.pos [|n|]
else
Array.sub (Array.append snake.pos [|n|]) (1) (Array.length snake.pos)
| Left ->
let n = moveSnake snake.pos.(Array.length snake.pos -1) (-1) (0) (world) (snake) in
if eatApple world n then
Array.append snake.pos [|n|]
else
Array.sub (Array.append snake.pos [|n|]) (1) (Array.length snake.pos)
| Top ->
let n = moveSnake snake.pos.(Array.length snake.pos -1) (0) (1) (world) (snake) in
if eatApple world n then
Array.append snake.pos [|n|]
else
Array.sub (Array.append snake.pos [|n|]) (1) (Array.length snake.pos)
| Down ->
let n = moveSnake snake.pos.(Array.length snake.pos -1) (0) (-1) (world) (snake) in
if eatApple world n then
Array.append snake.pos [|n|]
else
Array.sub (Array.append snake.pos [|n|]) (1) (Array.length snake.pos);;
(**
* Start a new action loop.
*)
let move snake world =
snake.pos <- run snake world;;
(**
* Start the game loops.
*)
let program snake world fKey =
while true do
begin
sleep 1.0;
if Graphics.key_pressed() then
fKey (snake) (Graphics.read_key());
move snake world;
display snake world;
end
done;;
let world,snake = initialize gridSize;;
addRandomApple snake world 10;;
display snake world;;
program snake world action;;
read_line();;