MODULE vote;
(* A two-dimensional torus configuration is initialized with random
   boolean data. This is to reflect the voting behavior of a population.
   In each time step, each element takes the opinion of one of its 8
   local neighbors as its new opinion.
   Over time, this behavior displays a clustering pattern. Larger
   and larger groups of the same opinion emerge until a single
   opinion prevails.
   Braunl, Univ. Stuttgart, Sep. 1994
*)
FROM ImageIO  IMPORT write_c_image, color, c_red, c_green;

CONST height  = 200;
      width   = 200;
      steps   = 100;

TYPE string   = ARRAY[1..10] OF CHAR;

CONFIGURATION image [0..height-1],[0..width-1];
CONNECTION left: image[i,j] <-> image[i, (j-1) MOD width ] :right;
           up  : image[i,j] <-> image[(i-1) MOD height, j] :down;

VAR step, win: CARDINAL;
    opinion  : image OF BOOLEAN;
    col_im   : image OF color;
       
PROCEDURE name(i: CARDINAL): string;
VAR s: string;
BEGIN (* generate consecutive labelled filename *)
  s := "vote.000";
  s[8] := CHR(i MOD 10 + ORD('0')); i := i DIV 10;
  s[7] := CHR(i MOD 10 + ORD('0')); i := i DIV 10;
  s[6] := CHR(i MOD 10 + ORD('0')); i := i DIV 10;
  RETURN(s);
END name;

PROCEDURE a_neighbor(a: image OF BOOLEAN): image OF BOOLEAN;
VAR n: image OF ARRAY[0..7] OF BOOLEAN;           
BEGIN                                       
  SEND.up   (a,n[0]);    SEND.down (a,n[1]);
  SEND.left (a,n[2]);    SEND.right(a,n[3]);   
  SEND.right(n[0],n[4]); SEND.left (n[0],n[5]);
  SEND.right(n[1],n[6]); SEND.left (n[1],n[7]);
  RETURN n[RandomInt(image) MOD 8];
END a_neighbor; 

BEGIN
  opinion := RandomBool(image);  (* init *)
  FOR step:=1 TO steps DO
    IF opinion THEN col_im := c_red
               ELSE col_im := c_green
    END;
    write_c_image(col_im, name(step),width,height);
    opinion := a_neighbor(opinion);
  END;
END vote.

