Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Trying to follow bitwise operations - Vivace Tutorial

This thread is locked; no one can reply to it. rss feed Print
Trying to follow bitwise operations - Vivace Tutorial
AceBlkwell
Member #13,038
July 2011
avatar

I'm trying to track the bitwise operation on a section of code. The author tells what the bits are as the code executes. The code works so obviously it's right. However, I can't follow it.

It appears ALLEGRO_KEY_DOWN returns a bool status. Could that status be used to populate an array?

Meaning would a true condition for ALLEGRO_KEY_DOWN make
key[ALLEGRO_KEY_DOWN] or key[85] == 00000001?

Assuming it does, then why would this section be needed?

#SelectExpand
1for(int i = 0; i < ALLEGRO_KEY_MAX; i++) 2 key[i] &= KEY_SEEN;

KEY_SEEN == 1. So ANDing it with zeros for the other 227 array elements seems like a waste and key[85] would already have a 1 in the last bit.

Thanks

DanielH
Member #934
January 2001
avatar

If you only want to know if a key is up or down, then yes, you could just use boolean.

case ALLEGRO_KEY_DOWN: key[event.keyboard.keycode] = true; break;
case ALLEGRO_KEY_UP: key[event.keyboard.keycode] = false; break;

The Vivace code, however, tracks key presses not only ups or downs.

What happens when a key is pressed and released before the next set of logic instructions? It would not recognize that a key was pressed at all.

Once, logic is done, this code is processed:

for(int i = 0; i < ALLEGRO_KEY_MAX; i++)
    key[i] &= KEY_SEEN;

It resets the "released" state of all keys, but keeps the "seen" state. Meaning any key that is still being pressed will remain seen.

----

AceBlkwell
Member #13,038
July 2011
avatar

Daniel,

Thanks for the explanation. I get the purpose of the loop now. By ANDing KEY_SEEN (00000001) with KEY_RELEASE | KEY_SEEN (00000011) we are resetting the KEY_RELEASE aspect of the number. Makes sense now.

I'm still not understanding the original assignment to the array. I know this if statement checks to see if the pressed button is ALLEGRO_KEY_DOWN.

if(key[ALLEGRO_KEY_DOWN]);

but does it place the true condition (00000001) in the key array? In short would key[85] == 1 or 00000001?

DanielH
Member #934
January 2001
avatar

Maybe it's me, but I don't understand what you are asking.

1 is the same thing as 00000001

#SelectExpand
1//1. at start memset 2key[ALLEGRO_KEY_DOWN] = 0 3 4//2. if it was pressed, it sets 5key[ALLEGRO_KEY_DOWN] = (KEY_SEEN | KEY_RELEASED) 6//key[ALLEGRO_KEY_DOWN] = 3 7 83. if it was released 9key[ALLEGRO_KEY_DOWN] &= KEY_RELEASED 10// key[ALLEGRO_KEY_DOWN] = 2 if it was pressed (3 & 2) = 2 11// key[ALLEGRO_KEY_DOWN] = 0 if it was not (1 & 2) = 0 12 134. after logic 14key[ALLEGRO_KEY_DOWN] &= KEY_SEEN 15// key[ALLEGRO_KEY_DOWN] = 1 if it was seen (1 & 1) = 1 16// key[ALLEGRO_KEY_DOWN] = 0 if it was only released (2 & 1) = 0

-----

I know this if statement checks to see if the pressed button is ALLEGRO_KEY_DOWN.

if(key[ALLEGRO_KEY_DOWN]);

This statement checks to see if the key is pressed or was pressed since last logic check.

Quote:

but does it place the true condition (00000001) in the key array?

This question is where I'm confused on what you are asking.

The code toggles the 1st and 2nd bits. It's true if any bit is set.

zero = false
nonzero = true

AceBlkwell
Member #13,038
July 2011
avatar

Thanks for your patience Daniel. I think I see the source of my confusion.

The if statements are only evaluating as the loop processes. The key array is updated by the EVENT_KEY lines.

