21
\$\begingroup\$

TLDR: This is the hexagonal version of Is this square symmetrical?

Given a hexagonal grid, decide if it is symmetric.

The shape of the grid is a regular hexagon. Each cell in the grid has two possible states.

Let's only consider reflections and rotations. Here are all the possible symmetries:

  • Reflection symmetry, where the axis is the perpendicular bisector of an edge (there are 3 possible such axes):

    enter image description here enter image description here enter image description here

    Smaller examples in ASCII art:

   . . . .         . . * .         * . * .
  . * . * .       * . * * .       . . . . *
 * . . . . *     * * . . . .     . * . . . .
* * . . . * *   * * * * . * .   * . . . . . *
 . . * * . .     . * * . * *     . . . . * .
  . . * . .       . * * . .       * . . . .
   * . . *         * * * .         . * . *
  • Reflection symmetry, where the axis is a diagonal (there are 3 possible such axes):

    enter image description here enter image description here enter image description here

    Smaller examples in ASCII art:

   * . * *         . . * *         * * . *
  * * . * .       . * . * .       . * . . .
 . . . . . .     * . . . . .     * . . . . *
* . . . . . .   * * . . . * .   * * . * . * *
 . . . . . .     . . . . * *     . . . . . .
  * * . * .       . * * . .       . . . * *
   * . * *         . * . .         * . . *
  • 60° rotational symmetry:

    enter image description here

    A smaller example in ASCII art:

   * * . *
  . * . * *
 * . . . . .
* * . * . * *
 . . . . . *
  * * . * .
   * . * *
  • 120° rotational symmetry:

    enter image description here

    A smaller example in ASCII art:

   * . . .
  . . * . *
 * . . . . .
. . . . . . *
 . * . . * .
  . . . . .
   * . * .
  • 180° rotational symmetry:

    enter image description here

    A smaller example in ASCII art:

   . . . .
  * . * . .
 . . * * . .
* . . . . . *
 . . * * . .
  . . * . *
   . . . .

Input

A hexagonal grid, in any reasonable format. You may choose the two distinct values for the two states in the input. When taking input as an 2d array, you may use one of the two states or a third value for padding.

