Alignment on Triangular Grids
Snails, 40 39 bytes
\#{z|=(ul.ul.`,l~a~)(l.a3|.a|d.ea5}.,\#
\# ,, match '#' { z | ,, Either turn in any octinilear direction, or do all the other stuff before the } =( ,, If this assertion succeeds, the starting cell is an "upwards-pointing triangle" ul.ul.`, ,, Go one cell up or left twice, any number of times. ,, This should have been one byte shorter with ul.`2 , or ul.`2+? but ,, the parsing of ` is buggy. l~a~ ,, Check that we are on the top-left cell by matching out-of-bounds to the left and then northeast ) ( l.a3 | ,, Move leftward once, then set direction to northwest; or .a | ,, Move right (the initial direction) once, then set direction to northeast; or d.ea5 ,, Move down once, then set direction to either northwest or northeast } ., ,, Match any number of arbitrary chars (moving in the current direction) \# ,, match '#'
CJam, 47 bytes
Well, now that there is a shorter solution I no longer feel bad sharing my own. :) (Mostly to show that this isn't particularly difficult, even if you don't have a 2D pattern matching language...)
qN%:eeee::f+:~{S&},2f<:P0f=P::+Xf|P::-Xf|]::=:|
This uses spaces in place of #
and really anything else for .
.
Run all test cases online.
I really hate the duplication in P::+Xf|P::-Xf|
but so far I haven't come up with anything to get rid of it.
Explanation
Don't read on if you want to figure out a solution for yourself.
First, the boring part: getting the two coordinate pairs of the two spaces in the input grid:
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.
Now the interesting part is how to determine whether those coordinates are aligned or not. My code computes all three axes separately:
- The horizontal axis is trivial. Check whether the vertical coordinates match.
Let's look at the north-east diagonal. In the ASCII grid, there are always two antidiagonals that belong to each tri-grid diagonal:
....AV.. ...AV... ..AV....
We can identify the current antidiagonal by adding up the
x
andy
coordinates:01234567 12345678 23456789
So we'd want
0
and1
to belong to the same diagonal, as well as2
and3
, and4
and5
and so on. That means, once we have our anti-diagonal index we want to round up to the next odd number. In other words, we take the bitwise OR with1
. (We could also round down to the next even number by bitwise AND with-2
but that's more expensive in code.)Now the south-east diagonals:
.VA..... ..VA.... ...VA...
In order to give diagonals an index, we subtract the
x
from they
coordinate (representing negative numbers as letters):0abcdefg 10abcdef 210abcde
In this case, we'd want
0
and1
to belong to the same diagonal, as well as-1
and-2
, or2
and3
. So once again, we want to round up to the next odd number.
Here is the code for that:
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.
APL (Dyalog Unicode), 36 27 bytes
1∊=/¯1 0 1∘.(⊥-2|⊣×⊥)⍸⍉⍎¨↑⎕
Try it online!
-9 bytes mostly from @Bubbler
Full program that returns 0
or 1
. Takes input as an array of strings, where each character is 0
for .
or 1
for #
.
How?
Uses the same general strategy as Martin Ender's CJam Answer. The two diagonals are indexed as y+(-1)*x
and y+1*x
, both rounded up to the nearest odd number. The horizontal axis is indexed as y+0*x
with no rounding.
1∊=/¯1 0 1∘.(⊥-2|⊣×⊥)⍸⍉⍎¨↑⎕
↑⎕ ⍝ The input array of strings, converted to a matrix
⍎¨ ⍝ Evaluate each character to obtain either 0 or 1
⍸ ⍝ Find the (y,x) positions of both 1s
∘. ⍝ Outer product:
¯1 0 1 ⍝ For each ⍺ in 1, 0, -1:
⍝ And for each (y,x) position
(⊥ ) ⍝ Compute (⍺×x)+y (convert to base ⍺)
⍝ (⍉-Transposed earlier to get x left of y)
-2|⊣×⊥ ⍝ If odd and ⍺ is not 0: subtract 1
1∊=/ ⍝ Check if the two positions have equal indices on any axis