3

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

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


У меня есть перечисление чисел от 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" 

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

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

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

// Enum of vectors 
 
let vectors = { 
 
\t TOP: 1, 
 
\t TOP_RIGHT: 2, 
 
\t RIGHT: 3, 
 
\t BOTTOM_RIGHT: 4, 
 
\t BOTTOM: 5, 
 
\t BOTTOM_LEFT: 6, 
 
\t LEFT: 7, 
 
\t TOP_LEFT: 8, 
 
}; 
 
_.extend(window, vectors); // Add them to global 
 

 
// Lookup table for vectors 
 
let dirMap = { 
 
\t 1: { 1: TOP_RIGHT, 0: RIGHT, "-1": BOTTOM_RIGHT }, 
 
\t 0: { 1: TOP, "-1": BOTTOM, }, 
 
\t "-1": { 1: TOP_LEFT, 0: LEFT, "-1": BOTTOM_LEFT } 
 
}; 
 

 
// Get the direction key 
 
function getDirection(a, b){ 
 
\t return dirMap[b.x - a.x][a.y - b.y]; 
 
} 
 

 
// Example path 
 
let path = [ 
 
\t {x: 22, y: 30}, 
 
\t {x: 22, y: 29}, 
 
\t {x: 22, y: 28}, 
 
\t {x: 23, y: 27}, 
 
\t {x: 24, y: 26}, 
 
\t {x: 25, y: 25}, 
 
\t {x: 26, y: 25}, 
 
\t {x: 27, y: 24}, 
 
\t {x: 26, y: 23}, 
 
\t {x: 27, y: 22}, 
 
\t {x: 26, y: 22} 
 
]; 
 

 
let strPath = "", strInverted = ""; 
 

 
for(let i = 1, len = path.length; i < len; i++){ 
 
\t let prev = path[i - 1]; 
 
\t let direction = getDirection(prev, path[i]); 
 
\t let inverse = direction + (direction > 4 ? -4 : 4); // Can I turn this into a bitwise operation? 
 
\t strPath += direction; 
 
\t 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){ 
 
\t let arrDir = []; 
 
    _.each(dirString, function(c){ 
 
    \t let val = parseInt(c), dir = ""; 
 
    _.find(vectors, function(o, i){ if(o === val){ dir = i; return true; }}); 
 
    arrDir.push(dir); 
 
\t }); 
 
    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>

Here's a jsfiddle to play with.

доски Я смотрел на последний час или около того whiteboard of ultimate scratchheading

+1

_ "Я пытался другое побитовые операции, чтобы сделать это как можно быстрее ». Поврежденные операторы выполняли большее количество операций, чем текущий подход, на' let inverse = direction + (direction> 4? -4: 4) '? – guest271314

+0

Это хороший вопрос. Я не знаю специфики того, как javascript выполняет битовые операции под капотом, но я бы предположил, что это будет быстрее, если операции будут равны или меньше операций, необходимых для текущего подхода? Это единственное место, где я могу реально улучшить производительность до того, как путь будет сохранен в памяти, поэтому каждый аргумент рассчитывается. – ShadowScripter

+0

См. Это [Ответ] (http://stackoverflow.com/a/34487506/) by @lleaff – guest271314

ответ

1

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

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

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

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

Как уже упоминалось вы можете использовать Devtools, чтобы проверить работу и сравнить, но в соответствии с этим stackoverflow question/answer JS хэш/массива поиски имеют постоянную временную сложность

+0

Хм, я попробую. Это похоже на лучший подход. Хотя мне все же хотелось бы знать, есть ли способ сделать это, используя побитовые операции (если это возможно?), Только потому, что я интеллектуально любопытен и упрям. Будет приниматься, если никто не сможет его решить :) – ShadowScripter

+0

Либо я использую инструменты профилирования неправильно, либо на самом деле не имеет никакой разницы или может быть небрежным? Более 10 миллионов работает, я получил разницу в 100-200 мс (с общим временем 20 секунд для обоих) в пользу вашего подхода (~ 2%). Тем не менее, все же лучше. – ShadowScripter