-
Notifications
You must be signed in to change notification settings - Fork 3
/
OCaml 2048.ml
149 lines (123 loc) · 2.77 KB
/
OCaml 2048.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
let list_make x v =
let rec aux acc i =
if i <= 0 then acc else aux (v::acc) (i-1)
in
aux [] x
let pad_right n line =
let len = List.length line in
let x = n - len in
line @ (list_make x 0)
let _move_left line =
let n = List.length line in
let line = List.filter ((<>) 0) line in
let rec aux acc = function
| x::y::tl ->
if x = y
then aux (x+y::acc) tl
else aux (x::acc) (y::tl)
| x::[] ->
aux (x::acc) []
| [] ->
List.rev acc
in
pad_right n (aux [] line)
let move_left grid =
List.map _move_left grid
let move_right grid =
grid
|> List.map List.rev
|> List.map _move_left
|> List.map List.rev
let rec replace g n v =
match g with
| x::xs -> if n = 0 then v::xs else x::(replace xs (n-1) v)
| [] -> raise (Invalid_argument "replace")
(* add a new value in a random cell containing zero *)
let rec new_value grid =
let zeros = ref [] in
List.iteri (fun y line ->
List.iteri (fun x v ->
if v = 0 then zeros := (x, y) :: !zeros
) line;
) grid;
let n = List.length !zeros in
if n = 0 then raise Exit;
let x, y = List.nth !zeros (Random.int n) in
let v = if Random.int 10 = 0 then 4 else 2 in
let line = List.nth grid y in
let new_line = replace line x v in
replace grid y new_line
(* turn counterclockwise *)
let turn_ccw grid =
let y = List.length grid in
let x = List.length (List.nth grid 0) in
List.init x (fun i ->
List.init y (fun j ->
List.nth (List.nth grid j) (x-i-1)
)
)
(* turn clockwise *)
let turn_cw grid =
let y = List.length grid in
let x = List.length (List.nth grid 0) in
List.init x (fun i ->
List.init y (fun j ->
List.nth (List.nth grid (y-j-1)) (i)
)
)
let move_up grid =
grid
|> turn_ccw
|> move_left
|> turn_cw
let move_down grid =
grid
|> turn_cw
|> move_left
|> turn_ccw
let display grid =
List.iter (fun line ->
print_string " [";
line
|> List.map (Printf.sprintf "%4d")
|> String.concat "; "
|> print_string;
print_endline "]"
) grid
let () =
Random.self_init ();
let width =
try int_of_string Sys.argv.(1)
with _ -> 4
in
let line = list_make width 0 in
let grid = list_make width line in
let grid = new_value grid in
let grid = new_value grid in
print_endline {|
s -> left
f -> right
e -> up
d -> down
q -> quit
|};
let rec loop grid =
display grid;
let grid =
match read_line () with
| "s" -> move_left grid
| "f" -> move_right grid
| "e" -> move_up grid
| "d" -> move_down grid
| "q" -> exit 0
| _ -> grid
in
let grid =
try new_value grid
with Exit ->
print_endline "Game Over";
exit 0
in
loop grid
in
loop grid