34
\$\begingroup\$

Produce this square snowflake.

XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
XX   X   X   X   X   X   X   X   X   X   X   X   X   X   X   XX
X XXXX   XXXXX   XXXXX   XXXXX   XXXXX   XXXXX   XXXXX   XXXX X
  XX       X X   X X       X X   X X       X X   X X       XX  
X X XXX XXXX       XXXX XXXX       XXXX XXXX       XXXX XXX X X
XXX XX   X X X   X X X   X X X   X X X   X X X   X X X   XX XXX
X   X XXXX XXX   XXX XXXXX XXX   XXX XXXXX XXX   XXX XXXX X   X
      XX               X X   X   X   X X               XX      
X   X X XXX XXX XXX XXXX               XXXX XXX XXX XXX X X   X
XXX XXX XX   X   X   X X X   X   X   X X X   X   X   XX XXX XXX
X X X   X XXXX   XXXXX XXX XXX   XXX XXX XXXXX   XXXX X   X X X
  XXXXX   XX       X X   X X X   X X X   X X       XX   XXXXX  
X X   X X X XXX XXXX   XXXXX       XXXXX   XXXX XXX X X X   X X
XXXX XX XXX XX   X X X X   X X   X X   X X X X   XX XXX XX XXXX
X       X   X XXXX XXX XX XXXX   XXXX XX XXX XXXX X   X       X
              XX                               XX              
X       X   X X XXX XXX XXX XXX XXX XXX XXX XXX X X   X       X
XXXX XX XXX XXX XX   X   X   X   X   X   X   XX XXX XXX XX XXXX
X X   X X X X   X XXXX   XXXXX   XXXXX   XXXX X   X X X X   X X
  XXXXX   XXXXX   XX       X X   X X       XX   XXXXX   XXXXX  
X X X   X X   X X X XXX XXXX       XXXX XXX X X X   X X   X X X
XXX XXX XXXX XX XXX XX   X X X   X X X   XX XXX XX XXXX XXX XXX
X   X X X       X   X XXXX XXX   XXX XXXX X   X       X X X   X
      XXXXX XXX       XX               XX       XXX XXXXX      
X   X X   X X X X   X X XXX XXX XXX XXX X X   X X X X   X X   X
XXX XXXX XXXX   XXX XXX XX   X   X   XX XXX XXX   XXXX XXXX XXX
X X X       X X X X X   X XXXX   XXXX X   X X X X X       X X X
  XXXXX   XXXXX   XXXXX   XX       XX   XXXXX   XXXXX   XXXXX  
X X   X   X   X X X   X X X XXX XXX X X X   X X X   X   X   X X
XXXX XXX XXX XX XXXX XX XXX XX   XX XXX XX XXXX XX XXX XXX XXXX
X               X       X   X XXX X   X       X               X
                              XXX                              
X               X       X   X XXX X   X       X               X
XXXX XXX XXX XX XXXX XX XXX XX   XX XXX XX XXXX XX XXX XXX XXXX
X X   X   X   X X X   X X X XXX XXX X X X   X X X   X   X   X X
  XXXXX   XXXXX   XXXXX   XX       XX   XXXXX   XXXXX   XXXXX  
X X X       X X X X X   X XXXX   XXXX X   X X X X X       X X X
XXX XXXX XXXX   XXX XXX XX   X   X   XX XXX XXX   XXXX XXXX XXX
X   X X   X X X X   X X XXX XXX XXX XXX X X   X X X X   X X   X
      XXXXX XXX       XX               XX       XXX XXXXX      
X   X X X       X   X XXXX XXX   XXX XXXX X   X       X X X   X
XXX XXX XXXX XX XXX XX   X X X   X X X   XX XXX XX XXXX XXX XXX
X X X   X X   X X X XXX XXXX       XXXX XXX X X X   X X   X X X
  XXXXX   XXXXX   XX       X X   X X       XX   XXXXX   XXXXX  
X X   X X X X   X XXXX   XXXXX   XXXXX   XXXX X   X X X X   X X
XXXX XX XXX XXX XX   X   X   X   X   X   X   XX XXX XXX XX XXXX
X       X   X X XXX XXX XXX XXX XXX XXX XXX XXX X X   X       X
              XX                               XX              
