Multicore Game Of Life Program
let instants = 500  // maximum number of instants fo the simulation
let delay = 1000    // number of cycles run at each instant by each living cells

/*****************************************************************/
let s1 = scheduler  // two synchronised schedulers
and s2 = scheduler  // sharing the same instants

/*****************************************************************/
// the type of colors; each color is a constructor without argument
type color = 
   BLUE | GREEN | YELLOW | RED | CYAN | BLACK | MAGENTA | GRAY25

/*****************************************************************/
// declaration of some interface functions (implemented in C)
let get_maxx           : unit -> int
let get_maxy           : unit -> int
let start_graphics     : unit -> bool // true = ok
let update_display     : unit -> unit
let draw_rectangle : 
    int // x
  * int // y
  * int // size
  * color -> bool

/***********************************************/
// GRAPHICS
/***********************************************/
let maxx = get_maxx ()  // x size of the graphical applet
let maxy = get_maxy ()  // y size of the graphical applet

/***********************************************/
// the module that initialises the display and updates it at each instant
let module update () =
   begin
      if not (start_graphics ()) then
         begin
           print_string ("can't initialize display\n");
           quit (1) // terminate the simulation
         end
      end;
      loop begin
         update_display ();
         cooperate
      end
  end

/***********************************************/
// the type of areas which are images of cells
type area = Area of 
    int // x
  * int // y
  * int //size
  * color 

// drawing an area
let draw_area (a) = 
  match a with Area (x,y,s,c) -> draw_rectangle (x,y,s,c) end

let draw_event = event // the event that collect areas to be drawn

// at each instant, draw areas for all values of the event draw_event
let module draw_processor () =
   loop for_all_values draw_event with a -> draw_area (a)

/*****************************************************/
// MAPS
/******************************************************/
// the array of cell activation events (initially, a null event)
let null_event = event
let event_map = ref [maxx] ref [maxy] null_event

// the array of cell states (living or dead; initially dead)
let state_map = ref [maxx] ref [maxy] ref false

/*****************************************************************/
// CELL DISPLAY
/*****************************************************************/
// function that displays a cell (BLACK when dead, color when alive)

let cell_display (x,y,living,color) =
   if not living then generate draw_event with Area (x,y,1,BLACK)
   else generate draw_event with Area (x,y,1,color)

/*****************************************************************/
// GOL STRATEGY
/*****************************************************************/
// the Game of Life basic function that defines birth and death of cells

let gol_strategy (living,neighbour) =
   if (not !living) && neighbour = 3 then living := true else 
   if !living && neighbour <> 2 && neighbour <> 3 then living := false 
   else ()

/*****************************************************************/
// NEIGHBOURS
/*****************************************************************/
/* toric geometry (immediate as access to an array element is 
modulo the array size, so there is no possibility of 
out-of-bound error) */

let event_at (x,y) = !(!event_map [x]) [y]

// list of activation events of the 8 neighbour cells
let get_neighbours (x,y) =
     Cons_list (event_at (x,y-1),
     Cons_list (event_at (x+1,y-1),
     Cons_list (event_at (x+1,y),
     Cons_list (event_at (x+1,y+1),
     Cons_list (event_at (x,y+1),
     Cons_list (event_at (x-1,y+1),
     Cons_list (event_at (x-1,y),
     Cons_list (event_at (x-1,y-1),Nil_list))))))))

// activate the neighbours
let awake (neighbours) =
   match neighbours with Nil_list -> () 
   | Cons_list (head,tail) -> 
          begin generate head; awake (tail) end
   end

/*****************************************************************/
// CELLS
/*****************************************************************/
// two events to synchronise the start of all cells
let ready = event
let starting_event = event

// the module that defines the cell behaviour
let module linked_cell (x,y,me,state,color,neighbours) =
let count = ref 0 in
let living = ref state in
begin
  generate ready;
  await starting_event;
  loop begin
    cell_display (x,y,!living,color);
    if !living then 
      awake (neighbours)
    else 
      await me; // just wait to be activated (passive waiting)
    count := 0;
    for_all_values me with _ -> count++; // get the number of living neighbours
    gol_strategy (living,!count); // apply the game of life strategy
    repeat delay do count++ // waste some computing resource...
  end
