Определение значения на основе смежных ячеек в матрице

Редактирование : Этот вопрос дал мне зуд, таким образом, я поднял веб-сервис JSONP на Google App Engine, который возвращает клиентский IP-адрес. Использование:

<script type="application/javascript">
function getip(json){
  alert(json.ip); // alerts the ip address
}
</script>

<script type="application/javascript" src="http://jsonip.appspot.com/?callback=getip"> </script>

Yay, никакие прокси сервера не необходимы.

<час>

Чистый JS не может. Если у Вас есть сценарий сервера под тем же доменом, который печатает его, Вы могли отправить XMLHttpRequest для чтения его.

8
задан Martin Nycander 16 November 2009 в 19:36
поделиться

7 ответов

Вдохновленный решением Дуга Т. , я сам написал следующее. Обычно дважды прогоняю матрицу (плохая производительность: /). В первый раз, когда я нарисую стены вокруг каждого 1 в матрице, я сделаю это с помощью битовых масок. Во второй раз убираю все «направленные внутрь» стены.

Пример настройки:

// Add padding to output-matrix
int owidth = width+2;
int oheight = height+2;
// 4-bit value: 0bWSEN
static char N = 0x1; // The dash that goes from the center to the north
static char E = 0x2; // The dash that goes from the center to the east
static char S = 0x4; // ...
static char W = 0x8;
// This is what I will draw around every tile
char box[] = 
    {S|E, E|W, W|S,
     N|S,  0 , N|S,
     N|E, E|W, W|N };

Цикл ограждения:

for(unsigned int y = 0; y < height; y++)
    for(unsigned int x = 0; x < width; x++)
    {
        // We ignore walls
        if (! isOne(x, y)) // isOne takes care of out-of-bounds
            continue;
        // Go through neighbourhood
        for(int dy = -1; dy <= 1; dy++)
            for(int dx = -1; dx <= 1; dx++)
            {
                if (dy == 0 && dx == 0) // Ignore self
                    continue;

                if (! isOne(x+dx, y+dy))
                {
                    // Draw part of box
                    int ox = x+1, oy = y+1; // output-x and y
                    out[(oy+dy)*owidth+(ox+dx)] |= box[(dy+1)*3 + (dx+1)];
                }
            }
    }

Цикл очистки:

// Clean up "pointing edges"
for(unsigned int y = 0; y < height; y++)
    for(unsigned int x = 0; x < width; x++)
    {
        // We ignore zero's since we're only cleaning walls.
        if (isOne(x, y))
            continue;

        int ox = x+1, oy = y+1; // output-x and y
        // Remove edges that points to 'zero'-cells.
        if (! isOne(x  , y-1)) out[y*width+x] &= ~N;
        if (! isOne(x  , y+1)) out[y*width+x] &= ~S;
        if (! isOne(x-1, y  )) out[y*width+x] &= ~W;
        if (! isOne(x+1, y  )) out[y*width+x] &= ~E;
    }

Затем у меня будет поисковый список размером 16 (по одному для каждого символа) с одной записью для каждого символа.

map<unsigned int, wchar_t> p;
p[0] = ' ';
p[N] = '.';
// ...
p[N|S] = L'\u2502'; // │
p[E|W] = L'\u2500'; // ─
// ...
p[N|E|S|W] = L'\u253C'; // ┼

Этот алгоритм ни в коем случае неэффективен, O (2 * ширина * высота) не годится ... Его можно улучшить, сгенерировав таблицу зацикливания размером 256, как предлагали другие, это даст нам O ( 1) об исполнении.

1
ответ дан 5 December 2019 в 22:19
поделиться

Я реализовал это в моей выигрышной записи для IOCCC 2004 г. Я уверен, что вы найдете этот код хорошо документированным и легким для понимания.

Если вам просто нужен ответ, насколько я помню, подход, который я использовал, заключался в вычислении растрового изображения занятых ячеек, окружающих каждую ячейку, и использовании этого как индекс в массив символов стены (или, что эквивалентно, глифов). Если, как и в моем решении, вы не разрешаете диагональное перемещение, растровое изображение имеет длину 4 бита и, следовательно, массив имеет 2 ^ 4 = 16 элементов. Если вы разрешаете диагональное перемещение, вам понадобится 8-битное растровое изображение и 256 записей.

2
ответ дан 5 December 2019 в 22:19
поделиться

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

1
ответ дан 5 December 2019 в 22:19
поделиться

Вместо того, чтобы сканировать каждую строку на предмет 1 и рисовать каждую ячейку, Вы могли бы «ходить» по стенам.

, но не в конце вашего массива bool:

  • Просканируйте, пока не найдете 1

, определяющую функцию с именем "Draw", которая:

  • Отрисовывает каждый соседний 0 (или за пределы) как стена
  • Измените текущую 1 на 3 (это потребует от вас использования чего-то другого, кроме массива bools)
  • Переключить текущий курсор на соседний 1
    • Рекурсия в "Draw"
  • Если такой смежный объект не существует, вернитесь из Draw. стены.

