Получить обратное направление, используя побитовую операцию на границах перечисления

Быстрый и грязный вопрос. Я чувствую, что мне не хватает некоторых фундаментальных знаний для побитовой манипуляции с некоторыми, казалось бы, простыми вещами.

Проблема, которую я пытаюсь решить, заключается в следующем:


У меня есть перечисление целых чисел от 1 до 8, представляющих все возможные векторы движения из позиции в сетке.
(Я полагаю, что некоторые из вас могут распознать эту проблему)

{
    TOP: 1,
    TOP_RIGHT: 2,
    RIGHT: 3,
    BOTTOM_RIGHT: 4,
    BOTTOM: 5,
    BOTTOM_LEFT: 6,
    LEFT: 7,
    TOP_LEFT: 8,
}

При заданном пути позиций на сетке между двумя точками их можно использовать для выражения движения по этому пути.

[
  {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}
]

наконец выражается в виде строки

"1122232827"

Как мне лучше изменить направление?

Я пробовал разные побитовые операции, чтобы сделать это как можно быстрее, но я не могу понять это (это большое узкое место). До сих пор я использовал сокращение, чтобы просто проверить, превышает ли направление более половины предела, а затем удалить или добавить половину этого значения. Но, опять же, я чувствую, что это может быть сделано более эффективно с некоторой побитовой игрой. Не стесняйтесь делать что-нибудь с кодом ниже.

Примечание: карта поиска, векторы направления и метод получения направления являются константами и не могут быть изменены. На самом деле они представляют собой интерпретацию того, что происходит под капотом определенного API, и, вероятно, намного лучше реализованы.

// 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>

Вот jsfiddle, чтобы играть с.

Доска, на которую я смотрел в течение последнего часа или около того доска окончательного нуля

1 ответ

Решение

Я не думаю, что вам нужны побитовые операции здесь, я на самом деле думаю, что массив, который имеет жестко закодированные значения, которые вы просто добавляете в качестве значения в качестве индекса, будет работать. Конечно, это не так эффективно для памяти, но ваш список будет иметь длину только 8, поэтому он незначителен.

Попробуйте это:

var inverseDirList = [5,6,7,8,1,2,3,4];
var invertedDirection = inverseDirList[direction - 1];

Если вы действительно не хотите делать какие-либо арифметические операции со значением направления, вы можете просто добавить элемент-заглушку, скажем, -1, в начало списка, так что он будет по существу основан на 1

Как уже упоминали другие, вы можете использовать devTools для проверки производительности и сравнения, но в соответствии с этим стековым потоком вопрос / ответ JS-поиск хеша / массива имеет постоянную сложность по времени

Другие вопросы по тегам