Выравнивание по треугольным сеткам

18

В последнее время гексагональные сетки стали довольно популярным решением проблем, связанных с двумерными данными. Тем не менее, кажется, что столь же интересными треугольными сетками до сих пор в значительной степени пренебрегали. Я хотел бы исправить это с довольно простой задачей.

Во-первых, как мы представляем треугольную сетку? Рассмотрим следующий пример (пока игнорируйте правильную диаграмму):

введите описание изображения здесь введите описание изображения здесь

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

1234567
89abcde
fghijkl
mnopqrs

Теперь, как показывает правая диаграмма, треугольная сетка имеет три основные оси: горизонтальную и две диагональные.

Выделив их в сетке ASCII:

AVAVAVA
VAabcAV
fVAiAVl
mnVAVrs

Соревнование

Вам дана прямоугольная строка, представляющая треугольную сетку (где верхний левый угол - это направленный вверх треугольник). Большинство ячеек будет ., но будет ровно две #, например:

....#
.#...
.....

Определите, #выровнены ли эти два элемента вдоль любой из трех осей сетки (т.е. лежат ли они в одном ряду в любом из трех направлений, выделенных выше). Для этого примера ответ «нет».

Вы можете написать программу или функцию, принимая ввод через STDIN (или ближайшую альтернативу), аргумент командной строки или аргумент функции и выводя результат через STDOUT (или ближайшую альтернативу), возвращаемое значение функции или параметр функции (out).

Входные данные могут быть одной строкой, разделенной переводом строки или другим удобным символом, или списком строк. Вы можете использовать любые два (непротиворечивых) печатных символа ASCII вместо .и #.

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

Применяются стандартные правила .

Тестовые случаи

Правдивые сетки:

.#..#.

#
#

...........
...#.......
...........
...........
...........
.......#...
...........

...........
.......#...
...........
...........
...........
...#.......
...........

.#.........
...........
...........
...........
...........
.......#...
...........

...........
...#.......
...........
...........
...........
...........
.......#...

.........#.
...........
...........
...........
...........
...#.......
...........

...........
.......#...
...........
...........
...........
...........
...#.......

...........
.#.....#...
...........
...........
...........

Ложные сетки:

#.....
.....#

.....#
#.....

...#.......
...........
...........
...........
...........
.......#...
...........

...........
...#.......
...........
...........
...........
...........
.........#.

.......#...
...........
...........
...........
...........
...#.......
...........

...........
.......#...
...........
...........
...........
...........
.#.........
Мартин Эндер
источник

Ответы:

3

Улитки , 40 39 байт

\#{z|=(ul.ul.`,l~a~)(l.a3|.a|d.ea5}.,\#
\# ,, совпадение '#'
{
  z | ,, Либо поверните в любом восьмеричном направлении, либо сделайте все остальное до
  = (,, Если это утверждение выполнено успешно, начальная ячейка является «направленным вверх треугольником»
    ul.ul`, ,, Пройдите на одну клетку вверх или влево дважды, любое количество раз.
              ,, Это должно было быть на один байт короче с ul`2 или ul`2 +? но
              ,, разбора `глючит.
    l ~ a ~ ,, Проверьте, что мы находимся в верхней левой ячейке путем сопоставления за пределами слева и затем на северо-восток
  )
  (l.a3 | ,, Двигайтесь влево один раз, затем установите направление на северо-запад; или
    .a | ,, Переместить вправо (начальное направление) один раз, затем установить направление на северо-восток; или
    d.ea5 ,, Двигайтесь вниз один раз, затем установите направление на северо-запад или северо-восток
}
., ,, сопоставить любое количество произвольных символов (перемещение в текущем направлении)
\# ,, совпадение '#'
feersum
источник
2

CJam, 47 байтов

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

qN%:eeee::f+:~{S&},2f<:P0f=P::+Xf|P::-Xf|]::=:|

Это использует пробелы вместо #и действительно что-нибудь еще для ..

Запустите все тестовые примеры онлайн.

Я действительно ненавижу дублирование, P::+Xf|P::-Xf|но до сих пор я не придумал ничего, чтобы избавиться от него.

объяснение

Не читайте дальше, если вы хотите найти решение для себя.

Сначала скучная часть: получение двух координатных пар из двух пространств во входной сетке:

qN%   e# Read input and split into lines.
:ee   e# Enumerate the characters in each line. I.e. turn each character 'x into a pair
      e# [N 'x] where N is its horizontal 0-based index.
ee    e# Enumerate the lines themselves, turning each line [...] into [M [...]] where M
      e# is its vertical 0-based index.
::f+  e# This distributes the vertical index over the individual lines, by prepending it
      e# to each pair in that line. So now we've got a 2-D array, where each character 'x
      e# has been turned into [M N 'x].
:~    e# Flatten the outermost dimension, so that we have a flat list of characters with
      e# their coordinates.
{S&}, e# Filter only those lists that contain a space.
2f<   e# Truncate the two results to only their first two elements.
:P    e# Store the result in P.

Теперь интересная часть состоит в том, как определить, выровнены ли эти координаты или нет. Мой код вычисляет все три оси отдельно:

  • Горизонтальная ось тривиальна. Проверьте, совпадают ли вертикальные координаты.
  • Давайте посмотрим на северо-восточную диагональ. В сетке ASCII всегда есть две антидиагонали, которые принадлежат каждой диагонали три-сетки:

    ....AV..
    ...AV...
    ..AV....
    

    Мы можем определить текущие антидиагональный путем сложения xи yкоординат:

    01234567
    12345678
    23456789
    

    Таким образом , мы хотим , 0и 1принадлежать к одной и той же диагонали, а также 2и 3, и , 4и , 5и так далее. Это означает, что, получив наш антидиагональный индекс, мы хотим округлить до следующего нечетного числа. Другими словами, мы берем побитовое ИЛИ с 1. (Мы также можем округлить до следующего четного числа побитовым И с, -2но это дороже в коде.)

  • Теперь юго-восточные диагонали:

    .VA.....
    ..VA....
    ...VA...
    

    Для того , чтобы дать диагоналям индекс, мы вычитаемx из yкоординат (представляющие отрицательных чисел как буквы):

    0abcdefg
    10abcdef
    210abcde
    

    В этом случае мы бы хотели 0и 1принадлежали к той же диагонали, как и -1и -2, или 2и 3. Итак, еще раз, мы хотим округлить до следующего нечетного числа.

Вот код для этого:

0f=  e# The coordinates are still on the stack. Replace each with its vertical coordinate
     e# to check for the horizontal axis.
P    e# Push the coordinates again.
::+  e# Sum each pair to get an anti-diagonal index.
Xf|  e# OR each index with 1 to round up to the next odd number.
P    e# Push the coordinates again.
::-  e# In each pair, subtract the horizontal coordinate from the vertical, to
     e# get a diagonal index.
Xf|  e# OR each index with 1.
]    e# Wrap all three index pairs in an array.
::=  e# Check equality for each pair.
:|   e# Fold bitwise OR over the results to check if at least one pair of indices
     e# was equal.
Мартин Эндер
источник