enum gamestate {
  waiting,
  playing,
  ended,
}

monitor rb {
  condition win;
  condition play[A, B][0, .., MAX-1];
  bool ready[A,B][0, .., MAX-1];
  bool captured[A,B][0, .., MAX-1];
  bool teamcaptured[A,B];
  condition waiterAdded;

  gamesate state;
  int teamsize;
  [int, int] score;

  procedure entry nuovapartita() {
    state = waiting;
    score = [0,0];
  }

  procedure entry [int, int] chiama(int[] players) {
    lookingFor = []
    for(player : players) lookingFor.push((B, player), (B, player))
    do {
      for((team, player) : lookingFor)
        if(ready[team][player])
          lookingFor.remove((team, player))
      if(lookingFor.size() > 0)
        waiterAdded.wait();
    } while(lookingFor.size() > 0)

    for(int i = 0; i < MAX; ++i)
      captured[team][i] = 0;
    teamcaptured[A] = 0;
    teamcaptured[B] = 0;
    teamsize = len(players)
    state = playing;

    for(player : players)
      play[team][player].signal();

    win.wait();
    if(score[A] == 10 || score[B] == 10) {
      state = ended;
      // Unblock any remaining blocked students
      for(int i = 0; i < MAX; ++i) {
        if(ready[A][i])
          play[A][i].signal();
        if(ready[B][i])
          play[B][i].signal();
      }
    }
    if(state != playing)
      return score;
  }

  procedure entry bool pronto(int team, int player) {
    if(state == ended)
      return 1

    ready[team][player] = 1;
    waiterAdded.signal();
    play[team][player].wait();
    ready[team][player] = 0;

    if(state == ended)
      return 1
    else
      return 0
  }

  procedure entry void allabandiera(int team, int player) {
    captured[team][player] = 1;
    ++teamcaptured[team];
    if(sum >= teamsize) {
      state = waiting;
      ++score[team];
      win.signal();
    }
  }
}