assign ID for states and retrieval the state values

I have two classes
challenge
and
SimpleState
and they are given as
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    class challenge{
    public:
            
            enum CONTEXTS{ // context
               SMALL_REWARD=0, LARGE_REWARD=1, PUNISHMENT=2, NONE=3
            };
            enum POSITIONS{ // position
               CX0Y3=0, CX1Y3=1,CX2Y3=2,CX3Y3=3,CX4Y3=4,CX5Y3=5,CX0Y2=6, CX1Y2=7,CX2Y2=8,CX3Y2=9,CX4Y2=10
            };
            enum TIME_STEPS{ // time
               TIME_STEP_1=0, TIME_STEP_2=1, TIME_STEP_3=2, TIME_STEP_4 = 3,TIME_STEP_5=4, TIME_STEP_6=5
            };
    protected:
           std::vector<SimpleState*> states_;
    
    }

    class SimpleState: public State {
    public:
    
            SimpleState();
            
            SimpleState(int _state_id);
            ~SimpleState();
            
    };
    SimpleState::SimpleState(int _state_id) {
    	state_id = _state_id;
    }

 


How can I write two functions in the challenge class, one would assign an state id from SimpleState class to the combination of CONTEXTS, POSITIONS and TIME_STEPS and the other one can extract CONTEXT, POSITIONS and TIME_STEPS values from just the id values? I guess putting a loop over them would be the easiest way or something like a hash table. So at the end, the result will be 4x11x6 number of states with successive ids each pointing to the combination of three enum's components. I will appreciate for any help.
Last edited on
Allot digits in specific positions in the integer to the enum values.

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class challenge {

    public:

            enum context { // context
               SMALL_REWARD=0, LARGE_REWARD=1, PUNISHMENT=2, NONE=3
            };
            enum position { // position
               CX0Y3=0, CX1Y3=1,CX2Y3=2,CX3Y3=3,CX4Y3=4,CX5Y3=5,CX0Y2=6, CX1Y2=7,CX2Y2=8,CX3Y2=9,CX4Y2=10
            };
            enum time_step{ // time
               TIME_STEP_1=0, TIME_STEP_2=1, TIME_STEP_3=2, TIME_STEP_4 = 3,TIME_STEP_5=4, TIME_STEP_6=5
            };
     // ...
 };

namespace multipliers { // multipliers to form the integer id

     constexpr int context = 1 ;
     constexpr int position = 100 ;
     constexpr int time_step = 10'000 ;
}

constexpr int make_state_id( challenge::context c, challenge::position p,  challenge::time_step t )
{
     // returns an integer of the form ttppcc (two digits for each of the enum values)
     // eg, if c == 3, p == 10, t = 4, returns 041003
     return c * multipliers::context + p * multipliers::position + t * multipliers::time_step ;
}

challenge::context context_from_id( int id ) {

      if( id < 0 || id >= multipliers::time_step * 10 ) throw "bad id" ; // check validity
      const int value = id % multipliers::position ; // gets the last two digits
      if( value > challenge::NONE ) throw "bad id" ; // check validity
      return challenge::context(value) ;
 }

challenge::position position_from_id( int id ) {

      if( id < 0 || id >= multipliers::time_step * 10 ) throw "bad id" ; // check validity
      int value = id % multipliers::time_step ; // pick up the last four digits
      value = id / multipliers::position ; // knock off the last two digits
      if( value > challenge::CX4Y2 ) throw "bad id" ; // check validity
      return challenge::position(value) ;
 }

// and likewise for time_step 
If you want the ids to be consecutive between 0 and 4*11*6-1 you can calculate the id like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const int NumTimeSteps =  6,
          NumPositions = 11,
          NumContexts  =  4;

int to_id(int context, int position, int time_step) {
    return context   * NumTimeSteps * NumPositions
         + position  * NumTimeSteps
         + time_step;
}

void from_id(int id, int& context, int& position, int& time_step) {
    context   = id / (NumTimeSteps * NumPositions);
    position  = id % (NumTimeSteps * NumPositions) / NumTimeSteps;
    time_step = id % NumTimeSteps;
}

if you want combinations of the states it may be worth doing some bit stuff.

If you look at these small changes...:

enum CONTEXTS{ // context
SMALL_REWARD=0, LARGE_REWARD=1, PUNISHMENT=2, NONE=3
}; //three is 11 in binary, 2+1.

enum POSITIONS{ // position
CX0Y3= 4, //0100 bits
CX1Y3=8, //1000 bits
CX3Y3=12, //1100 bits ... see how we leave the last 2 bits open for 0-3?

};

if you continue with this idea, your ID number can contain the info. Say your ID is a 64 bit integer, then
the back end is the bit pattern for your 3 enums, added together (so 15 is 12+3 is cx3y3 and none, etc) and the most significant bits can be a unique ID number for the entry (0, 1, 2,... or whatever starting point then increment).

depending on what you want to do, you may also want to just use powers of 2 rather than combinations. that looks like

enum CONTEXTS{ // context
SMALL_REWARD=1, LARGE_REWARD=2, PUNISHMENT=4, NONE=8
};

enum POSITIONS{ // position
CX0Y3= 16,
CX1Y3=32,
CX3Y3=64,
...
};

that may make some operations easier, but the id number gets rather large. the beauty of the powers of 2 approach is you can say
id & large_reward or id & cx1y3 or whatever and have an instant response. the merged patterns I started with you have to extract the whole thing. Both approaches have merits.

Honestly this may or may not be a little old school. Unless you want all the information in a single value, this is likely overkill and unnecessary. If you do want it all in one value, then sure, this is a way to knock it out with minimal effort.

successive IDs will make it more trouble -- I ignored that requirement to show you an alternative. If you insist on it, you need a more complex answer.
Last edited on
Topic archived. No new replies allowed.