X       X   X XXXX XXX XX XXXX   XXXX XX XXX XXXX X   X       X
XXXX XX XXX XX   X X X X   X X   X X   X X X X   XX XXX XX XXXX
X X   X X X XXX XXXX   XXXXX       XXXXX   XXXX XXX X X X   X X
  XXXXX   XX       X X   X X X   X X X   X X       XX   XXXXX  
X X X   X XXXX   XXXXX XXX XXX   XXX XXX XXXXX   XXXX X   X X X
XXX XXX XX   X   X   X X X   X   X   X X X   X   X   XX XXX XXX
X   X X XXX XXX XXX XXXX               XXXX XXX XXX XXX X X   X
      XX               X X   X   X   X X               XX      
X   X XXXX XXX   XXX XXXXX XXX   XXX XXXXX XXX   XXX XXXX X   X
XXX XX   X X X   X X X   X X X   X X X   X X X   X X X   XX XXX
X X XXX XXXX       XXXX XXXX       XXXX XXXX       XXXX XXX X X
  XX       X X   X X       X X   X X       X X   X X       XX  
X XXXX   XXXXX   XXXXX   XXXXX   XXXXX   XXXXX   XXXXX   XXXX X
XX   X   X   X   X   X   X   X   X   X   X   X   X   X   X   XX
XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX

TIO link, and a more square spaced-out version.

How it's made

You start with a initial crystal (cell) at the center. Then, a new crystal is formed simultaneously at each empty space that touches exactly one existing crystal, looking at the 8 cells orthogonally or diagonally adjacent to it. Crystals remain indefinitely. Here is the snowflake after 3 steps, marking the crystals added at each step.

333 333
32   23
3 111 3
  101 
3 111 3
32   23
333 333

We continue this for 31 steps, making a 63-by-63 snowflake with 1833 crystals.

This process is the Life-like (totalistic) cellular automaton B1/S012345678, also known as H-trees or Christmas Life.

Output

Output or print in any 2D array format with two distinct entries for crystal and empty space, or anything that displays as such. The grid must by exactly 63 by 63, that is having no wasted margin. It's fine to have trailing spaces for non-crystals or jagged arrays truncated to the last crystal in each row. A trailing newline is also OK.

Bit representations are not valid unless they display with two distinct symbols for the bits by default.


I also posted this challenge on Anarchy Golf. It requires a strict output format of the ASCII art above of X's and spaces.

\$\endgroup\$
2
  • \$\begingroup\$ Is this representation acceptable? Matrix with 0 and 1, displayed with spaces in betwee \$\endgroup\$
    – Luis Mendo
    Commented May 11, 2020 at 20:16
  • \$\begingroup\$ @LuisMendo Yes, that's completely fine. \$\endgroup\$
    – xnor
    Commented May 11, 2020 at 20:18

17 Answers 17

20
\$\begingroup\$

MATL, 21 19 bytes

l31:"TTYat3Y6Z+1=Y|

Try it online!

Explanation

l         % Push 1 (this is the initial 1×1 array)
31:"      % Do 31 times
  TTYa    %   Extend with a frame of zeros in 2D
  t       %   Duplicate
  3Y6     %   Push [1 1 1; 1 0 1; 1 1 1] (8-neighbourhood; predefined literal)
  Z+      %   2D convolution, maintaining size. This gives the number of active
          %   neighbours for each cell
  1=      %   Equal to 1? Element-wise
  Y|      %   Logical OR
          % End (implicit)
          % Display (implicit)
\$\endgroup\$
2
  • 2
    \$\begingroup\$ @Downvoter: any suggestion for improvement? What problem do you find with my answer? \$\endgroup\$
    – Luis Mendo
    Commented May 13, 2020 at 22:00
  • 2
    \$\begingroup\$ Someone's just jealous ;) \$\endgroup\$ Commented May 14, 2020 at 14:41
10
\$\begingroup\$

APL (Dyalog Unicode), 31 29 27 bytes

(⊢∨1={≢⍸⍵}⌺3 3)⍣≡∘.×⍨32=⍳63

