10
\$\begingroup\$

Your lab needed to simulate how a particular cell evolves over time in a 2D grid space. A sample 2D grid space below shows a single cell at the centre of the grid.

0 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0

The cell evolution follows these rules:

  1. '0' indicates no live cell
  2. A positive number indicates a live cell. The number indicates its age.
  3. A cell will grow from age 1 to 5 in each evolution
  4. After age 5, a cell will die at the next evolution (resetting to '0')
  5. If a cell has 4 or more neighbours (adjacent and diagonally), it will die due to over-crowding.
  6. In each evolution, a live cell will spread to its neighbour (adjacent and diagonally) if there is no live cell there

Rule change

Given an integer n in the input, which represents the size of the grid given, output the next n evolution of cells

Extra rules:

  1. The first live cell is always in the center of the grid
  2. n must be odd so the live cell is always centered
  3. The first grid of the 1 in the center is not counted as an evolution

Test case

Only 1 to save space in question

Input: 3

0 0 0
0 1 0
0 0 0
1 1 1
1 2 1
1 1 1
2 0 2
0 0 0
2 0 2
3 1 3
1 1 1
3 1 3

This is code-golf, so shortest bytes wins!

\$\endgroup\$
19
  • 3
    \$\begingroup\$ Would you mind adding the result for n=5 (in a pastebin perhaps to not clutter the challenge description)? \$\endgroup\$ Jan 20, 2022 at 8:33
  • 3
    \$\begingroup\$ @tsh "n must be odd so the live cell is always centered". \$\endgroup\$
    – ophact
    Jan 20, 2022 at 9:38
  • 2
    \$\begingroup\$ How fixed is the output format? Can we return nested arrays of integers or do we have to print space separated integers? \$\endgroup\$
    – ovs
    Jan 20, 2022 at 10:40
  • 6
    \$\begingroup\$ Reminder: cumbersome I/O formats is the most upvoted thing to avoid. \$\endgroup\$
    – Arnauld
    Jan 20, 2022 at 13:53
  • 3
    \$\begingroup\$ Also: if you really want a fixed output format, this should be clearly specified in the challenge. \$\endgroup\$
    – Arnauld
    Jan 20, 2022 at 14:00

7 Answers 7

4
\$\begingroup\$

JavaScript (ES6), 222 bytes

This version uses the cumbersome output format mentioned in the comments.

n=>(v=[...Array(n)],z=~-n/2*~n,g=m=>~n--?[m.map(r=>r.join` `).join`
`,...g(m.map((r,y)=>r.map((v,x)=>[t=0,..."1235678"].map(d=>(m[y+~-(d/3)]||0)[x+d%3-1]&&t++)|v++?v%=t>3||6:+!!t)))]:[])(v.map(_=>v.map(_=>+!z++))).join`

`

Try it online!

Or 187 bytes if a standard output is allowed (a list of matrices).

Center cell of the matrix

Given the width \$n\$ of the matrix, we define:

$$z=\frac{(n-1)\times(-n-1)}{2}$$

Or as JS code: z=~-n/2*~n

We increment \$z\$ after each visited cell while walking through the matrix from left to right and top to bottom. The center cell is reached when \$z=0\$.

For instance, for \$n=5\$ we start with \$z=-12\$, leading to:

$$\begin{pmatrix}-12&-11&-10&-9&-8\\ -7&-6&-5&-4&-3\\ -2&-1&0&1&2\\ 3&4&5&6&7\\ 8&9&10&11&12\end{pmatrix}$$

This is -- I think -- shorter than keeping track of \$(x,y)\$ and doing the test on them.

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

APL(Dyalog Unicode), 62 bytes SBCS

{(0,⍳⍵){(6|{(+/∊8⍳⍤-4×5⊃⊢)×,⍵}⌺3 3×1+⊢)⍣⍺⊢⍵}¨⊂⍵ ⍵⍴1↑⍨-⌈2÷⍨⍵*2}

Try it on APLgolf!

Or 54 bytes as a full program with a questionable output format:

{(6|{(+/∊8⍳⍤-4×5⊃⊢)×,⍵}⌺3 3×1+⎕∘←)⍣⍵⊢⍵ ⍵⍴1↑⍨-⌈2÷⍨⍵*2}⎕

Try it online! Slightly adjusted to run on the version 17 on TIO.

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

Python 3.8 (pre-release), 287 bytes

N=int(input())
K=range(N)
G=[[+(i==j==N//2)for j in K]for i in K]
F=lambda:print('\n'.join(' '.join(str(c)for c in r)for r in G)+'\n')
F()
for _ in K:G=[[-~G[i][j]%6*(0<sum(-1<I<N and-1<J<N and G[I][J]>0for J in[j-1,j,j+1]for I in[i-1,i,i+1])<5+5*(not G[i][j]))for j in K]for i in K];F()

Try it online!

This is the version with a nice, tidy output method.

Explanation

Take integer as input (call it N) representing the size of the grid.

Make a variable for its range, to save bytes. (The range is used quite a few times.)

Set up the grid by placing 1 in the center (the row and column are N//2) and 0 in all other places.

Make a function to print the grid.

Print the grid.

Change the grid N times, by changing the element at i, j to -~G[i][j]%6 (one plus the existing one, modulo 6: the modulo 6 ensures that 5 becomes 6%6 = 0) if there is at least one live element in its neighborhood (which includes itself; if no live elements are in the area, it cannot come alive) and at most 5 live elements if that element is itself live (this is the part which kills overcrowded elements), and 10 live elements if that element is dead (it doesn't matter how overcrowded the element is, because if there is at least one live element around it, which is not itself as it is dead, it comes alive regardless). If those conditions are not satisfied, set it to zero. Then print the grid at each iteration.

"the first grid is not an evolution"

Python 3.8 (pre-release), 270 bytes

N=int(input())
K=range(N)
G=[[+(i==j==N//2)for j in K]for i in K]
for _ in K:G=[[-~G[i][j]%6*(0<sum(-1<I<N and-1<J<N and G[I][J]>0for J in[j-1,j,j+1]for I in[i-1,i,i+1])<5+5*(not G[i][j]))for j in K]for i in K];print('\n'.join(' '.join(str(c)for c in r)for r in G)+'\n')

Try it online!

At present, I am not sure if the first grid is an evolution, but just in case, I have provided both versions. (The statement that the first grid is not an evolution conflicts with the test case output.)

\$\endgroup\$
2
  • 2
    \$\begingroup\$ F=lambda:[print(*r)for r in G+['']] saves some bytes \$\endgroup\$
    – ovs
    Jan 20, 2022 at 10:58
  • \$\begingroup\$ @ovs thanks. I don't wanna waste time updating both versions, so I'll wait for the OP's input as to whether the first grid is an evolution before applying your suggestion. Nice catch though! \$\endgroup\$
    – ophact
    Jan 20, 2022 at 10:59
2
\$\begingroup\$

05AB1E, 55 54 52 bytes

δ‚·<QPIƒD»,¶?0δ.ø¬0*šĆ2Fø€ü3}εε˜DÅsD>I>%Š_iOĀ*ëĀO5‹*

Formats by joining each row with a space-delimiter and then all lines with a newline-delimiter. The output can therefore be a bit wonky if it contains any multi-digit integers (for inputs \$n\geq17\$).
The D»,¶? could have been = (-4 bytes) without the strict output format, by just outputting the matrices as is (without popping).

Try it online or verify all test cases below 10.

Explanation:

Step 1: Using the input \$n\$, create an \$n\times n\$ matrix of \$0\$s with a \$1\$ in the center:

δ                   # Apply double-vectorized:
                    # (which implicitly converts the implicit input-integer to
                    # the range [1,input] first, used twice)
 ‚                  #  Pair them together
  ·                 # Double each inner integer
   <                # Decrease each by 1
    Q               # Check for each value if it's equal to the (implicit) input
     P              # Get the product of each inner pair

Try just step 1 online.

Step 2: Loop \$n+1\$ amount of times, and pretty-print the matrix at the start of each iteration:

Iƒ                  # Loop the input+1 amount of times:
  D                 #  Duplicate the current matrix
   »                #  Join each inner list by spaces,
                    #  and then each string by newlines
    ,               #  Pop and print it with trailing newline
     ¶?             #  Print an additional empty line

Try steps 1 & 2 online.

Step 3a: Surround the entire matrix with a ring of 0s:

   δ                #  Map over each row:
  0 .ø              #   Surround it with a leading/trailing 0
      ¬             #  Push the first row (without popping the matrix)
       0*           #  Convert all its values to 0
         š          #  Prepend this list to the matrix
          Ć         #  Enclose; append its first row

Step 3b: And then get all overlapping 3x3 blocks. Each of these 3x3 blocks will have the current value at the center, and its 8 neighbors around it.

  2F                #  Loop 2 times:
    ø               #   Zip/transpose; swapping rows/columns
     €              #   Map over each row:
      ü3            #    Create overlapping triplets of this row
   }                #  Close the loop

Try steps 1 & 3 online.

Step 4: Based on these 3x3 blocks, determine the next value for the cell:

εε                  #  Map over each inner 3x3 block:
  ˜                 #    Flatten it to a single list of 9 values
   D                #    Duplicate this list
    Ås              #    Pop and push the middle cell value
      D             #    Duplicate this middle value
       >            #    Increase it by 1
        I>%         #    Modulo the (input+1)
           Š        #    Triple-swap list,middle,middle+1 to middle+1,list,middle
            _i      #    If the middle cell is 0:
              O     #     Sum its neighbors together
               Ā    #     Check if this is not 0 (0 if 0; 1 otherwise)
                *   #     Multiply this by the middle+1
             ë      #    Else:
              Ā     #     Check for each value that it's NOT 0
               O    #     Sum to get the amount of filled cells, including itself
                5‹  #     Check if this is smaller than 5,
                    #     so there are not 4 or more filled neighbors
                  * #     Multiply this by the middle+1
\$\endgroup\$
1
\$\begingroup\$

J, 62 bytes

<@>:_&(](-~&*+(5>])*[+0<[)[:+/(>,{;~i:1)|.!.0*@])[:*/~<.@-:=i.

Try it online!

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

Python 2, 214 bytes

E=enumerate
n=input()
g=eval(`[[0]*n]*n`)
g[n/2][n/2]=1
exec'print("%d "*n+"\\n")*n%tuple(sum(g,[]));g=[[(0<sum(e>0for q in g[y+y%~y:y+2]for e in q[x+x%~x:x+2])<5+4*0**v)*-~v%6for x,v in E(r)]for y,r in E(g)];'*-~n

Attempt This Online!

Because of the fixed output format switching to Python 3 could actually save a few bytes here: ATO

The most interesting part of this program is the following expression:

(0<sum(e>0for q in g[y+y%~y:y+2]for e in q[x+x%~x:x+2])<5+4*0**v)*-~v%6

Given the previous state in g, the indices of a cell y, x and the value of that cell v, this generates the next state of that cell. To select three rows of g centered on y the slice g[y-1:y+2]. This works if y is not on the boundaries of g or if y == n-1. For y == 0 the slice would start at the end of g, which is not what we want. To adjust for that we can use y-(y>0) instead, but y+y%~y is a shorter expression that achieves the same.

In conclusion [e for q in g[y+y%~y:y+2]for e in q[x+x%~x:x+2]] lists all values in a truncated 3x3 block centered on y, x. We then count the non-zero values and check for overpopulation if v>0.

\$\endgroup\$
0
\$\begingroup\$

Charcoal, 74 bytes

Nθ≔EθEθ⁰η§≔§η⊘θ⊘θ¹F⊕θ«Eη⪫κωFθFθ«Jλκ§≔§ηκλ∧›5KK⎇ΣKK∧›⁴LΦKMΣμ⊕KK‹0⌈KM»UE¹D⎚D

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

Nθ

Input n.

≔EθEθ⁰η§≔§η⊘θ⊘θ¹

Create an n×n matrix whose centre element is 1.

F⊕θ«

Loop n+1 times, because we output the position first.

Eη⪫κω

Output the current position to the canvas.

FθFθ«Jλκ

Loop over each cell.

§≔§ηκλ∧›5KK⎇ΣKK∧›⁴LΦKMΣμ⊕KK‹0⌈KM

If the current cell is less than 5, then if it is a 0 then set it to 1 if it has any neighbours, otherwise increment it if it has fewer than 4 neighbours. Otherwise, set it to 0.

»UE¹D⎚D

Output the canvas neatly. (D⎚ would work but the output would be much less readable.)

\$\endgroup\$

Your Answer

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

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