I get the sense that I'm missing some fundamental knowledge for bitwise manipulation on some seemingly simple things.
I have an enumeration of integers between 1 and 8, representing all the possible vectors of movement from a position in a grid.
(I imagine some of you may recognize this problem)
{
TOP: 1,
TOP_RIGHT: 2,
RIGHT: 3,
BOTTOM_RIGHT: 4,
BOTTOM: 5,
BOTTOM_LEFT: 6,
LEFT: 7,
TOP_LEFT: 8,
}
Given a path of positions on the grid, between two points, these can be used to express the movement along that path.
[
{x: 22, y: 30},
{x: 22, y: 29},
{x: 22, y: 28},
{x: 23, y: 27},
{x: 24, y: 26},
{x: 25, y: 25},
{x: 26, y: 25},
{x: 27, y: 24},
{x: 26, y: 23},
{x: 27, y: 22},
{x: 26, y: 22}
]
is finally expressed as a string
"1122232827"
How do I best invert the direction?
I've been trying different bitwise operations to make this as fast as possible but I can't figure it out (this is a big bottleneck). So far, I've been using a shorthand if to just check if the direction is more than half the limit and then remove or add half of that. But, again, I sense that this can be done more efficiently with some bitwise jiggery. Feel free to do whatever with the code below.
Note: the lookup map, direction vectors and the method to get the direction are constants and can't be changed. They are actually interpretations of what happens under the hood of a certain API and are presumably much better implemented.
// Enum of vectors
let vectors = {
TOP: 1,
TOP_RIGHT: 2,
RIGHT: 3,
BOTTOM_RIGHT: 4,
BOTTOM: 5,
BOTTOM_LEFT: 6,
LEFT: 7,
TOP_LEFT: 8,
};
_.extend(window, vectors); // Add them to global
// Lookup table for vectors
let dirMap = {
1: { 1: TOP_RIGHT, 0: RIGHT, "-1": BOTTOM_RIGHT },
0: { 1: TOP, "-1": BOTTOM, },
"-1": { 1: TOP_LEFT, 0: LEFT, "-1": BOTTOM_LEFT }
};
// Get the direction key
function getDirection(a, b){
return dirMap[b.x - a.x][a.y - b.y];
}
// Example path
let path = [
{x: 22, y: 30},
{x: 22, y: 29},
{x: 22, y: 28},
{x: 23, y: 27},
{x: 24, y: 26},
{x: 25, y: 25},
{x: 26, y: 25},
{x: 27, y: 24},
{x: 26, y: 23},
{x: 27, y: 22},
{x: 26, y: 22}
];
let strPath = "", strInverted = "";
for(let i = 1, len = path.length; i < len; i++){
let prev = path[i - 1];
let direction = getDirection(prev, path[i]);
let inverse = direction + (direction > 4 ? -4 : 4); // Can I turn this into a bitwise operation?
strPath += direction;
strInverted = inverse + strInverted;
}
console.log("Forward: ", strPath);
console.log("Reverse: ", strInverted);
document.getElementById("forward").innerHTML = strPath;
document.getElementById("reverse").innerHTML = strInverted;
// Just for debugging purposes
function getDirString(dirString){
let arrDir = [];
_.each(dirString, function(c){
let val = parseInt(c), dir = "";
_.find(vectors, function(o, i){ if(o === val){ dir = i; return true; }});
arrDir.push(dir);
});
return arrDir.join(", ");
}
document.getElementById("full_forward").innerHTML = getDirString(strPath);
document.getElementById("full_reverse").innerHTML = getDirString(strInverted);
body{ font-family: Arial, Helvetica, sans-serif; }
#forward:before, #reverse:before, #full_forward:before, #full_reverse:before{
display: inline-block;
margin-right: 1em;
width: 4em;
}
#full_forward, #full_reverse{font-size: 0.7em; white-space: nowrap;}
#forward:before{ content: "Forward:"; }
#reverse:before{ content: "Reverse:"; }
#full_forward:before{ content: "Forward:"; }
#full_reverse:before{ content: "Reverse:"; }
<script src="https://cdn.jsdelivr.net/lodash/2.1.0/lodash.compat.js"></script>
<div id="forward"></div>
<div id="reverse"></div>
<br>
<div id="full_forward"></div>
<div id="full_reverse"></div>
I dont think you want bitwise operations here, I actually think that an array that has hardcoded values which you simply plop in your value as an index would work. Of course it is not as memory efficient but you list would only have a length of 8 so it is negligible.
Try this out:
var inverseDirList = [5,6,7,8,1,2,3,4];
var invertedDirection = inverseDirList[direction - 1];
If you really care about not doing any arithmetic operations on the direction value you can simply add a stub element, say -1, to the beginning of the list, so it would be essentially 1-based
As others have mentioned you can use devTools to check performance and compare, but according to this stackoverflow question/answer JS hash/array lookups have a constant time complexity