Try it online!

-4 bytes thanks to @ngn.

A full program that prints a boolean matrix.

How it works

(⊢∨1={≢⍸⍵}⌺3 3)⍣≡∘.×⍨32=⍳63
                     32=⍳63  ⍝ A 63-length vector whose center element is 1
                             ⍝ and the rest is 0
                 ∘.×⍨  ⍝ Outer product self by ×, giving initial state of CA
(             )⍣≡  ⍝ Run the cellular automaton until it stabilizes...
     {≢⍸⍵}⌺3 3     ⍝ Count ones in 3-by-3 subgrids
   1=              ⍝ Test if the 3×3 subgrid has exactly one alive cell
 ⊢∨                ⍝ or the cell is already alive
\$\endgroup\$
4
  • \$\begingroup\$ This is very nice. \$\endgroup\$
    – Jonah
    Commented May 12, 2020 at 2:05
  • 1
    \$\begingroup\$ ¯63↑32↑1 -> 32=⍳63 \$\endgroup\$
    – ngn
    Commented May 12, 2020 at 2:10
  • \$\begingroup\$ {5⌷⍵∨1=+/⍵}∘,⌺3 3 -> (⊢∨1={+/,⍵}⌺3 3) \$\endgroup\$
    – ngn
    Commented May 12, 2020 at 2:18
  • \$\begingroup\$ +/,⍵ (in mine) -> ≢⍸⍵ \$\endgroup\$
    – ngn
    Commented May 12, 2020 at 2:27
9
\$\begingroup\$

Python 2 with scipy, 105 bytes

from scipy.signal import*
A=[1],
K=1,1,1
exec"A=convolve2d(A,[K,(1,9,1),K]);A=(A>8)+(A==1)+0;"*31
print A

Try it online!

Use convolution to grow the array. The convolution kernel used is:

[[1, 1, 1]
 [1, 9, 1]
 [1, 1, 1]]

and the criteria for living cell is:

c >= 9 or c==1

aka when the cell is already living or when there is exactly 1 neighbor.

Note that NumPy by default only prints a summary of a large array, like so:

[[1 1 1 ... 1 1 1]
 [1 1 0 ... 0 1 1]
 [1 0 1 ... 1 0 1]
 ...
 [1 0 1 ... 1 0 1]
 [1 1 0 ... 0 1 1]
 [1 1 1 ... 1 1 1]]

Thus, I have to call numpy.set_printoptions to force Numpy to prints the entire array. This part is not included in the byte count, since I dont't think it's relevant to the actual problem.

This 114 bytes function returns the array instead of printing it out, thus circumventing the print option problem.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ This truncated printing is fine, since it's the default numpy way to render arrays. I added "with scipy" to the header as per the convention that's it being installed is akin to a language version, as I expressed here. \$\endgroup\$
    – xnor
    Commented May 12, 2020 at 1:36
  • 1
    \$\begingroup\$ The exec * 31 trick is amazing ! \$\endgroup\$ Commented May 13, 2020 at 22:11
  • \$\begingroup\$ You might be interested in trying the anarchy version of this challenge that I posted \$\endgroup\$
    – xnor
    Commented May 20, 2020 at 9:15
  • \$\begingroup\$ @xnor Thanks, I'll take a look. I've never done anarchy golf before, but it seems like the output is more restrictive. I might have to try a different approach. \$\endgroup\$ Commented May 21, 2020 at 1:34
7
\$\begingroup\$

J, 38 34 bytes

