-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathturtle.ml
190 lines (168 loc) · 6.16 KB
/
turtle.ml
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
open Graphics;;
(** Turtle graphical commands *)
type command =
| Line of int (** advance turtle while drawing *)
| Move of int (** advance without drawing *)
| Turn of int (** turn turtle by n degrees *)
| Store (** save the current position of the turtle *)
| Restore (** restore the last saved position not yet restored *)
;;
(** Position and angle of the turtle *)
type position = {
x: float; (** position x *)
y: float; (** position y *)
a: float; (** angle of the direction *)
};;
(** Turtle with current pos and a list of old pos *)
type turtle = {
current_pos: position;
saved_pos: position list;
};;
(** This exception is raised if saved_pos list is empty and a Restore command is called *)
exception Restoration_failure of string;;
(** Good approximation of pi *)
let pi = 4.0 *. atan 1.0;;
(** Implementation of round function for Float *)
let round (f: float) : float =
let dessus = ceil f in
if compare (dessus-.f) 0.5 <= 0 then dessus
else floor f
;;
(** Create a turtle at specific postion on the graph *)
let create_turtle_at (x: int) (y: int) : turtle =
moveto x y;
{current_pos = {
x = float_of_int (current_x ());
y = float_of_int (current_y ());
a = 90.}; (* default angle = 90° => toward top of the screen *)
saved_pos = []} (* No saved postion *)
;;
(** Create a turtle at origin of the graph *)
let create_turtle () : turtle =
create_turtle_at 0 0
;;
(** Update the max and min postion for horizontal and vertical axes *)
let calc_size (t: turtle) (c: command) ((hp, vp, hn, vn): (float * float * float * float))
: (float * float * float * float * turtle) =
match c with
| Move i | Line i ->
let newx = (float_of_int i) *. (cos ((t.current_pos.a /. 180.) *. pi)) in
let newx = round newx in
let coefx = newx +. t.current_pos.x in
let newx = int_of_float coefx in
let newy = (float_of_int i) *. (sin ((t.current_pos.a /. 180.) *. pi)) in
let newy = round newy in
let coefy = newy +. t.current_pos.y in
let newy = int_of_float coefy in
let hp = max hp coefx in
let vp = max vp coefy in
let hn = min hn coefx in
let vn = min vn coefy in
(hp, vp, hn, vn, {
current_pos = {
x = float_of_int newx;
y = float_of_int newy;
a = t.current_pos.a};
saved_pos = t.saved_pos})
| Turn i -> (* turn by i degrees *)
(hp, vp, hn, vn, {
current_pos = {
x = t.current_pos.x;
y = t.current_pos.y;
a = mod_float ( t.current_pos.a +. (float_of_int i) ) 360.};
saved_pos = t.saved_pos})
| Store -> (* save current_pos in saved_pos *)
(hp, vp, hn, vn, {
current_pos = {
x = t.current_pos.x;
y = t.current_pos.y;
a = t.current_pos.a};
saved_pos = t.current_pos :: t.saved_pos})
| Restore -> (* put saved_pos in current_pos if possible *)
match t.saved_pos with
| [] ->
let mes = "Erreur de Restoration -> Aucune position sauvegardée!\n" in
raise (Restoration_failure mes)
| s :: l ->
begin
(hp, vp, hn, vn, {
current_pos = s;
saved_pos = l})
end
;;
(** Calls calc_command for each command of the list *)
let rec calc_commands (t: turtle) (l: command list) ((hp, vp, hn, vn): float * float * float * float)
: (float * float * float * float * turtle) =
match l with
| [] -> (hp, vp, hn, vn, t)
| x :: l ->
begin
let (hp, vp, hn, vn, tort) = calc_size t x (hp, vp, hn, vn) in
calc_commands tort l (hp, vp, hn, vn)
end
;;
(** Execute the turtle command as a graphics command add applies the coef in line length i *)
let exec_command (t: turtle) (c: command) ((coef): float) : (turtle) =
set_color ((current_x()+current_y()) * (0xFFFFFF / (1000+1000)));
match c with
| Line i -> (* move while drawing by i * coef pixels *)
let i = float_of_int (if i mod 2 = 0 then i else i + 1) in
let newx = coef *. i *. (cos ((t.current_pos.a /. 180.) *. pi)) in
let newx = round newx in
let newx = int_of_float (newx +. t.current_pos.x) in
let newy = coef *. i *. (sin ((t.current_pos.a /. 180.) *. pi)) in
let newy = round newy in
let newy = int_of_float (newy +. t.current_pos.y) in
let time = if coef > 0.8
then coef *. 0.0005 *. i
else if coef > 0.25
then coef *. 0.0001 *. i
else coef *. 0.0000001 *. i in
Unix.sleepf(time);
lineto (newx) (newy);
{current_pos = {
x = float_of_int (current_x ());
y = float_of_int (current_y ());
a = t.current_pos.a};
saved_pos = t.saved_pos}
| Move i -> (* move without drawing by i * coef pixels *)
let i = float_of_int (if i mod 2 = 0 then i else i + 1) in
let newx = coef *. i *. (cos ((t.current_pos.a /. 180.) *. pi)) in
let newx = int_of_float (newx +. t.current_pos.x) in
let newy = coef *. i *. (sin ((t.current_pos.a /. 180.) *. pi)) in
let newy = int_of_float (newy +. t.current_pos.y) in
moveto (newx) (newy);
{current_pos = {
x = float_of_int (current_x ());
y = float_of_int (current_y ());
a = t.current_pos.a};
saved_pos = t.saved_pos}
| Turn i -> (* turn by i degrees *)
{current_pos = {
x = t.current_pos.x;
y = t.current_pos.y;
a = mod_float ( t.current_pos.a +. (float_of_int i) ) 360.};
saved_pos = t.saved_pos}
| Store -> (* save current_pos in saved_pos *)
{current_pos = t.current_pos;
saved_pos = t.current_pos :: t.saved_pos} (* store at start *)
| Restore -> (* put saved_pos in current_pos if possible *)
match t.saved_pos with
| [] ->
let mes = "Erreur de Restoration -> Aucune position sauvegardée!\n" in
raise (Restoration_failure mes)
| s :: l ->
begin
moveto (int_of_float s.x) (int_of_float s.y);
{current_pos = s;
saved_pos = l} (* list without s *)
end
;;
(** Calls exec_command for each command of the list *)
let rec exec_commands (t: turtle) (l: command list) ((coef) : float) : turtle =
match l with
| [] -> t
| x :: l ->
let turtle = exec_command t x coef in
exec_commands turtle l coef
;;