Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Good practice for choosing an algorithm randomly with c++

Setting:
A pseudo-random pattern has to be generated. There are several ways / or algorithms availible to create different content. All algorithms will generate a list of chars (but could be anything else)... the important part is, that all of them return the same type of values, and need the same type of input arguments.

It has to be possible to call a method GetRandomPattern(), which will use a random one of the algorithms everytime it is called.

My first aproach was to put each algorithm in it's own function and select a random one of them each time GetRandompattern() is called. But I didn't come up with another way of choosing between them, than with a switch case statement which is unhandy, ugly and inflexible.

class PatternGenerator{
 public:
  list<char> GetRandomPattern();
 private:
  list<char>GeneratePatternA(foo bar);
  list<char>GeneratePatternB(foo bar);
  ........
  list<char>GeneratePatternX(foo bar);
}

What would be a good way to select a random GeneratePattern function every time the GetRandomPattern() method is called ?

Or should the whole class be designed differently ?

Thanks a lot

like image 641
zitroneneis Avatar asked Aug 16 '10 14:08

zitroneneis


4 Answers

Create a single class for each algorithm, each one subclassing a generator class. Put instances of those objects into a list. Pick one randomly and use it!

More generically, if you start creating several alternative methods with the same signature, something's screaming "put us into sibling classes" at you :)

Update Can't resist arguing a bit more for an object-oriented solution after the pointer-suggestion came

  • Imagine at some point you want to print which method created which random thing. With objects, it's easy, just add a "name" method or something. How do you want to achieve this if all you got is a pointer? (yea, create a dictionary from pointers to strings, hm...)
  • Imagine you find out that you got ten methods, five of which only differ by a parameter. So you write five functions "just to keep the code clean from OOP garbage"? Or won't you rather have a function which happens to be able to store some state with it (also known as an object?)
  • What I'm trying to say is that this is a textbook application for some OOP design. The above points are just trying to flesh that out a bit and argue that even if it works with pointers now, it's not the future-proof solution. And you shouldn't be afraid to produce code that talks to the reader (ie your future you, in four weeks or so) telling that person what it's doing
like image 75
Nicolas78 Avatar answered Nov 20 '22 06:11

Nicolas78


You can make an array of function pointers. This avoids having to create a whole bunch of different classes, although you still have to assign the function pointers to the elements of the array. Any way you do this, there are going to be a lot of repetitive-looking lines. In your example, it's in the GetRandomPattern method. In mine, it's in the PatternGenerator constructor.

#define FUNCTION_COUNT 24
typedef list<char>(*generatorFunc)(foo);

class PatternGenerator{
    public:
        PatternGenerator() {
            functions[0] = &GeneratePatternA;
            functions[1] = &GeneratePatternB;
            ...
            functions[24] = &GeneratePatternX;
        }
        list<char> GetRandomPattern() {
            foo bar = value;
            int funcToUse = rand()%FUNCTION_COUNT;
            functions[funcToUse](bar);
        }
    private:
        generatorFunc functions[FUNCTION_COUNT];
}
like image 5
Eric Finn Avatar answered Nov 20 '22 06:11

Eric Finn


One way to avoid switch-like coding is using Strategy design pattern. As example:

class IRandomPatternGenerator
{
public:
  virtual list<int> makePattern(foo bar);
};

class ARandomPatternGenerator : public IRandomPatternGenerator
{
public:
  virtual list<int> makePattern(foo bar)
  {
    ...    
  }
};

class BRandomPatternGenerator : public IRandomPatternGenerator
{
public:
  virtual list<int> makePattern(foo bar)
  {
    ...    
  }
};

Then you can choose particular algorithm depending on runtime type of your RandomPatternGenerator instance. (As example creating list like nicolas78 suggested)

like image 1
cybevnm Avatar answered Nov 20 '22 06:11

cybevnm


Thank you for all your great input. I decided to go with function pointers, mainly because I didn't know them before and they seem to be very powerfull and it was a good chance to get to know them, but also because it saves me lot of lines of code.

If I'd be using Ruby / Java / C# I'd have decided for the suggested Strategy Design pattern ;-)

class PatternGenerator{
 typedef list<char>(PatternGenerator::*createPatternFunctionPtr);
public:
 PatternGenerator(){
  Initialize();
   }
 GetRandomPattern(){
  int randomMethod = (rand()%functionPointerVector.size());
  createPatternFunctionPtr randomFunction = functionPointerVector.at( randomMethod );
  list<char> pattern = (this->*randomFunction)();
  return pattern;
  }
private:
  void Initialize(){
   createPatternFunctionPtr methodA = &PatternGenerator::GeneratePatternA;
   createPatternFunctionPtr methodB = &PatternGenerator::GeneratePatternB;
   ...
   functionPointerVector.push_back( methodA );
   functionPointerVector.push_back( methodB );
   }
  list<char>GeneratePatternA(){
   ...}
  list<char>GeneratePatternB(){
   ...}
  vector< createPattern > functionPointerVector;

The readability is not much worse as it would have been with the Design Pattern Solution, it's easy to add new algorithms, the pointer arithmetics are capsuled within a class, it prevents memory leaks and it's very fast and effective...

like image 1
zitroneneis Avatar answered Nov 20 '22 05:11

zitroneneis