3 3(1 e.+/,4&{)@,;._3^:31*/~0=i:62

Try it online!

-3 bytes thanks to ngn

-1 byte thanks to Bubbler

Try it online!

Core ideas taken from Bubbler's elegant APL answer -- be sure to upvote him.

This was an experiment to see how close I could get using J, which lack's APL diamond operator and so is at a disadvantage.

Instead, J has SubArrays, which requires you to manually add the padding of zeros. I opted here to add all the padding at once, up front: a 125 x 125 matix of zeros with a 1 in the center.

After each iteration, we'll lose 2 from our dimension, so after 31 iterations we'll be down to 63 x 63, which is what we need.

\$\endgroup\$
6
  • \$\begingroup\$ 7812=i.,~125 -> */~0=i:62 \$\endgroup\$
    – ngn
    Commented May 12, 2020 at 4:07
  • \$\begingroup\$ Ofc! Thanks @ngn. \$\endgroup\$
    – Jonah
    Commented May 12, 2020 at 4:17
  • \$\begingroup\$ You can remove the ] between ^:31 and */~. \$\endgroup\$
    – Bubbler
    Commented May 12, 2020 at 4:18
  • \$\begingroup\$ Was just making that change as you commented :) \$\endgroup\$
    – Jonah
    Commented May 12, 2020 at 4:22
  • 1
    \$\begingroup\$ Just found a solution not using ;._3 with the same byte count. Btw, ;.3 / ;._3 is only called MaxCubes when it is called with one argument. With two args, it is Subarrays. \$\endgroup\$
    – Bubbler
    Commented May 12, 2020 at 5:31
6
\$\begingroup\$

JavaScript (ES6),  149 138 136  135 bytes

Returns a binary matrix.

f=k=>k>31?m:f(-~k,m=(k?m:a=[...Array(63)]).map((r=a,y)=>r.map((v,x)=>k?v|!~(g=d=>d--&&g(d)-~~(m[y+~-(d/3)]||0)[x-1+d%3])(9):x*y==961)))

Try it online!

Commented

The same map() loops are used to initialize the 63x63 binary matrix m[] and to recursively update it. Doing a separate initialization of m[] before entering the recursion would cost more bytes.

f = k =>                         // f is a recursive function taking a counter k
  k > 31 ?                       // if k is greater than 31:
    m                            //   stop recursion and return m[]
  :                              // else:
    f(                           //   do a recursive call:
      -~k,                       //     increment k
      m = (                      //     update m[]
        k ? m                    //     if this is not the first iteration, use m[]
          : a = [...Array(63)]   //     otherwise, use a vector a[] of 63 entries
      ).map((r = a, y) =>        //     for each row r[] at position y, using a[]
                                 //     as a fallback for the first iteration:
        r.map((v, x) =>          //       for each value v at position x:
          k ?                    //         if this is not the first iteration:
            v | !~(              //           if v is already set, let it set
              g = d =>           //           or use the result of the recursive
                                 //           function g taking a direction d
              d-- &&             //             decrement d; stop if it's zero
              g(d) -             //             recursive call
              ~~(                //             subtract 1 if the cell at ...
                m[y + ~-(d / 3)] //               ... y + dy ...
                || 0             //
              )[x - 1 + d % 3]   //               ... and x + dx is set
            )(9)                 //           initial call to g with d = 9
          :                      //         else (first iteration):
            x * y == 961         //           set the cell iff x = y = 31 (because 31
                                 //           is prime, it's safe to test xy = 31²)
        )                        //       end of inner map()
      )                          //     end of outer map()
    )                            //   end of recursive call
\$\endgroup\$
4
\$\begingroup\$

T-SQL, 330 266 232 bytes

This takes a long time to execute(reason: must be something wrong with the question).

-22 Bytes thanks to @RossPresser

SELECT top 3969' 'z,IDENTITY(INT,0,1)i,63x
INTO t FROM sys.messages
WHILE @@ROWCOUNT>0UPDATE
t SET z=1WHERE(SELECT SUM(1*z)FROM t x
WHERE(t.i/x-i/x)/2=0and(t.i%x-i%x)/2=0)=1or i=1984and''=z
SELECT string_agg(z,'')FROM t GROUP BY i/x

This will execute in Microsoft SQL Server 2017 or higher. Try it online on dbfiddle.uk; link is set to use markdown for output so you can see the whole snowflake.

Before execute press ctrl-t for output to text instead of grid. This takes 60 seconds to execute on my computer.

