blob: f71e965ce843e74d3358ee89f984ae789481c580 (
plain)
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
|
module Dial : sig
(** [t] is a dial between 0 and 99 inclusive *)
type t
(** [direction] is a direction the dial can be turned *)
type direction = Left of int | Right of int
val start : t
(** [start] is the initial state of the dial *)
val dial_out_of_range : string
(** [dial_out_of_range] is the error message when the dial is out of range *)
val prev : t -> t
val next : t -> t
val is_zero : t -> bool
val to_string : t -> string
(** [to_string t] is the string representation of [t] *)
val to_int : t -> int
(** [to_int t] is the integer representation of [t] *)
val pp_direction : direction -> string
end = struct
(** [t] is an int between 0 and 99 inclusive *)
type t = int
type direction = Left of int | Right of int
let start = 50
let dial_out_of_range = "dial out of range"
(** [next n] is the new state of the dial after turning [Right].
Raises: [dial_out_of_range] if [n] is greater than 99. *)
let next = function
| n when n < 99 ->
n + 1
| 99 ->
0
| _ ->
failwith dial_out_of_range
(** [prev n] is the new state of the dial after turning [Left].
Raises: [dial_out_of_range] if [n] is less than 0. *)
let prev = function
| n when n > 0 ->
n - 1
| 0 ->
99
| _ ->
failwith dial_out_of_range
let is_zero = function 0 -> true | _ -> false
let to_string = string_of_int
let to_int t = t
let pp_direction = function
| Left n ->
"Left " ^ string_of_int n
| Right n ->
"Right " ^ string_of_int n
end
module Turner : sig
val turn : Dial.t -> int -> Dial.direction -> Dial.t * int
(** [turn dial direction] is the new state of the dial after turning [direction] on [dial] *)
end = struct
(** [turn dial direction] is the new state of the dial after turning [direction] on [dial].
Raises: [dial_out_of_range] if the dial is moved to an invalid state. *)
let rec turn dial zero_count direction =
let open Dial in
match direction with
| Left 0 ->
(dial, zero_count)
| Left n ->
let dial' = prev dial in
let zero_count' =
if Dial.is_zero dial' then zero_count + 1 else zero_count
in
turn dial' zero_count' (Left (n - 1))
| Right 0 ->
(dial, zero_count)
| Right n ->
let dial' = next dial in
let zero_count' =
if Dial.is_zero dial' then zero_count + 1 else zero_count
in
turn dial' zero_count' (Right (n - 1))
end
|