Is it possible to implement a function that results in this mapping:
{
(0x01, 0x01),
(0x10, 0x10),
(0x11, 0x00)
}
Using only bitwise operations?
Context
In the Flixel framework, there are a set of four constants,
FlxObject.LEFT:uint = 0x0001;
FlxObject.RIGHT:uint = 0x0010;
FlxObject.UP:uint = 0x0100;
FlxObject.DOWN:uint = 0x1000;
Obviously designed to be manipulated with bitwise operators. I was trying to write a function, using only bitwise operators, that would return the opposite direction of whatever was passed in (in terms of these FlxObject constants).
Some example mappings:
{
(0x0110, 0x1001),
(0x0100, 0x1000),
(0x1010, 0x0101),
(0x0001, 0x0010),
(0x1100, 0x0000)
}
The problem is, my solution tends to break down when you pass it something like 0x0011, 0x1100, 0x1110 and similar, and requires a check against this case.
Testing code here (also at http://pastie.org/3420169):
#!/usr/bin/env python
from sys import stdout
from os import linesep
# Implementation without conditional
def horiz(dir):
return(dir ^ 0x0011 ^ 0x1100) & 0x0011
def vert(dir):
return (dir ^ 0x1100 ^ 0x0011) & 0x1100
def oppositeDirection(dir):
return horiz(dir) | vert(dir)
# Implementation with conditional
def horizFix(dir):
dir = horiz(dir)
return dir if dir != 0x0011 else 0
def vertFix(dir):
dir = vert(dir)
return dir if dir != 0x1100 else 0
def oppositeDirectionFix(dir):
return horizFix(dir) | vertFix(dir)
failcount = 0
testcount = 0
def test(dir, expect, func):
global failcount, testcount
testcount += 1
result = func(dir)
stdout.write('Testing: {0:04x} => {1:04x}'.format(dir, result))
if result != expect:
stdout.write('\t GOT {0:04x} expected {1:04x}'.format(result, expect))
failcount += 1
stdout.write(linesep)
test_cases =[0x0000, 0x0001, 0x0010, 0x0100, 0x1000, 0x0011, 0x0101, 0x1001, 0x0110, 0x1010, 0x1100, 0x0111, 0x1011, 0x1101, 0x1110, 0x1111]
print 'Testing full oppositeDirection function----------------'
for case in test_cases:
test(case, oppositeDirectionFix(case), oppositeDirection)
print '\nTesting horiz function---------------------------------'
for case in test_cases:
test(case, horizFix(case), horiz)
print '\nTesting vert function----------------------------------'
for case in test_cases:
test(case, vertFix(case), vert)
print '{0}Succeeded: {2}/{1}, Failed: {3}/{1}'.format(linesep, testcount, testcount - failcount, failcount)
If you run the test, you’ll see that in the cases like 0x0011 and 0x0000 horiz will return 0x0011, and for 0x1100 and 0x000 vert will return 0x1100. So close!
This is clearly an incredibly insignificant problem, and there will never be any situation in my game code where a direction value would be simultaneously left and right or up and down. But, I’m taking this as an opportunity to hone my bit twiddling skills. Is there some logic principle I’m missing here that will help me either solve it or realize it’s an unsolvable problem?
No, you have to make some kind of test because your result depends on two adjacent bits.
You could use
XORwith1111and then test if the result contains1100or0011.But since you only have 16 values to verify would it not be simpler to make a switch/select/match function for the 8 valid values?