- после возврата возобновить сканирование до тех пор, пока не будет найдена следующая 1 или конец ввода.

Может быть, не самый эффективный, но вы сказали элегантно. Рекурсия всегда элегантна! (пока вы не получите stackoverflow, который есть).

Вот некоторый взломанный код (не используйте магические числа, как я :)), чтобы помочь вам:

int inputIdxToOutputIdx(int idx)
{
        return (idx + 1);
}


int draw(int x, int y, int arr[6][6], char outBuff[8][8])
{
        for (int deltaX = -1; deltaX < 2; ++deltaX)
        {       
                for (int deltaY = -1; deltaY < 2; ++deltaY)
                {       
                        int currX = (x + deltaX);
                        int currY = (y + deltaY);
                        int drawX = inputIdxToOutputIdx(x) + deltaX; 
                        int drawY = inputIdxToOutputIdx(y) + deltaY; 
                        // if any adjacent to 1 are 0 or off the map,
                        // draw a border
                        arr[x][y] = 3;
                        if (currX > 5 || currY > 5 || currX < 0 || currY < 0 || arr[currX][currY] == 0)
                        {       
                                printf("Drawing at %i, %i (%i,%i)\n", currX, currY,drawX,drawY);
                                outBuff[drawX][drawY] = '*';
                        }       
                        else if (arr[x][y] == 1) 
                        {       
                                draw(currX, currY, arr, outBuff);
                        }       
                }
        }
}


// make the output buffer size of input + 2
int printMaze(int arr[6][6], char outBuff[8][8])
{
        for (int x = 0; x < 6; ++x)
        {
                for (int y = 0; y < 6; ++y)
                {
                        // this might be able to be made more efficient.
                        if (arr[x][y] == 1)
                        {
                                draw(x, y, arr, outBuff);
                        }
                }
        }
}

В приведенном выше решении я просто рисую ' * 's. Однако, если вы хотите нарисовать конкретный фрагмент для данной ситуации, я бы использовал таблицу поиска, такую ​​как walkytalky , сказал в своем комментарии. Сопоставьте заданный набор смежных 1 и 0 с заданной частью. IE:

Поиск:

0 1 0
0 1 1
0 1 0 

даст результат "Т" для центральной части стены. Обязательно относитесь к "вне карты" как к 0.

1
ответ дан 5 December 2019 в 22:19
поделиться

Сначала прогоните матрицу, добавив следующую матрицу ядра, центрируя 0 ядра на каждом 1 и добавляя числа к соседним квадратам (то есть сделать двоичное представление всех соседей).

1   2   4 
8   16  32 
46  128 256  

Затем просто напишите список правил, одно правило для каждой формы , а не правило для каждой возможной суммы. Например,

s = s_ij  # the sum at the location of interest
if not s & 16:  # never write a symbol over a 1
    if s & 8 and not (s & 128 or s & 2): 
        c = "|"
    elif s ==128:
        c = “┌─┐”
    # etc

или что угодно.

1
ответ дан 5 December 2019 в 22:19
поделиться

Просто быстрый взлом. Используя массив 3x3 и некоторую арифметику по модулю, вы, вероятно, могли бы значительно снизить количество обращений к памяти, но это может выглядеть некрасиво. Предупреждение. Я не запускал его через компилятор, поэтому он может содержать опечатки.

wchar_t maze_wall(int** input,int rows, int cols){

   wchar_t** output;
   int i,j;
   int N,E,S,W,NE,SE,NW,SW;

   output = (wchar_t**) malloc(sizeof(wchar_t*)*rows);
   for(i=0;i<cols;i++)
      output[i]= (wchar_t*) malloc(sizeof(wchar_t)*cols);
   for(i=0;i<rows;i++){
      for(j=0;j<cols;j++){
        if(input[i][j] ==1)
           {output[i][j] = '1'; continue;}
        N=E=S=W=NE=SE=NW=SW=0;
        if(i != 0) /*We are not at the top*/
           N = input[i-1][j];
        if(i != rows-1) /* We are not at the bottom*/
          S = input[i+1][j];
        if(j != rows-1) /* We are not at the right side*/
          E = input[i][j+1];
        if(j != 0) /* We are not at the left side*/
          W = input[i][j-1];
      /*Expand this for the corners*/

      if(N+E+S+W+NE+SE+SW+NE+NW == 0)
          {output[i][j] = ' '; continue;}

      /*Fill it in for the other six cases {'└', '┐', '┌', '┘', '-', '|'} */
      } 
   }
   return output; 
}  
0
ответ дан 5 December 2019 в 22:19
поделиться

Если вы сначала обнаружите, какие плитки являются стенами, укажите особый случай для каждого типа стены, который у вас есть, например, вертикальный, если есть один слева и / или справа, но нет сверху или снизу.

Надеюсь, это должно немного сузить круг вопросов. :) вертикальный, горизонтальный и четыре разных края. Это 6 случаев, если вы определили, какие из них вообще являются ребрами.

По крайней мере, менее 256. :)

0
ответ дан 5 December 2019 в 22:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: