/* The Great Computer Language Shootout
   http://shootout.alioth.debian.org/

   Reference implementation in C# contributed by Isaac Gouy

   converted to D by Dave Fladebo
   compile: dmd -O -inline -release chameneos.d
*/

import std.stdio, std.string, std.thread, std.c.linux.linux;

void main(char[][] args)
{
    int meetings, n = args.length > 1 ? atoi(args[1]) : 1;
    MeetingPlace m = new MeetingPlace(n);

    Creature[] creatures = new Creature[colours.length];
    foreach(int i, inout Creature c; creatures)
    {
        c = new Creature(m,colours[i]);
        c.start();
    }
    foreach(Creature c; creatures)
    {
        c.wait();
        meetings += c.creaturesMet;
    }
    writefln(meetings);
}

enum Colour { blue, red, yellow, faded }
Colour[] colours = [ Colour.blue, Colour.red, Colour.yellow, Colour.blue ];

class MeetingPlace
{
    private static sem_t mustWait;
    private Colour first, second;
    private bool firstCall = true;
    private int n;

    this(int maxMeetings)
    {
        n = maxMeetings;
        sem_init(&mustWait,0,1);
    }

    private Colour OtherCreaturesColour(Colour me)
    {
        Colour other = Colour.faded;

        sem_wait(&mustWait);
        if(firstCall)
        {
            if(n)
            {
                first = me;
                firstCall = false;
                sem_post(&mustWait);
                other = second;
                n--;
            }
            sem_post(&mustWait);
        } else {
            firstCall = true;
            second = me;
            other = first;
        }

        return other;
    }
}

class Creature : Thread
{
    private MeetingPlace m;
    private int creaturesMet = 0;
    private Colour me;

    this(MeetingPlace m, Colour c)
    {
        this.m = m; this.me = c;
    }

    int run()
    {
        while(me != Colour.faded) MeetOtherCreature();
        return 0;
    }

    private void MeetOtherCreature()
    {
        Colour other = m.OtherCreaturesColour(me);
        if(other == Colour.faded)
        {
            me = other;
        } else {
            me = Complement(other);
            creaturesMet++;
        }
    }

    private Colour Complement(Colour other)
    {
        switch(me)
        {
            case Colour.blue:
                return other == Colour.red ? Colour.yellow : Colour.red;
            case Colour.red:
                return other == Colour.blue ? Colour.yellow : Colour.blue;
            case Colour.yellow:
                return other == Colour.blue ? Colour.red : Colour.blue;
            default:
                break;
        }
        return me;
    }
}