150 lines
2.8 KiB
OCaml
150 lines
2.8 KiB
OCaml
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
|