Some example inputs (Taken from Bubbler's HexaGoL challenge):

  • ASCII art:
  . . . 
 * . . * 
* . * * * 
 * * * . 
  * . . 
  • List of rows:
[[0, 0, 0],
 [1, 0, 0, 1],
 [1, 0, 1, 1, 1],
 [1, 1, 1, 0],
 [1, 0, 0]]
  • 2d array, skewed to the right (with zero padding):
[[0, 0, 0, 0, 0],
 [0, 1, 0, 0, 1],
 [1, 0, 1, 1, 1],
 [1, 1, 1, 0, 0],
 [1, 0, 0, 0, 0]]
  • 2d array, skewed to the left (with 2's as padding):
[[0, 0, 0, 2, 2],
 [1, 0, 0, 1, 2],
 [1, 0, 1, 1, 1],
 [2, 1, 1, 1, 0],
 [2, 2, 1, 0, 0]]
  • Flatten array, with an integer that indicates the size:
3, [0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0]

Output

A value representing whether the hexagonal grid is symmetric. You can choose to

  • output truthy/falsy using your language's convention (swapping is allowed), or
  • use two distinct, fixed values to represent true (affirmative) or false (negative) respectively.

This is , so the shortest code in bytes wins.

Testcases

Here I use 2d arrays skewed to the left with zero padding.

Truthy:

[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[0, 0, 0], [0, 1, 0], [0, 1, 1]]
[[1, 1, 1, 0, 0], [1, 0, 0, 1, 0], [1, 0, 1, 0, 1], [0, 1, 0, 0, 1], [0, 0, 1, 1, 1]]
[[1, 0, 1, 0, 0], [0, 1, 1, 1, 0], [1, 0, 1, 1, 1], [0, 1, 0, 1, 0], [0, 0, 1, 0, 1]]
[[1, 0, 0, 0, 0], [0, 0, 1, 1, 0], [0, 1, 1, 1, 1], [0, 1, 1, 0, 1], [0, 0, 1, 1, 1]]
[[1, 1, 1, 1, 0, 0, 0], [1, 0, 1, 0, 1, 0, 0], [1, 0, 0, 1, 0, 1, 0], [1, 0, 0, 1, 0, 0, 1], [0, 1, 0, 1, 0, 0, 1], [0, 0, 1, 0, 1, 0, 1], [0, 0, 0, 1, 1, 1, 1]]

Falsy:

[[1, 0, 0], [0, 0, 0], [0, 1, 1]]
[[0, 1, 0], [1, 0, 1], [0, 0, 0]]
[[0, 0, 0, 0, 0], [0, 0, 1, 1, 0], [1, 0, 1, 1, 1], [0, 1, 0, 1, 0], [0, 0, 1, 0, 1]]
[[0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [1, 1, 0, 0, 0], [0, 0, 0, 1, 1], [0, 0, 0, 0, 0]]
[[0, 0, 0, 0, 0], [1, 1, 0, 0, 0], [1, 0, 1, 1, 1], [0, 1, 0, 1, 0], [0, 0, 0, 1, 0]]
[[1, 0, 1, 1, 0, 0, 0], [1, 1, 1, 1, 1, 0, 0], [0, 1, 1, 0, 1, 1, 0], [0, 1, 0, 1, 0, 0, 1], [0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0]]
\$\endgroup\$
6
  • 4
    \$\begingroup\$ The examples in the images (not the smaller ones in ASCII art) are still lifes in hexagonal cellular automaton B2p6/S02m3-m4p6H. \$\endgroup\$
    – alephalpha
    Jan 22 at 4:22
  • 3
    \$\begingroup\$ I knew this was alephalpha before I scrolled to the author. \$\endgroup\$
    – null
    Jan 22 at 5:42
  • \$\begingroup\$ idk how to do this lmao i need a reference code but ok nice challenge! \$\endgroup\$
    – DialFrost
    Jan 22 at 9:07
  • 1
    \$\begingroup\$ Don't get 2d array, skewed to the right (with zero padding):. The second from the top is shift to the right but the bottom two are shift to the left. Is this correct? \$\endgroup\$
    – Noodle9
    Jan 22 at 11:02
  • \$\begingroup\$ @Noodle9 That's correct. \$\endgroup\$
    – alephalpha
    Jan 22 at 11:03

4 Answers 4

8
\$\begingroup\$

Python NumPy, 92 bytes (@Neil)

def f(l,*o):
 for a in[l>0]*6:l.T[::-1][a[::-1]]=l[a];o+=str(l),str(l.T)
 return 7>len({*o})

Attempt This Online!

Pure (no NumPy) Python version, 111 bytes

lambda l:7>len({l:=((x:=~len(l)//2)and(*(k[(x:=x+1):]+k[:x]for k in i*l[::-1]),)or(*zip(*l),))for i in[0,1]*6})

Attempt This Online!

Old Python, 128 bytes

def f(*l):
 for n in[len(*l)//2]*6:l+=(k:=(*(j[i:]+j[:i]for i,j in enumerate(l[-1][::-1],-n)),)),(*zip(*k),)
 return 7>len({*l})

Attempt This Online!

Old Python NumPy, 93 bytes

def f(l,*o):
 for a in[l>0]*6:l.T[::-1][a[::-1]]=l[a];o+=str(l),str(l.T)
 return 12>len({*o})

Attempt This Online!

Old Python NumPy, 97 bytes

def f(l):
 o={0}
 for a in[l>0]*6:l[::-1][a[::-1]]=l[a];o|={str(l),str(l:=l.T)}
 return 13>len(o)

Attempt This Online!

Old Python NumPy, 111 bytes

def f(l):a=l>0;b=l*0;l=l[a];b[a]=range(len(l));return 12>len({str(l:=l[s])for s in[b.T[a],b[::-1][a[::-1]]]*6})

Attempt This Online!

Takes right-skewed zero-padded input with values 1 and 2.

Generates the 12 possible symmetries from two relatively easy to implement reflections, viz. updown and matrix transpose. As their axes subtend an angle of 30° their composition is a 60° rotation. We can therefore apply them alternately and then count the number of distinct patterns.

\$\endgroup\$
2
  • \$\begingroup\$ Can len({*o}) actually take any values between 6 and 12? If not, you could use <7 instead of <12. \$\endgroup\$
    – Neil
    Jan 22 at 13:32
  • \$\begingroup\$ @Neil pretty sure you are correct. Thanks! \$\endgroup\$
    – loopy walt
    Jan 22 at 14:29
6
\$\begingroup\$

Charcoal, 61 58 bytes

WS⊞υ⪪ι¹≔⟦⟧θF⁶F²«⊞θ⭆υ⪫λωUMυ⎇κ⮌λE✂υ⁺⊘Lυμ±⁻⊘⊕׳Lυμ±¹⊟ν»⊙θ⊖№θι

Try it online! Link is to verbose version of code. Takes input as newline-terminated ASCII art but without any spaces and outputs a Charcoal boolean, i.e. - for symmetric, nothing if not. Explanation:

WS⊞υ⪪ι¹

Input the list of rows.

≔⟦⟧θ

Start building up the list of rows and reflection.

F⁶F²«

Loop through six rotations and two reflections. (Probably overkill, but I can't make it any shorter by performing less work.)

⊞θ⭆υ⪫λω

Save the current hexagon to the list.

UMυ⎇κ

Modify the hexagon in-place, alternating between either...

⮌λ

... reflecting it along the T-B bisector, or...

E✂υ⁺⊘Lυμ±⁻⊘⊕׳Lυμ±¹⊟ν

... reflecting it along the BL-TR diagonal. Since the combination of these two reflections is a 60° rotation, this eventually covers all possible symmetries.

»⊙θ⊖№θι

Check the list for duplicates.

The BL-TR diagonal reflection is obtained by taking slices of the hexagon, starting from just the top half, extending each row until the whole hexagon is covered, then shrinking until the last row takes the bottom half of the hexagon. The last character of each row is removed and these characters form the new row of the hexagon.

Previous 61-byte canvas based version:

WS⊞υι≔⟦⟧θF³«FLυ«M✳⁻ι⊗⊕‹⊗κLυP✳⊖ι§υκ»F²«⊞θ⪫KAω‖»⎚»F✂θ⊞θ⮌ι⊙θ⊖№θι

Try it online! Link is to verbose version of code. Takes input as newline-terminated ASCII art but without any spaces and outputs a Charcoal boolean, i.e. - for symmetric, nothing if not. Explanation:

WS⊞υι

Input the ASCII art.

≔⟦⟧θ

Start building up the list of rotations and reflections.

F³«

Loop through the rotations of -60°, 0° and 60°.

FLυ«

Loop though each line of the ASCII art.

M✳⁻ι⊗⊕‹⊗κLυ

Move along the edge of the hexagon.

P✳⊖ι§υκ

Output the line of ASCII art.

»F²«

Loop through each reflection.

⊞θ⪫KAω

Serialise the ASCII art back to text and join all of the lines together.

Reflect the ASCII art horizontally.

»⎚

Clear the canvas ready for the next rotation.

»F✂θ⊞θ⮌ι

Append the 180° rotations of the above rotations and reflections to the list.

⊙θ⊖№θι

Check the list for duplicates.

Here's a 73 byte modification that takes (spaced) ASCII art as input and outputs all 12 rotations and reflections as ASCII art:

WS⊞υ⁻ι ≔⟦⟧θF³«FLυ«P✳⊖ι⪫§υκ… ¬⊖ι¿‹⊗⊕κLυM⊕¬ι✳⁺⁴÷׳ι²M⊕‹¹ι✳⁻⁻ι¬ι²»F²«D‖D‖↓»⎚

Try it online! Link is to verbose version of code. Output is in the following order:

  • Rotate 60° clockwise
  • Reflect along TL-BR diagonal
  • Rotate 120° anticlockwise
  • Reflect along BR-TL bisector
  • Rotate 0°
  • Reflect along T-B bisector
  • Rotate 180°
  • Reflect along L-R diagonal
  • Rotate 60° anticlockwise
  • Reflect along BR-TL diagonal
  • Rotate 120° clockwise
  • Reflect along TL-BR bisector
\$\endgroup\$
5
\$\begingroup\$

Python 3.8 (pre-release), 137 bytes

g=lambda h:(*[".".join(r.split(".")[::-1])for r in h],)
f=lambda h,*S:len(S)<8>0<f(g(map("".join,zip(*(t:=h[::-1])))),h,g(t),*S)or h in S

Try it online!

The function f takes in a tuple of strings representing a left-skewed hexagon. Returns True if the hexagon is symmetric, or False otherwise.

Explanation

At each iteration, adds the current hexagon and its vertical flip to the list S. Then rotates the hexagon by 60 degrees clockwise, and repeats. Stops when we finds a duplicate hexagon (symmetric), or if S gets too big (not symmetric).

Skew helper

g is a helper function that converts a right-skewed hexagon to a left-skewed one:

..ABC      ABC..
.DEFG      DEFG.
HIJKL  ->  HIJKL
MNOP.      .MNOP
QRS..      ..QRS

This is done by taking each row r, and swapping the empty (.) with non-empty positions: ".".join(r.split(".")[::-1])

Rotate a hexagon

To rotate a hexagon: simply rotates the 2D array 90 degrees, then applies g to fix the skewness.

ABC..          ..HDA        HDA..
DEFG.   rot90  .MIEB   g    MIEB.
HIJKL  ------> QNJFC -----> QNJFC
.MNOP          ROKG.        .ROKG
..QRS          SPL..        ..SPL

Rotating a 2D array can be done with map("".join,zip(*h[::-1]))

Flip a hexagon vertically

Simply flips the 2D array vertically, then applies g to fix the skew: g(h[::-1])

\$\endgroup\$
1
\$\begingroup\$

Pari/GP, 72 bytes

Based on @loopy walt's Python answer.

a->7>#Set([a=if(i%2,matrix(#a,,i,j,a[i,(#a\2+i-j)%#a+1]),a~)|i<-[1..8]])

Try it online!

Takes a matrix skewed to the left with zero padding.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.