end

/* the basic cell module; first, get the activation event of the cell,
the initial state, and the neighbours; then, link to the
appropriate scheduler and launch an instance of linked_cell in it.
*/

let module cell (k,x,y,color) = 
  let me = !(!event_map[x])[y] in
  let state = !(!(!state_map[x])[y]) in
  let neighbours = get_neighbours (x,y) in
    if k=1 then  
       link s1 do
          thread linked_cell (x,y,me,state,color,neighbours)
    else
       link s2 do
          thread linked_cell (x,y,me,state,color,neighbours)

/*****************************************************/
// INITIAL SHAPE
/******************************************************/
// sets as alive a cell given by its coordinates x and y
let fire (x,y) =
    let state = !(!state_map [x]) [y] in state := true

/****************************************************/
// the initial shape (called pentomino) placed at coordinates x,y
let r_pentomino_shape (x,y) =
 begin
   fire (x,y);
   fire (x+1,y);
   fire (x+1,y-1);
   fire (x+1,y+1);
   fire (x+2,y-1)
 end

/****************************************************/
// SLICES
/****************************************************/
// the function that creates cells in a slice, with appropriate color
let slice (n,inity,endy) =
  let y = ref inity in
  repeat endy-inity do begin
      let x = ref 0 in
      repeat maxx do begin
       if n = 1 then thread cell (1,!x,!y,GREEN) 
       else thread cell (2,!x,!y,RED);
       x++
     end;
     y++
   end

/****************************************************/
// CONTROL OF THE SIMULATION
/****************************************************/
// module to trace instants and to end the simulation
let module ctrl (n) =
 let c = ref 0 in
   begin
       await starting_event;
       print_string ("start simulation\n");
       repeat n do begin
          print_int (!c); c++; print_string (" "); flush ();
          cooperate;
       end;
       print_string ("end simulation\n");
       quit (0);
   end

/****************************************************/
// MAP INITIALISATION
/****************************************************/
// creation of the event map; a new fresh event for each cell
let create_event_map () =
  let y = ref 0 in
   repeat maxy do 
   begin
     let x = ref 0 in
     repeat maxx do begin
        (!event_map[!x])[!y] := event;
        x++;
     end;
     y++
   end

// creation of the state map; each cell is initially dead
let create_state_map () =
  let y = ref 0 in
   repeat maxy do 
   begin
     let x = ref 0 in
     repeat maxx do begin
        !(!state_map[!x])[!y] := false;
        x++;
     end;
     y++
   end

/****************************************************/
// INITIAL SYNCHRONISATION
/****************************************************/
/* waits for all cells to be ready (there are maxx*maxy cells) 
and starts them by generating the event starting_event (events are
broadcast in s1 and s2, so all cells receive it; moreover, they all
receive it at the same instant) */

let module starter () =
   let n = maxx*maxy in
   let count = ref 0 in
   begin
      while !count < n do
         for_all_values ready with _ -> count++;
      generate starting_event; // go!
   end

/****************************************************/
// MAIN
/****************************************************/
// the main entry point (the initial thread)

let module main () = 
  begin
    create_event_map ();
    create_state_map ();
    // put the pentomino in the middle of the applet
    r_pentomino_shape (maxx/2,maxy/2);

    slice (1,0,maxy/2);      // top slice of cells run by s1
    slice (2,1+maxy/2,maxy); // bottom slice of cells run by s2

    link s1 do begin // arbitrary choice of s1 (could be s2 as well)
       thread ctrl (instants);
       thread update (); 
       thread draw_processor (); 
       thread starter ();
    end
  end

/****************************************************/

This Html page has been produced by Skribe.
Last update Wed Apr 4 15:53:19 2007.