#SelectExpand
1 2 switch(event.type) 3 { 4 case ALLEGRO_EVENT_TIMER: 5 if(key[ALLEGRO_KEY_UP]) 6 y--; 7 if(key[ALLEGRO_KEY_DOWN]) //Only evaluates. It doesn't alter content of key[85] 8 y++; 9 if(key[ALLEGRO_KEY_LEFT]) 10 x--; 11 if(key[ALLEGRO_KEY_RIGHT]) 12 x++; 13 14 if(key[ALLEGRO_KEY_ESCAPE]) 15 done = true; 16 17 for(int i = 0; i < ALLEGRO_KEY_MAX; i++) 18 key[i] &= KEY_SEEN; 19 20 redraw = true; 21 break; 22 23 case ALLEGRO_EVENT_KEY_DOWN: 24 key[event.keyboard.keycode] = KEY_SEEN | KEY_RELEASED; // the assignment of 00000011 done here 25 break; 26 case ALLEGRO_EVENT_KEY_UP: 27 key[event.keyboard.keycode] &= KEY_RELEASED; 28 break; 29 30 case ALLEGRO_EVENT_DISPLAY_CLOSE: 31 done = true; 32 break; 33 }

I think my confusion came from the if statement preceding the assignment statement. I assumed if we were looking at key[ALLEGRO_KEY_DOWN], it had the potential to have a value other than 0. First time through it wouldn't. Thanks again.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

This is not a good explanation of bitwise operations.

First you need to know what each bitwise operator does.

&      0     1
0      0     0
1      0     1

|      0     1
0      0     1
1      1     1

Bitwise AND only returns a 1 bit if both arguments are 1s.
Bitwise OR only returns a 1 bit if either argument is a 1.
Bitwise NOT returns a 0 if 1 or 1 if 0
Bitwise XOR returns a 1 if both bits are different and 0 otherwise.

I don't know what 'seen' is supposed to mean, but I guess it is tracking key presses and not just key down.

My input library does all this for you and more.

For example, key presses and releases are tracked automatically, and all you have to do is check a boolean array.

if (input_key_released(EAGLE_KEY_X)) {
   /// User let go of x key
}
if (input_key_press(EAGLE_KEY_Y) {
   /// user just pressed y
}
if (input_key_held(EAGLE_KEY_LCTRL) {
   /// L CTRL is held
}
// etc...

I accomplish the same thing by using a dual array of keys.

if (!oldkey[ALLEGRO_KEY_SPACE] && key[ALLEGRO_KEY_SPACE]) {
   /// space key was just pressed
}

DanielH
Member #934
January 2001
avatar

Bitwise AND returns a 1 if you're only ANDing the last bit.

KEY_SEEN and KEY_RELEASED should be renamed to KEY_HAS_BEEN_PRESSED and KEY_HAS_BEEN_RELEASED

As I said, you can do it your way if you're only concerned with key downs or not.

I do.

This is the first time looking at the Vivace tutorials. Had to read it twice to understand what was doing with those bits.

AceBlkwell
Member #13,038
July 2011
avatar

Edgar,

Being a bitwise novice, in my first attempt to follow the bit changes in the tutorial I came up with different results. The code worked so I knew I was misunderstanding it.

I thought the if statements were doing multiple things in one line of code. Capturing the keystroke and then evaluating it some how. Looking back I see it was a crazy thought. No matter how you formulate it whatever is between a set of array [brackets] is just an index of the array.

Daniel,

I think I'm understanding the AND & OR part a little better. I was just getting confused on when the bits were actually changing.

In my opinion the tutorials are pretty good. I think they "take the long way around" to allow the reader to see how things function. Normally I don't work so hard to understand every little thing. I copy/paste code then learn from the altering to fit my code. I allow for the fact there are things going on behind the scenes I'll never understand.

DanielH
Member #934
January 2001
avatar

Ask away if you have any more questions

Bitwise operations work on each bit.

Bitwise AND
'&' is usually used for masking or to check if one or more bits are set?

if (value & mask_bits) // process if value and mask have one or more bits in common

Bitwise OR
'|' is used to set a bit

value |= set_bits; // set certain bits in value to 1

Bitwise XOR
'^' is used to toggle bits

value  ^= toggle_bits;

Bitwise NOT
'~' single operand, flips bits
value = ~(0x1101); // value = 0x0010

AceBlkwell
Member #13,038
July 2011
avatar

One last question on the subject. Are bitwise operators worth the effort? I can see the benefit if you are coding the next Elder Scrolls but I'm not seeing it with small console type games or something the average programmer would do.

From a novice stand point, the benefit is for program run speed and minimizing memory usage. With today's machines is that as big a concern as it originally was?

Just curious.

Dizzy Egg
Member #10,824
March 2009
avatar

Bitwise will always be faster than + - / * etc, but whether or not to use them would be a design decision.

As you say, on a massive multiplayer network game it would save valuable processing time.

For small personal games I rarely use them, but there's no right/wrong answer, comes down to how comfortable you are using them, and whether the design demands their usage IMHO.

----------------------------------------------------
Please check out my songs:
https://soundcloud.com/dont-rob-the-machina

DanielH
Member #934
January 2001
avatar

They have their uses, but not for everything.

For instance, Allegro uses them for setting flag options.

I use either bitwise operations and/or bit fields to simplify things and decrease overhead.

If forget what game it was, but years ago I made a map system. I wanted a more precise collision system then checking if the whole tile was blocked or not. I broke the tile down into smaller squares chunks. A segment was blocked if that bit was set or not. In my map editor, I could set/unset the entire tile or individual chunks.

AceBlkwell
Member #13,038
July 2011
avatar

Thanks for the input guys. Since my programming projects have always been small and just to learn something new, I haven't developed a need for some of the programming advances that the more hard core programmers have. When learning something new (C to C++) I often see the advancements as unnecessarily complicated. So the benefits are not always obvious to me.

DanielH
Member #934
January 2001
avatar

unnecessarily complicated

Yes! That's what we do. Regular programming is boring. We try a tweak it and make it harder.

Something like tictactoe. You could make a simple int grid[9], but why?

#SelectExpand
1enum SQUARE_TYPE 2{ 3 CELL_EMPTY = 0x00, 4 CELL_X = 0x01, 5 CELL_O = 0x10 6}; 7 8typedef struct grid 9{ 10 union 11 { 12 uint32_t ivalue; 13 struct svalue 14 { 15 uint32_t s0 : 2; 16 uint32_t s1 : 2; 17 uint32_t s2 : 2; 18 uint32_t s3 : 2; 19 uint32_t s4 : 2; 20 uint32_t s5 : 2; 21 uint32_t s6 : 2; 22 uint32_t s7 : 2; 23 uint32_t s8 : 2; 24 uint32_t fluff : 14; 25 }; 26 }; 27} grid;

AceBlkwell
Member #13,038
July 2011
avatar

;D Yeah I haven't had much exposure to unions. I've read about them a little.

My code isn't as organized, especially on smaller projects. My TicTacToe didn't look anything like the section you had. I often get an idea or think "wonder if I could do...." and address that goal. Afterwards I create additional code to complete the program, test the section code, or error proof it . Ends up being "layered" approach. If I plan on using the code or displaying it, I'll clean it up by trying to take some of the clutter out. Add some comment lines etc. Not quite spaghetti code but just this side sometimes.

I often get to the end of a problem and look at the complete code and think "man that looks awfully busy, there has to be a more direct approach".

I've uploaded my TicTacToe program (cpp files). I couldn't think of systemic checks for win/lose status so I ended up checking each possible condition individually. You'll have to be lenient in your evaluation. I can't remember what I was trying out, and it did work at the time. Even beat me a few times ;D.

DanielH
Member #934
January 2001
avatar

The code I posted before was just a concept I've been working in my head. I planned to add another video to my library making TicTacToe. I SHOULD make it simple and use the brute force approach. However, I don't like simple. ;D;D

In school for by Bachelor's Degree, I took an AI class. In it we had to write a tictactoe game in Java. In it, we also had to implement some simple AI using the minmax algorithm. Not particular hard to do.

need a function to evaluate a grid.
return 10 is X wins
return -10 if O wins
return 0 if no wins

When it was the computers turn, it looked at all available moves for O. For each move, evaluate the grid. Pick the minimum values (might have multiple minimums). If the grid value was -10, it won. It the minimum grid value was zero, then it would do another layer deeper. This time it would calculate all possible moves for X and find the maximum value. If any grid values were again zero, then go another layer deeper.

Repeat until win/lose or no more moves

To the point: each layer and iteration requires a copy of the previous. While an array of 9 integers is not much. 1 integer is better.

Dizzy Egg
Member #10,824
March 2009
avatar

There’s a lot to be said for unit testing and OO design, at least where A5 is concerned. The trial and error approach of A4 seems way to popular whilst being way too archaic for me.

I’ve had a few beers.

----------------------------------------------------
Please check out my songs:
https://soundcloud.com/dont-rob-the-machina

AceBlkwell
Member #13,038
July 2011
avatar

As you say Dizzy I often take a trial-and-error approach which has its pitfalls. When I went to college the languages offered were Cobal & Fortran. I even took two semesters of IBM’s RPG. I don’t recall any PC style languages like C being offered. From what I could tell most were mainframe based. The learning I’ve done has been on my own with no real demand for my programs. Like a self-taught musician, I’m sure I’ve developed bad habits that are now crippling when trying to expand how I think / pseudo code programs.

Daniel, I’ve never had the luxury to mess with AIs. Sounds like it would be cool. I do try to get the computer to generate objects automatically / mathematically when I can figure out how to. However, there are times (TicTacToe) where I just write in the possible conditions and have the computer compare. Example, my most recent game was a board game with a maze aspect. I tried for days to figure out how to get the computer to generate the maze automatically. This would allow it to be more random. I was close I could feel it. Eventually I gave up and created 20 maps within the code. With the 20 maps and 81 potential starting points the chance of duplication seems minimal. Again, manually doing something that could be done automatically. But I digress .

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Go to: