import tango.core.Thread;
import tango.core.Exception;

import tango.core.sync.Barrier;
import tango.core.sync.Condition;
import tango.core.sync.Mutex;

import tango.text.convert.Integer;

import tango.io.Stdout;
import tango.io.Console;

typedef int Color;
const Color BLUE = 0, RED = 1, YELLOW = 2, FADED = 3;

class MeetingPlace
  {
    this( int remaining )
      {
        remaining_ = remaining;
        lock_ = new Mutex;
        wakeup_ = new Condition( lock_ );
      }

    void meet( Creature me )
      {
        lock_.lock;
        scope(exit) lock_.unlock;

        if( remaining_ > 0 )
          {
            if( null is first_ )
              {
                first_ = &me;
                wakeup_.wait();
              }
            else
              {
                me.other = first_.color;
                first_.other = me.color;

                first_ = null;
                --remaining_;

                wakeup_.notify();
              }
          }
        else
          {
            me.other = FADED;
          }
      }

  private :
    int remaining_;
    Creature * first_ = null;
    Mutex lock_;
    Condition wakeup_;
  }

class Creature : Thread
  {
    this( Color selfColor, MeetingPlace meetingPlace )
      {
        super( &meeting );

        color_ = selfColor;
        meetingPlace_ = meetingPlace;
      }

    Color color() { return color_; }
    Color other() { return other_; }
    void other( Color value ) { other_ = value; }
    int creaturesMeet() { return creaturesMeet_; }

  private :
    Color color_;
    Color other_ = FADED;
    MeetingPlace meetingPlace_ = null;
    int creaturesMeet_ = 0;

    void meeting()
      {
        while( color_ != FADED )
          {
            meetingPlace_.meet( this );
            if( FADED != ( color_ = complement ) )
              ++creaturesMeet_;
          }
      }

    Color complement()
      {
        if( FADED != other_ )
          switch( color )
          {
              case BLUE: return other == RED ? YELLOW : RED;
              case RED: return other == BLUE ? YELLOW : BLUE;
              case YELLOW: return other == BLUE ? RED : BLUE;
              default: break;
          }

        return FADED;
      }
  }

void
main( char[][] args )
  {
    int remaining = ( 2 == args.length ? parse( args[ 1 ], 10 ) : 10 );

    auto meetingPlace = new MeetingPlace( remaining );

    Creature[] creatures = [];
    foreach( c; [ BLUE, RED, YELLOW, BLUE ] )
      {
        auto creature = new Creature( c, meetingPlace );
        creatures ~= creature;
        creature.start;
      }

    int total = 0;
    foreach( c; creatures )
      {
        c.join;
        total += c.creaturesMeet;
      }

    Stdout( total ).newline;
  }

// vim:ts=2:sts=2:sw=2:expandtab:fenc=utf-8:

Hosted by uCoz