#include <iostream>
#include <ace/OS.h>
#include <ace/Thread_Manager.h>
#include <ace/Thread_Mutex.h>
#include <ace/Condition_T.h>
#include <ace/Guard_T.h>
typedef ACE_Condition< ACE_Thread_Mutex > Condition;
typedef ACE_Guard< ACE_Thread_Mutex > Guard;
typedef int Color;
const Color BLUE = 0;
const Color RED = 1;
const Color YELLOW = 2;
const Color FADED = 3;
struct MeetingPlace
  {
    int remaining_;
    ACE_Thread_Mutex lock_;
    Condition meetplaceAvailable_;
    Condition meetCompleted_;
    int creaturesInside_;
    Color * swappedColor_;
    MeetingPlace()
      : remaining_( 10 )
      , meetplaceAvailable_( lock_ )
      , meetCompleted_( lock_ )
      , creaturesInside_( 0 )
      , swappedColor_( 0 )
      {}
  };
class Creature
  {
  public :
    Creature(
        Color my,
        MeetingPlace & meetingPlace )
      : my_( my )
      , meetingPlace_( meetingPlace )
      , creaturesMeet_( 0 )
      {}
    void
    run()
      {
        while( true )
          {
            Color other = my_;
            {
              Guard localLock( meetingPlace_.lock_ );
              while( meetingPlace_.creaturesInside_ >= 2 )
                meetingPlace_.meetplaceAvailable_.wait();
              if( meetingPlace_.remaining_ )
                {
                  if( !meetingPlace_.swappedColor_ )
                    {
                      meetingPlace_.creaturesInside_ += 1;
                      meetingPlace_.swappedColor_ = &other;
                      meetingPlace_.meetCompleted_.wait();
                      meetingPlace_.swappedColor_ = 0;
                      meetingPlace_.creaturesInside_ = 0;
                      --meetingPlace_.remaining_;
                      meetingPlace_.meetplaceAvailable_.broadcast();
                    }
                  else
                    {
                      meetingPlace_.creaturesInside_ += 1;
                      other = *meetingPlace_.swappedColor_;
                      *meetingPlace_.swappedColor_ = my_;
                      meetingPlace_.meetCompleted_.signal();
                    }
                }
              else
                break;
            }
            if( FADED != other )
              {
                my_ = complement( other );
                ++creaturesMeet_;
              }
          }
      }
    int
    total() const
      {
        return creaturesMeet_;
      }
  private :
    Color my_;
    MeetingPlace & meetingPlace_;
    int creaturesMeet_;
    Color
    complement( Color other ) const
      {
        switch( my_ )
        {
            case BLUE:
                return other == RED ? YELLOW : RED;
            case RED:
                return other == BLUE ? YELLOW : BLUE;
            case YELLOW:
                return other == BLUE ? RED : BLUE;
            default:
                break;
        }
        return my_;
      }
  };
ACE_THR_FUNC_RETURN
creatureThread( void * arg )
{
  Creature * creature = reinterpret_cast< Creature * >( arg );
  creature->run();
  return 0;
}
int
main( int argc, char ** argv )
  {
    MeetingPlace meetingPlace;
    if( 2 == argc )
      meetingPlace.remaining_ = ACE_OS::atoi( argv[ 1 ] );
    const int creatureCount = 4;
    Color colors[ creatureCount ] = { BLUE, RED, YELLOW, BLUE };
    Creature * group[ creatureCount ];
    int i;
    for( i = 0; i != creatureCount; ++i )
      {
        group[ i ] = new Creature( colors[ i ], meetingPlace );
        ACE_Thread_Manager::instance()->spawn(
            &creatureThread, group[ i ] );
      }
    ACE_Thread_Manager::instance()->wait();
    int total = 0;
    for( i = 0; i != creatureCount; ++i )
      {
        total += group[ i ]->total();
        delete group[ i ];
      }
    std::cout << total << std::endl;
    return 0;
  }
// vim:ts=2:sts=2:sw=2:expandtab:fenc=utf-8: