-- The Great Computer Language Shootout
-- http://shootout.alioth.debian.org/
--
-- contributed by Adam Sampson <ats@offog.org>

#INCLUDE "course.module"

VAL INT N IS 5000000:
VAL INT Creatures IS 4:

CHAN TYPE MEETING
  MOBILE RECORD
    CHAN INT a?:
    CHAN INT b!:
:
PROTOCOL MEET
  CASE
    client; MEETING!
    server; MEETING?
    done
:

PROC meeting.place (SHARED CHAN MEET c!, back?)
  MEETING! cli:
  MEETING? svr:
  SEQ
    cli, svr := MOBILE MEETING
    SEQ i = 0 FOR N
      SEQ
        CLAIM c!
          c ! client; cli
        CLAIM c!
          c ! server; svr
        SEQ j = 0 FOR 2
          CLAIM back?
            back ? CASE
              client; cli
                SKIP
              server; svr
                SKIP
    SEQ i = 0 FOR Creatures
      CLAIM c!
        c ! done
:

PROC creature (VAL INT init.col, SHARED CHAN MEET c?, back!, INT count)
  INITIAL INT mode IS 1:
  INITIAL INT colour IS init.col:
  WHILE mode <> 0
    MEETING! cli:
    MEETING? svr:
    SEQ
      CLAIM c?
        c ? CASE
          client; cli
            mode := 1
          server; svr
            mode := 2
          done
            mode := 0
      count := count + 1
      CASE mode
        0
          count := count - 1
        1
          SEQ
            cli[a] ! colour
            cli[b] ? colour
            CLAIM back!
              back ! client; cli
        2
          INT new.col:
          SEQ
            svr[a] ? new.col
            svr[b] ! colour
            colour := new.col
            CLAIM back!
              back ! server; svr
:

PROC main (CHAN BYTE out!)
  SHARED CHAN MEET c, back:
  INITIAL [Creatures]INT count IS [i = 0 FOR Creatures | 0]:
  INITIAL INT sum IS 0:
  SEQ
    PAR
      meeting.place (c!, back?)
      PAR i = 0 FOR Creatures
        creature (i, c?, back!, count[i])
    SEQ i = 0 FOR Creatures
      sum := sum + count[i]
    out.int (sum, 0, out!)
    out ! '*n'
:

