/* 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
converted to Tango by Sean Kelly
*/
import tango.stdc.stdio, tango.stdc.stdlib, tango.core.Thread, tango.util.locks.Semaphore;
void main(char[][] args)
{
int meetings, n = args.length > 1 ? atoi((args[1] ~ '\0').ptr) : 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.join();
meetings += c.creaturesMet;
}
printf("%d\n", meetings);
}
enum Colour { blue, red, yellow, faded }
Colour[] colours = [ Colour.blue, Colour.red, Colour.yellow, Colour.blue ];
class MeetingPlace
{
private static Semaphore mustWait;
private Colour first, second;
private bool firstCall = true;
private int n;
private bool second_was_here = false;
this(int maxMeetings)
{
n = maxMeetings;
mustWait = new Semaphore(1); //sem_init(&mustWait;,0,1);
}
private Colour OtherCreaturesColour(Colour me)
{
Colour other = Colour.faded;
mustWait.acquire(); //sem_wait(&mustWait;);
if(firstCall)
{
if(n)
{
first = me;
firstCall = false;
second_was_here = false;
mustWait.release(); //sem_post(&mustWait;);
assert( second_was_here, "second must was be here" );
other = second;
n--;
}
mustWait.release(); //sem_post(&mustWait;);
} else {
firstCall = true;
second = me;
second_was_here = true;
other = first;
}
return other;
}
}
class Creature : Thread
{
private MeetingPlace m;
private int creaturesMet = 0;
private Colour me;
this(MeetingPlace m, Colour c)
{
super(&run);
this.m = m; this.me = c;
}
void 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;
}
}