#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: