mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 13:10:12 +03:00
252 lines
5.9 KiB
D
252 lines
5.9 KiB
D
// NOTE: the shootout appears to be BSD licensed content.
|
|
// Including this in the test suite based on that license.
|
|
|
|
/* The Great Computer Language Shootout
|
|
http://shootout.alioth.debian.org/
|
|
|
|
Unoptimised reference implementation
|
|
|
|
contributed by Isaac Gouy
|
|
*/
|
|
|
|
import core.memory;
|
|
|
|
int main(string[] args)
|
|
{
|
|
int n = 1000;
|
|
|
|
HealthcareRegion healthcareSystem = HealthcareRegion.Create();
|
|
|
|
for(int i = 0; i < n; i++)
|
|
healthcareSystem.TransferPatients();
|
|
|
|
Totals t = healthcareSystem.AccumulateTotals();
|
|
|
|
version (VERBOSE)
|
|
{
|
|
import core.stdc.stdio : printf;
|
|
printf("Patients: %lld\n", t.patients);
|
|
printf("Time: %lld\n", t.hospitalTime);
|
|
printf("Visits: %lld\n", t.hospitalVisits);
|
|
}
|
|
|
|
if (n == 1000)
|
|
{
|
|
assert(t.patients == 102515);
|
|
assert(t.hospitalTime == 33730654);
|
|
assert(t.hospitalVisits == 106371);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
class HealthcareRegion
|
|
{
|
|
public:
|
|
static HealthcareRegion Create()
|
|
{
|
|
return HealthcareRegion.Create(LEVELS, 0, 42);
|
|
}
|
|
|
|
static HealthcareRegion Create(int level, int seed1, int seed2)
|
|
{
|
|
HealthcareRegion r = null;
|
|
|
|
if(level > 0)
|
|
{
|
|
r = new HealthcareRegion(level, seed1*seed2);
|
|
for(ptrdiff_t i = r.districts.length-1; i >= 0; i--)
|
|
r.districts[i] = Create(level-1, cast(int)((seed1*4)+i+1), seed2);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
this(int level, int s)
|
|
{
|
|
districts = new HealthcareRegion[DISTRICTS];
|
|
localHospital = new Hospital(level == LEVELS, level, s);
|
|
}
|
|
|
|
private:
|
|
enum int LEVELS = 5, DISTRICTS = 4;
|
|
HealthcareRegion[] districts;
|
|
Hospital localHospital;
|
|
|
|
package:
|
|
Patient[] TransferPatients()
|
|
{
|
|
for(ptrdiff_t i = districts.length-1; i >= 0; i--)
|
|
if(districts[i])
|
|
foreach(Patient p; districts[i].TransferPatients().dup)
|
|
localHospital.NewArrival(p);
|
|
|
|
localHospital.TriageExaminationTreatment();
|
|
|
|
return localHospital.RegionalTransferPatients();
|
|
}
|
|
|
|
Totals AccumulateTotals()
|
|
{
|
|
Totals t = new Totals();
|
|
for(ptrdiff_t i = districts.length-1; i >= 0; i--)
|
|
if(districts[i])
|
|
t += districts[i].AccumulateTotals();
|
|
|
|
localHospital.AccumulateTotals(t);
|
|
|
|
return t;
|
|
}
|
|
}
|
|
|
|
class Hospital
|
|
{
|
|
public this(bool hasNoRegionalHospital, int level, int seed)
|
|
{
|
|
this.hasNoRegionalHospital = hasNoRegionalHospital;
|
|
availableStaff = 1 << (level - 1);
|
|
discharged = new Totals();
|
|
this.seed = seed;
|
|
}
|
|
|
|
package:
|
|
void TriageExaminationTreatment()
|
|
{
|
|
DischargePatients();
|
|
TreatOrTransferPatients();
|
|
TriagePatients();
|
|
|
|
if(genRandom(1.0) > 0.7)
|
|
{ Patient p = new Patient();
|
|
NewArrival(p);
|
|
}
|
|
}
|
|
|
|
Patient[] RegionalTransferPatients()
|
|
{
|
|
return transfers;
|
|
}
|
|
|
|
void AccumulateTotals(Totals t)
|
|
{
|
|
foreach(Patient p; triage) t.Plus(p);
|
|
foreach(Patient p; examination) t.Plus(p);
|
|
foreach(Patient p; treatment) t.Plus(p);
|
|
t += discharged;
|
|
}
|
|
|
|
void NewArrival(Patient p)
|
|
{
|
|
p.hospitalVisits++;
|
|
if(availableStaff > 0)
|
|
{
|
|
availableStaff--;
|
|
examination ~= p;
|
|
p.remainingTime = 3;
|
|
p.hospitalTime += 3;
|
|
} else {
|
|
triage ~= p;
|
|
}
|
|
}
|
|
|
|
private:
|
|
Patient[] triage, examination, treatment, transfers;
|
|
Totals discharged;
|
|
int availableStaff;
|
|
bool hasNoRegionalHospital;
|
|
|
|
void DischargePatients()
|
|
{
|
|
for(ptrdiff_t i = treatment.length-1; i >= 0; i--)
|
|
{
|
|
Patient p = treatment[i];
|
|
p.remainingTime -= 1;
|
|
if(!p.remainingTime)
|
|
{
|
|
availableStaff++;
|
|
treatment = treatment[0..i] ~ treatment[i+1..$];
|
|
discharged.Plus(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
void TreatOrTransferPatients()
|
|
{
|
|
__delete(transfers);
|
|
|
|
for(ptrdiff_t i = examination.length-1; i >= 0; i--)
|
|
{
|
|
Patient p = examination[i];
|
|
p.remainingTime -= 1;
|
|
|
|
if(!p.remainingTime)
|
|
{
|
|
// no transfer
|
|
if(genRandom(1.0) > 0.1 || hasNoRegionalHospital)
|
|
{
|
|
examination = examination[0..i] ~ examination[i+1..$];
|
|
treatment ~= p;
|
|
p.remainingTime = 10;
|
|
p.hospitalTime += 10;
|
|
} else {
|
|
// transfer
|
|
availableStaff++;
|
|
examination = examination[0..i] ~ examination[i+1..$];
|
|
transfers ~= p;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void TriagePatients()
|
|
{
|
|
for(ptrdiff_t i = triage.length-1; i >= 0; i--)
|
|
{
|
|
Patient p = triage[i];
|
|
assert(p.hospitalTime != 0x7fff);
|
|
if(availableStaff > 0)
|
|
{
|
|
availableStaff--;
|
|
p.remainingTime = 3;
|
|
p.hospitalTime += 3;
|
|
triage = triage[0..i] ~ triage[i+1..$];
|
|
examination ~= p;
|
|
} else {
|
|
p.hospitalTime++;
|
|
}
|
|
}
|
|
}
|
|
|
|
int seed = 42;
|
|
const int IM = 139968;
|
|
const int IA = 3877;
|
|
const int IC = 29573;
|
|
double genRandom(double max)
|
|
{
|
|
return(max * (seed = (seed * IA + IC) % IM) / IM);
|
|
}
|
|
}
|
|
|
|
class Patient
|
|
{
|
|
package int remainingTime, hospitalTime, hospitalVisits;
|
|
}
|
|
|
|
class Totals
|
|
{
|
|
public Totals opOpAssign(string op)(Totals b) if (op == "+")
|
|
{
|
|
patients += b.patients;
|
|
hospitalTime += b.hospitalTime;
|
|
hospitalVisits += b.hospitalVisits;
|
|
return this;
|
|
}
|
|
|
|
package:
|
|
long patients, hospitalTime, hospitalVisits;
|
|
|
|
void Plus(Patient p)
|
|
{
|
|
patients++;
|
|
hospitalTime += p.hospitalTime;
|
|
hospitalVisits += p.hospitalVisits;
|
|
}
|
|
}
|