isklife.ml
(* the life game : skeleton version *)
(*
two neighbours alive => stay
three neighbours alive => alive
else => dead
*)
open Graphics;;
let n = 100;; (* the board is n by n, mesh toroidal *)
let init_board () =
let board = Array.create_matrix n n 0 in
for i = 0 to (n-1) do
for j = 0 to (n-1) do
if ((Random.int 10) < 3)
then Array.set board.(i) j blue
else Array.set board.(i) j white
done
done;
board;;
let dist i j radius =
let c = n/2 in
let di = (i-c)*(i-c) in
let dj = (j-c)*(j-c) in
if((di+dj)<(radius*radius)) then true else false;;
let c_init_board radius =
let board = Array.create_matrix n n 0 in
for i = 0 to (n-1) do
for j = 0 to (n-1) do
if (dist i j radius)
then
(if ((Random.int 10) < 2)
then Array.set board.(i) j red
else Array.set board.(i) j white)
else
Array.set board.(i) j white
done
done;
board;;
let first_display = ref true;;
let display board =
if(!first_display)
then (open_graph (" "^(string_of_int n)^"x"^(string_of_int n));
first_display := false);
draw_image (make_image board) 0 0 ;;
let display_tasks t =
for i = 0 to (Array.length t-1) do
begin
clear_graph();
display t.(i);
Unix.sleep 3;
end
done;;
let init_board_user () =
let board = Array.create_matrix n n white in
let fine = ref false in
begin
open_graph (" "^(string_of_int (n))^"x"^(string_of_int (n)));
display board;
while(not !fine) do
let stat = wait_next_event [Button_down;Key_pressed] in
if(stat.keypressed) then fine:=true
else
begin
let i = stat.mouse_x in
let j = stat.mouse_y in
begin
Array.set board.(i) (j) blue;
clear_graph();
display board
end
end
done;
close_graph();
board
end;;
let alive_stencil stencil =
let sum = ref 0 in
let res = ref 0 in
for i = 0 to 2 do
for j = 0 to 2 do
sum := !sum + (if(stencil.(i).(j) = white) then 0 else 1)
done
done;
sum := !sum - (if (stencil.(1).(1) = white) then 0 else 1);
if(!sum = 2) then res:= (if(stencil.(1).(1) = white) then 0 else 1);
if(!sum = 3) then res:= 1;
if(!res = 0) then white else blue
;;
let make_stencil m ii jj =
let s = Array.create_matrix 3 3 white in
for i = 0 to 2 do
for j = 0 to 2 do
Array.set s.(i) (j) m.((i+ii-1+n) mod n).((j+jj-1+n) mod n)
done
done;
s
;;
let lifestep_stencil m =
let mm = Array.create_matrix n n white in
for i = 0 to (n-1) do
for j = 0 to (n-1) do
Array.set mm.(i) j (alive_stencil (make_stencil m i j))
done
done;
mm
;;
(* prepare the matrix of stencils :
out of a matrix which is n x n
take out k matrixes which are (n/k + 2) x n
*)
exception NotDivisible;;
(* get k+2 rows from m starting at ii-1 *)
let k_rows_from m ii k =
let res = Array.create (k+2) m.(0) in
for i = 0 to (k+1) do
Array.set res i m.((ii+i-1+n) mod n)
done;
res;;
(* prepares a vector of k slices of m (each slice has stencil rows) *)
let prepare_tasks k m =
if (not ((n mod k) = 0)) then raise NotDivisible
else
let res = Array.create k (k_rows_from m 0 (n/k)) in
begin
for kk = 0 to (k-1) do
Array.set res kk (k_rows_from m (kk*(n/k)) (n/k))
done;
res
end;;
(* compute a slice of the result *)
let compute_slice _ slice =
let k = Array.length slice - 2 in
let res = Array.create_matrix k n red in
for i = 0 to (k-1) do
for j = 0 to (n-1) do
Array.set res.(i) j (alive_stencil (make_stencil slice (i+1) j))
done
done;
res
;;
let merge_slices _ slices =
let k = Array.length slices in
let m = Array.length slices.(0) in
let res = Array.create n slices.(0).(0) in
for i = 0 to (n-1) do
Array.set res i (slices.(i/m).(i mod m))
done;
res;;
let display_and_pass _ m =
display m; m;;
(* ok this generates a stream of random boards ... *)
let stream_generate nitems =
let n = ref nitems in
(function _ ->
if(!n = 0)
then raise End_of_file
else (n:=!n-1;c_init_board 30));;
(* this the thing showing the successive steps of the board at intermediate
nodes ...
let lifestep =
(seq(fun _ ->(prepare_tasks 2))
||| mapvector(seq(compute_slice),5)
||| seq((merge_slices))
||| seq(display_and_pass) );;
*)
(* let's have the real one : for each board in the stream, compute 10
iterations then deliver the resulting board *)
let lifestep = parfun (fun () -> (seq(fun _ -> (prepare_tasks 2)) ||| mapvector(seq(compute_slice),5) |||
seq((merge_slices))));;
let open_graphics () =
open_graph (" "^(string_of_int (n))^"x"^(string_of_int (n)));;
(* the game of life with the skeletons *)
pardo (fun () ->
open_graphics();
let init = P3lstream.of_fun (stream_generate 5) in
let rec loop s =
function
0 -> ()
| n -> let s' = lifestep s
in List.iter display (P3lstream.to_list s'); loop s' (n-1)
in loop init 4
)