Pick a class at random

axricard axelrwiko at gmail.com
Wed Jan 3 16:50:57 UTC 2024


I have an interface that is implemented by many classes, and I 
want to pick one of these implementations at random. There are 
two more constraints : first the distribution is not uniform, all 
classes can define the chance they have to be picked (this is 
reflected by the function 'weight()' below). And all classes are 
not always available, this depends on some runtime information.

I went to this minimal working sample, but it seems pretty heavy 
(especially because of the intermediate enum I think) and I feel 
like it could be way prettier and more understandable (maybe by 
using template mixins / compile time manipulations ?).

Do you have any hint on how to improve this ?

```
import std.stdio;
import std.array;
import std.algorithm;
import std.conv;
import std.random;

interface Parent
{
     void doWork();
     static int weight();

     static Parent from(Implem impl)
     {
         final switch (impl)
         {
         case Implem.IMPLEM_1:
             return new Implem1();
         case Implem.IMPLEM_2:
             return new Implem2();
         case Implem.IMPLEM_3:
             return new Implem3();
         }
     }
}

class Implem1 : Parent
{
     void doWork()
     {
         writeln("From Implem 1");
     }

     static int weight()
     {
         return 3;
     }
}

class Implem2 : Parent
{
     void doWork()
     {
         writeln("From Implem 2");
     }

     static int weight()
     {
         return 2;
     }
}

class Implem3 : Parent
{
     void doWork()
     {
         writeln("From Implem 3");
     }

     static int weight()
     {
         return 3;
     }
}

enum Implem
{
     IMPLEM_1,
     IMPLEM_2,
     IMPLEM_3
};

Implem[] availableImplems()
{
     bool runtimeCondition = true;
     if (runtimeCondition)
         return [Implem.IMPLEM_1, Implem.IMPLEM_2];
     else
         return [Implem.IMPLEM_2, Implem.IMPLEM_3];
}

int getWeight(Implem implem)
{
     final switch (implem)
     {
     case Implem.IMPLEM_1:
         return Implem1.weight();
     case Implem.IMPLEM_2:
         return Implem2.weight();
     case Implem.IMPLEM_3:
         return Implem3.weight();
     }
}

int[] getAllWeights(in Implem[] availableImplems)
{
     return availableImplems.map!(implem => 
implem.getWeight()).array;
}

Parent drawAtRandom()
{
     const Implem[] available = availableImplems();
     const int[] weights = getAllWeights(available);
     const Implem drawn = available[dice(weights)];
     return Parent.from(drawn);
}

void main()
{
     Parent p = drawAtRandom();
     p.doWork();
}
```


More information about the Digitalmars-d-learn mailing list