\$\endgroup\$
8
  • 1
    \$\begingroup\$ Long time no "see". Thanks for the edit Ross. \$\endgroup\$ Commented May 12, 2020 at 17:55
  • \$\begingroup\$ I fully intend to try to golf this when I get time :) \$\endgroup\$ Commented May 12, 2020 at 19:41
  • \$\begingroup\$ @RossPresser I took another look and realized i could save some bytes. I would love if you found some additional golfing. Performance is better now \$\endgroup\$ Commented May 13, 2020 at 8:13
  • \$\begingroup\$ golfed out 22 bytes by using SELECT INTO instead of CREATE TABLE/INSERT. Might have killed the performance :) Also fixed dbfiddle link to latest. \$\endgroup\$ Commented May 15, 2020 at 16:58
  • 1
    \$\begingroup\$ @t-clausen-dk this is my current golf \$\endgroup\$ Commented May 19, 2020 at 14:32
4
\$\begingroup\$

Python 2, 125 bytes

s="%64c"%10
exec's*=63;s="".join(s[n][(s[n+3967:][:191]*3)[::64].strip()=="X":n!=2015]or"X"for n in range(4032));'*32
print s

Try it online!

This answer is by user "clock" based on hallvabo's solution, on the Anarchy Golf version of this challenge that I submitted. Note that output there is strict and is required to be exactly the picture of X's and spaces to STDOUT via a full program, with only an allowance for a trailing newline.

The most interesting part of this answer, in my opinion, is the concise construction (s[n+3967:][:191]*3)[::64] after s*=63 to get the nine neighbors of the cell counting itself in a flat newline-joined string representing the grid. To check if there's exactly one X among them, .strip() is called to get rid of whitespace on either side, and the result is checked to equal just "X".

It's interesting how simulating the steps on the string representation of the output directly (rather than an array of bits) not only saves on doing a conversion to characters later but also allows string-specific methods to be used in a golfy way.

Another neat trick, borrowed from hallvabo, is "%64c"%10 used to initialize s to 63 spaces followed by a newline for a line of the initial empty grid. Using the %c format, which converts an ASCII value to a character, is shorter than " "*63+"\n" or "%64s"%"\n".

\$\endgroup\$
4
\$\begingroup\$

Wolfram Language (Mathematica) + my LifeFind package, 47 bytes

