C++ Question Need some elegance in an algorithm!

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,882
Reaction score
2,133
Points
203
Location
between the planets
The problem I have is trivial. But then I start an algorithm to solve it, and it gets so convoluted and uggly that I just can't bare it. There must be a much more elegant solution that I'm missing.

The problem, as stated, doesn't sound like much. I have 3 variables that can have 3 valid states, and an invalid one (showing that the variable has not yet been assigned a valid value).

Any of the variables can have any valid state, but they must all have a different one (i.e. every valid value must be assigned to a variable).

Initially, it is possible for all three variables to be invalid, or for one or two of them to already have a valid value. The algorithm must do nothing more than find out which values are still available and assign them to the available variables. It doesn't matter which one goes to which one.

Sounds simple, and probably is, but I'm getting into a nasty spaghetti pot. Can anyone tell me how to solve the problem with as simple an algorithm as possible (pseudo-code or real code, doesn't really matter).
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,626
Reaction score
2,344
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
Sounds simple, and probably is, but I'm getting into a nasty spaghetti pot. Can anyone tell me how to solve the problem with as simple an algorithm as possible (pseudo-code or real code, doesn't really matter).

If I understand this correctly... you have only (3*2) possible valid states for the three variables, right?

And if two or three variables are uninitialized... how should the algorithm behave?
 

Artlav

Aperiodic traveller
Addon Developer
Beta Tester
Joined
Jan 7, 2008
Messages
5,790
Reaction score
780
Points
203
Location
Earth
Website
orbides.org
Preferred Pronouns
she/her
Can you define the values?
If yes, it's trivial.

byte v[3]; are your variables.
1, 2 and 4 are your values, 0 is uninitialized.

Given that, something like this should work:
Code:
for (int i = 0; i < 3; i++) {
 byte all = v[0] | v[1] | v[2];
 byte shl = 1 << i;
 if ((all | shl) == 0) for (int j = 0; j < 3; j++) if (v[j] == 0) { v[j] = shl; break;}
}

It tries every value (which are orthogonal to each other) for it's existence among the variables, and if nonexistent - assigns it to the first uninitialized one.

P.S. It assumes no error conditions, like same value already assigned to several variables.
You can check for existence of such condition with "if (((v[0] | v[1] | v[2]) != 7) && v[0] && v[1] && v[2]) error();".
 
Last edited:

dgatsoulis

ele2png user
Donator
Joined
Dec 2, 2009
Messages
1,927
Reaction score
340
Points
98
Location
Sparta
I have 3 variables that can have 3 valid states, and an invalid one (showing that the variable has not yet been assigned a valid value).
Any of the variables can have any valid state, but they must all have a different one (i.e. every valid value must be assigned to a variable).

Initially, it is possible for all three variables to be invalid, or for one or two of them to already have a valid value. The algorithm must do nothing more than find out which values are still available and assign them to the available variables. It doesn't matter which one goes to which one.

Not sure how much this helps, but I find that the 3 variables can have 28 different combinations:

1,2,3 = valid 4 = invalid

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
1 4 4
1 2 4
1 3 4
2 4 4
2 1 4
2 3 4
3 4 4
3 1 4
3 2 4
4 1 4
4 1 2
4 1 3
4 2 4
4 2 1
4 2 3
4 3 4
4 3 1
4 3 2
4 4 1
4 4 2
4 4 3
4 4 4
 

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,882
Reaction score
2,133
Points
203
Location
between the planets
Given that, something like this should work:

Thanks, that's exactly the kind of thing I was looking for.

byte all = v[0] | v[1] | v[2];

I had absolutely no idea that a declaration like that was possible :blink:
 

Jarod

Member
Joined
Dec 13, 2011
Messages
169
Reaction score
0
Points
16
When I saw Artlav's solution, I thought "what the heck is that ?", and didn't really tried to understand.
I tried to write something which resulted in spaghetti code, and then I tried to think as each valid state as a vector orthogonal to each other, and then to map their coordinates to binary, when I was writing the OR operation to find which states are missing, I thought "what the heck ?", came back to Artlav's solution and saw that it was exactly what he already wrote.
Damn, well, at least now I understand. :)
It allowed me to spot an error in Artlav's code too.
The if condition on the last line shoud read :
Code:
if ((all & shl) == 0)

Code:
for (int i = 0; i < 3; i++) {
 byte all = v[0] | v[1] | v[2];
 byte shl = 1 << i;
 if ((all & shl) == 0) for (int j = 0; j < 3; j++) if (v[j] == 0) { v[j] = shl; break;}
}
 

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
Keeping it tight:
Code:
  int v[3] = {2,1,0};
  int a = v[0] | v[1] | v[2];
  for (int b = 4; b > 0; b/=2) if ((a & b) == 0) for (int i=0; i<3; i++) v[i]= v[i]>0? v[i] : b;

Not sure abut the byte definition, but I'll happily waste a few bits and make them ints!!
 

Artlav

Aperiodic traveller
Addon Developer
Beta Tester
Joined
Jan 7, 2008
Messages
5,790
Reaction score
780
Points
203
Location
Earth
Website
orbides.org
Preferred Pronouns
she/her
I had absolutely no idea that a declaration like that was possible :blink:
What exactly surprised you in it?

It allowed me to spot an error in Artlav's code too.
Well, i did write that code at 1 am, in bed and on a cellphone, so i couldn't exactly test it. :)

Always be wary of a code that runs on the first try - it only means that the error is subtle and will bite you later.
 

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,882
Reaction score
2,133
Points
203
Location
between the planets
What exactly surprised you in it?

That you can declare a variable that has several possible states (if that is what it's actually doing). Although I generally suck at bit-level manipulation big time. It's just one of the many things I never learned to use...
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,626
Reaction score
2,344
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
That you can declare a variable that has several possible states (if that is what it's actually doing). Although I generally suck at bit-level manipulation big time. It's just one of the many things I never learned to use...

Its not declared... its a bitwise-or operation, with the variable states defined as such by Artlav, that every state has its own bit position.
 

meson800

Addon Developer
Addon Developer
Donator
Joined
Aug 6, 2011
Messages
405
Reaction score
2
Points
18
If the values of the "v" array are 1,2,4, the declaration
Code:
byte all = v[0] | v[1] | v[2];
is the exact same thing as,
Code:
byte all = 7;

Because you just or them all together
Code:
1: 0 0 1
2: 0 1 0
4: 1 0 0
-------- (or operation of the above)
7: 1 1 1
 

Shifty

Donator
Donator
Joined
Jul 24, 2013
Messages
395
Reaction score
0
Points
16
Location
San Diego
came back to Artlav's solution and saw that it was exactly what he already wrote.

Yeah, I spent 10 minutes sketching out a solution on my whiteboard, came back, reloaded the forum and Artlav had already posted pretty much exactly the same thing, except I assumed a generic type for the variables and had an initial routine to convert them to the bitflag states and back.
 

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,882
Reaction score
2,133
Points
203
Location
between the planets
Well, thanks a whole lot to everyone for posting from their cellphones in bed, getting out their whiteboards aso. I didn't quite expect that amount of feedback. :embarrassed:
 
Top