Direction Booleans into single Integer

Started by
17 comments, last by frob 8 years, 11 months ago
Even if using the look-up-table approach, I'd highly recommend using one bit per direction instead of assigning each direction it's own ID number, as this will let you write logic that tests for a specific direction (e.g. up-left) but also easily test for classes of directions (e.g. any direction involving left: up-left, left, down-left).
enum DirectionBits {
  LEFT  = 0x01,
  RIGHT = 0x02,
  UP    = 0x04,
  DOWN  = 0x08
};
int lookup[3][3] = {
{LEFT|UP,    UP,  UP|RIGHT},
{LEFT,        0,     RIGHT},
{LEFT|DOWN,DOWN,DOWN|RIGHT}
};

int dir = lookup[...];

if( dir == UP|LEFT )
  DoUpLeftThing();
if( dir & LEFT )
  DoAnyLeftThing();
Advertisement

The single Direction ID is only used to be passed forward to the HID Class Driver. So i am not using it other than that i need to generate and forward it.

When i want to check for directions myself i still have my initial Booleans.

Blog: http://www.julianloehr.de

Twitter: https://twitter.com/jloehr_gamedev

HID Wiimote - Windows Device Driver for Wii Remote & Wii U Pro Controller: http://julianloehr.de/educational-work/hid-wiimote/



int lookup[3][3] = {
{8,1,2},
{7,0,3},
{6,5,4}
};
int direction = lookup[1+down-up][1+right-left];
I thought this is a nice way to represent it if you go with a lookup... Array has only the values you need, and theyre arranged visually so its easy to change them if you want. You can easily extend it into 3D too if you need another axis of freedom.


That's brilliant. I'm going to steal this from now on instead of the bitfield-lookup approach.
The more I think about it, there's entirely too much danger that someone might actually understand the full factorial interaction matrix approach I used in my first try. So I give you the polynomial evaluation version:

  int64_t x = 3 * (up - down) + left - right;
  return x * (x * (x * (x * (x * (x * (x * (x * (-31) - 28) + 938) + 840) - 8519) - 6972) + 24412) + 12880) / 3360;
More seriously, the full factorial interaction matrix has 16 different possible coefficients, but the solution had 14 non-zero coefficients. For the polynomial evaluation, there are nine coefficients, and eight of them were non-zero. This basically says that the mapping structure is slightly more regular than just random assignment, but not by much. I'm not going to say there isn't some clever way to do this computation more efficiently, but the horrible brute force techniques aren't simplifying into anything nice.

The more I think about it, there's entirely too much danger that someone might actually understand the full factorial interaction matrix approach I used in my first try. So I give you the polynomial evaluation version:


  int64_t x = 3 * (up - down) + left - right;
  return x * (x * (x * (x * (x * (x * (x * (x * (-31) - 28) + 938) + 840) - 8519) - 6972) + 24412) + 12880) / 3360;
More seriously, the full factorial interaction matrix has 16 different possible coefficients, but the solution had 14 non-zero coefficients. For the polynomial evaluation, there are nine coefficients, and eight of them were non-zero. This basically says that the mapping structure is slightly more regular than just random assignment, but not by much. I'm not going to say there isn't some clever way to do this computation more efficiently, but the horrible brute force techniques aren't simplifying into anything nice.

No, it isn't random at all, but rather based on angles!


auto x = (float)right-left;
auto y = (float)up-down;
if(!(x || y)) return 0;
return 1+(int(round((4.f/3.14159265f)*atan2(x, y)))+8)%8;

Wait a second, is this related to a hat device or such? Because it sounds like 0-8 is what the device is returning (it is mentioned it's driver code, and I recall hats being returned as angles). That'd explain why the values can't be changed.

In this case yeah, a look-up table sounds like the best approach.

Don't pay much attention to "the hedgehog" in my nick, it's just because "Sik" was already taken =/ By the way, Sik is pronounced like seek, not like sick.

Yes, it is for my Wiimote Device Driver.

I get the input from the DPad as booleans and need them to be converted to the hat switch angles for the HID report.

Blog: http://www.julianloehr.de

Twitter: https://twitter.com/jloehr_gamedev

HID Wiimote - Windows Device Driver for Wii Remote & Wii U Pro Controller: http://julianloehr.de/educational-work/hid-wiimote/

So you actually need the opposite look-up table, i.e. you have an entry for each boolean combination and the values in the table are the hat angle.

I'd suggest you to treat opposite directions as negating each other, i.e. if both get pressed simultaneously for some reason then set the table like nothing was pressed. The look-up table would look like this (assuming the order is up, down, left, right):

unsigned dpad_to_hat[] =
{
   0, 1, 5, 0,
   7, 8, 6, 7,
   3, 2, 4, 3,
   0, 1, 5, 0
};
Don't pay much attention to "the hedgehog" in my nick, it's just because "Sik" was already taken =/ By the way, Sik is pronounced like seek, not like sick.


In this case yeah, a look-up table sounds like the best approach.
It may the best approach, but the branchless polynomial version would be more fun to see in code.

Even if you comment it out and use the table (which is probably the best idea) it would absolutely make my day to see that commented out in the source code.


// The branchless polynomial version:
// int64_t x = 3 * (up - down) + left - right;
// return x * (x * (x * (x * (x * (x * (x * (x * (-31) - 28) + 938) + 840) - 8519) - 6972) + 24412) + 12880) / 3360;
// the boring but faster table version:
int lookup[9] = ...

I love seeing gems like that in code. It can make me smile for days on end.

This topic is closed to new replies.

Advertisement