<<Life`
Last@CA[{{1}},31,Rule->"B1/S01234568"]&

There isn't any living cell with 7 living neighbors in the first 31 steps, so I can golf the rule by 1 byte: B1/S012345678 -> B1/S01234568.

\$\endgroup\$
3
\$\begingroup\$

Charcoal, 38 37 bytes

J³¹¦³¹XF³²«UMKAXF⁶³F⁶³«Jκλ›⁼№KMX¹⁼KKX

Try it online! Link is to verbose version of code. Explanation:

J³¹¦³¹X

Output the X in the centre of the square.

F³²«

Grow the snowflake 31 times. (The last loop is just used for its side-effect of replacing the -s with Xs.)

UMKAX

Change all the -s to Xs.

F⁶³F⁶³«

Iterate over the square.

Jκλ

Jump to each position in the square.

›⁼№KMX¹⁼KKX

If the cell does not yet have an X but it has one neighbouring X then print a -.

\$\endgroup\$
3
\$\begingroup\$

05AB1E, 31 bytes

1¸¸31F0δ.ø¬0*¸.øD2Fε0.øü3O}ø}Θ~

05AB1E and matrices are not a good combination.. :/

Outputs as a 63x63 matrix of 0s and 1s for spaces and crystals respectively.

Try it online. (The footer is to pretty-print it, feel free to remove it to see the actual result.)

Explanation:

1¸¸            # Start with a matrix containing 1: [[1]]
 31F           # Loop 31 times:
    0δ.ø       #  Surround each row with leading and trailing 0
               #   i.e. [[1,1,1],[1,1,1],[1,1,1]] → [[0,1,1,1,0],[0,1,1,1,0],[0,1,1,1,0]]
    ¬          #  Take the first row (without popping the matrix)
               #   → [0,1,1,1,0]
     0*        #  Multiply each value by 0
               #   → [0,0,0,0,0]
       ¸       #  Wrap it into a list
               #   → [[0,0,0,0,0]]
        .ø     #  And surround the matrix with that row of 0s
               #   i.e. [[0,0,0,0,0],[0,1,1,1,0],[0,1,1,1,0],[0,1,1,1,0],[0,0,0,0,0]]
    D          #  Duplicate it
     2F        #  Loop 2 times:
       ε       #   Map each row to:
        0.ø    #    Surround the row with leading and trailing 0
               #     i.e. [0,1,1,1,0] → [0,0,1,1,1,0,0]
           ü3  #    Create overlapping triplets
               #     → [[0,0,1],[0,1,1],[1,1,1],[1,1,0],[1,0,0]]
             O #    Sum each triplet
               #     → [1,2,3,2,1]
       }ø      #   After the map: transpose/zip; swapping rows/columns
               #    i.e. [[0,0,0,0,0],[1,2,3,2,1],[1,2,3,2,1],[1,2,3,2,1],[0,0,0,0,0]]
               #     → [[0,1,1,1,0],[0,2,2,2,0],[0,3,3,3,0],[0,2,2,2,0],[0,1,1,1,0]]
      }Θ       #  After the inner loop: check for each whether it's 1 (1 if 1; 0 otherwise)
               #   i.e. [[1,2,3,2,1],[2,4,6,4,2],[3,6,9,6,3],[2,4,6,4,2],[1,2,3,2,1]]
               #    → [[1,0,0,0,1],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[1,0,0,0,1]]
        ~      #  Take the bitwise-OR of the values at the same positions in the matrices
               #   → [[1,0,0,0,1],[0,1,1,1,0],[0,1,1,1,0],[0,1,1,1,0],[1,0,0,0,1]]
               # (after the loop, the resulting matrix is output implicitly)
\$\endgroup\$
3
\$\begingroup\$

Jelly, 41 34 bytes

ı*Ɱ5I;$Ṗ+)FċⱮẹ1ịƲ;
32×1ıWÇṛ¡’ÆiḞŒṬ

Try it online!

-7 because to nobody's surprise there's two shorter ways to get \$32+32i\$ than “ ‘Æị, the symmetry of the neighborhood lets golf to I, we can trade two ¤s and a for ) and $, exists, œ| is overkill, and selfing ċⱮ is outright superfluous

This is an absolute mess that could probably be outdone easily by someone with any clue as to how to mimic others' convolution-based approach. Outputs a two-dimensional list of ones and zeros, which are conveniently translated to the example's Xs and spaces by the testing footer provided.

ı*Ɱ5I;$Ṗ+)FċⱮẹ1ịƲ;    Monadic helper link: grow a list of complex numbers
         )            For each number:
ı*Ɱ5                  raise the imaginary unit 1j to each power from 1 to 5,
    I;$               prepend the differences between its adjacent elements,
       Ṗ              remove the extra 1j,
        +             and add each to the number.
          F           Flatten the resulting list of lists,
               ịƲ     take the elements at indices
             ẹ1       which are indices of 1 in
           ċⱮ         the list of how many times each element occurs,
                 ;    and append the original list.

32×1ıWÇṛ¡’ÆiḞŒṬ    Niladic main link: generate the snowflake
32                 Set the argument to 32,
  ×1ı              then multiply it by 1+1j
     W             and wrap it in a singleton list.
      Ç ¡          Grow that a number of times equal to
       ṛ ’         the argument minus 1.
          ÆiḞ      Convert the complex numbers to pairs of integers,
             ŒṬ    and interpret the pairs as coordinates of 1s in a 2D array.
\$\endgroup\$
2
\$\begingroup\$

PHP, 206 bytes

for($a[][]=1;++$n<32;){$b=$a;for($i=$n;$i>=-$n;$i--)for($j=$n;$j>=-$n;$j--){$a[$i][$j]=$a[$i][$j]&1;$c=0;for($k=2;--$k>-2;)for($l=2;--$l>-2;)if($k|$l)$c+=$b[$i+$k][$j+$l];1!=$c?:$a[$i][$j]=1;}}var_dump($a);

Try it online!

Well I'm getting used to horrible PHP answers :D don't blame the language, there are libs for matrixes.. displays an unordered array of 1 and 0, but with proper keys. change the first loop value (32) to generate any size snowflake..

24 bytes could have been saved by removing $a[$i][$j]=$a[$i][$j]&1; if we only needed the truthy values.

\$\endgroup\$
2
\$\begingroup\$

Python 2, 146 130 bytes

Prints a 2d-list of booleans.

R=range(63)
for i in R:m=[[i>0==(x*y-961)*0**m[y][x]*~-sum(sum(k[x+x%~x:x+2])for k in m[y+y%~y:y+2])for x in R]for y in R]
print m

Try it online!

\$\endgroup\$
4
  • \$\begingroup\$ Nice trick with the x%~x. How did you come up with that? \$\endgroup\$
    – xnor
    Commented May 13, 2020 at 5:53
  • \$\begingroup\$ @xnor I didn't like the x+(x>0), so I tried to find something better. x-1+1%-~x would work, so I tried a few more arguments to %. If I hadn't arrived at x+x%~x by hand, I would have bruteforced it. \$\endgroup\$
    – ovs
    Commented May 13, 2020 at 6:39
  • \$\begingroup\$ @xnor did a brute force search now, turns out -2%-~x and 0-2%~a both work at the same length. \$\endgroup\$
    – ovs
    Commented May 13, 2020 at 8:07
  • \$\begingroup\$ You might be interested in trying the anarchy version of this challenge that I posted \$\endgroup\$
    – xnor
    Commented May 20, 2020 at 9:15
2
\$\begingroup\$

R, 144 122 118 bytes

m=matrix(!-2112:2112,65)
for(k in 1:31){l=m;for(i in 67:4159)if(sum(l[i+-3:5%/%3+-1:1*65][-5])==1)m[i]=1}
m[2:64,2:64]

Try it online!

My first code golf attempt (except for secret ones that I never dared to post...), so nothing really clever going on, I'm afraid...

Edit 1: -4 bytes to remove useless variable definition

Edit 2: thanks to Giuseppe: -18 bytes!

Edit 3: thanks again to Giuseppe: -4 more bytes

\$\endgroup\$
6
  • 1
    \$\begingroup\$ Nice work! Some suggestions. \$\endgroup\$
    – Giuseppe
    Commented May 14, 2020 at 14:32
  • \$\begingroup\$ Thankyou! I've edited-in your suggestions, with acknowledgement. Very much appreciated! \$\endgroup\$ Commented May 14, 2020 at 15:17
  • 1
    \$\begingroup\$ 118 bytes \$\endgroup\$
    – Giuseppe
    Commented May 14, 2020 at 18:24
  • \$\begingroup\$ Thankyou again Giuseppe. Especially for (implicitly) pointing-out my beginner's errors (useless '>1'...)... editing-in again now... \$\endgroup\$ Commented May 14, 2020 at 19:46
  • \$\begingroup\$ You've come a long way since this answer :-) \$\endgroup\$
    – Giuseppe
    Commented Jan 5, 2022 at 14:51
1
\$\begingroup\$

Java (JDK), 243 bytes

v->{int N=63,K=N*N,g[][]=new int[N][N],w[]=new int[K],i=31,x,c,y;for(g[i][i]=1;i-->0;){for(x=K;x-->0;w[x]=c==1?x+1:0)for(c=0,y=K;y-->0;)if(g[y%N][y/N]>0&(Math.abs(x%N-y%N)|Math.abs(x/N-y/N))<2)c++;for(int z:w)if(z-->0)g[z%N][z/N]=1;}return g;}

Try it online!

Explanations

Basically, the algorithm is to fill two grids by consecutive merges to keep the data from being changed at runtime. For each square, we check if there are neighbours set (using a second full loop instead of a smaller 1-square distance to avoid byte-costly constraints). If there's exactly one neighbour, the square is added to the writing (to-be-merged) grid. Then when all the computation is done, the writing-grid is merged to the main grid. When all the 31 loops are done, the resulting grid is returned.

v->{
  int N=63,
      K=N*N,
      g[][]=new int[N][N],          // the grid and return-value, we read from it
      w[]=new int[K],               // the temp array to write in
      i=31,                         // the main iterator to expand the snowflakes
      x,c,y;                        // x the position being tested, c the count of neighbours, y the neighbour candidates
  for(    g[i][i]=1;                // Init the snowflake in its center
          i-->0;                    // Expand the snowflake 31 times
    ){
    for(    x=K;                     // init x to match all the positions
            x-->0;                   // For each position
            w[x]=c==1?x+1:0          // If the counter is exactly 1,
                                     // set x as a position that's not empty.
                                     // and store x+1 instead of 1 or x to ease the merge operation
                                     // and leave 0 as a default value
       )
      for(c=0,y=K;y-->0;)            // Reset the count and loop through all squares again
        if(  g[y%N][y/N]>0           // if y is set
            &( Math.abs(x%N-y%N)     // and if x and y are neighbours
              |Math.abs(x/N-y/N))<2
          )
          c++;                       // Then increase the neighbour-count.
    for(int z:w)                     // For each value to be merged
      if(z-->0)                      // which is +1'd and non default
        g[z%N][z/N]=1;               // Then place it in the grid.
  }
  return g;                          // Return the grid
}
\$\endgroup\$
2
  • \$\begingroup\$ c==1?x+1:0 and if(z-->0) can be c==1?x:-1 and if(z>=0) for -2. \$\endgroup\$ Commented May 14, 2020 at 13:14
  • \$\begingroup\$ Building on @KevinCruijssen 235 bytes \$\endgroup\$
    – ceilingcat
    Commented Dec 1, 2022 at 16:17
1
\$\begingroup\$

C (gcc), 207 206 192 bytes

-1 -14 bytes thanks to ceilingcat!

#define F(x)for(x=64;--x;
#define z M[r][c]
M[65][65]={[32][32]=32},r,c,i=32,x;main(s){for(;--i;)F(r))F(c)z=s-!z?z:i)for(s=0,x=-9;x++;)s+=M[x/3-~r][x%3-~c]>i;F(r)puts(""))F(c))putchar(33-!z);}

Try it online!

To avoid having to use two tables (one for current iteration and one for the next), each new crystal is written using the current iteration number, instead of just using 1. This allows for ignoring any crystals from the current iteration when counting neighbours.

A lot of the counting is done backwards for golfing reasons, including the iteration number, which is why we seed the table with 32 in the middle.

The table is made too large so as to have padding, allowing us to count neighbours without having to care about edge-cases.

A more elegant solution is bound to exist. This many loops is hardly ever a good sign.

#define F(x)for(x=64;--x;       To make recurring loops more compact.
                                Goes from 63 down to 1, to skip padding in table.
M[65][65]={[32][32]=32},        Make padded table seeded with first crystal.
r,c,i=32,x,y;main(s){           Misc variables; i holds iteration.
for(;--i;)F(r))F(c)             Loop through table for each iteration.
s==!M[r][c]?M[r][c]=i:0)        Update current cell according to neighbour count
                                found in loop below. We only update if cell is empty
                                (M[r][c] == 0) and if s == 1, combined as shown.
for(s=0,x=r-2;x++<=r;)          Go through 3x3 grid with current cell in center.
for(y=c-2;y++<=c;)
s+=M[x][y]>i;                   If a cell contains a crystal NOT from current gen,
                                increase our neighbour count.

F(r)puts(""))F(c))              Output loop
putchar(33-!M[r][c]);}          Make any non-zero cell a exclamation mark; space otherwise
\$\endgroup\$
1
  • \$\begingroup\$ @ceilingcat Neat one. For some reason I abandonded that avenue too early. \$\endgroup\$
    – gastropner
    Commented May 15, 2020 at 20:19
0
\$\begingroup\$

JavaScript (V8), 465 bytes

[w=1414812756,269488144,357569872,285212944,22304e3,286265616,353718608,69648,1414856704,269553680,357650768,17830160,1426150656,286327056,1364280656,0,w,1343229968,1162876240,83886352,1146377472,1414533392,1078284624,327680,1078219860,1414811664,1145062736,89392384,1141130324,1427395664,1073758277,5].map(e=>(Array(32).fill().map(l=>(c.push(1&e?"X":" "),e>>=1),c=[]),c.slice(1).reverse``.concat(c)),o=e=>console.log(e.join``)||e).map(o).reverse``.slice(1).map(o);

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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