10
\$\begingroup\$

What is elementary cellular automata?

Since I'm not sure I'll be able to explain this so that somebody who has never heard of this is able to understand, I'm giving an explanation from https://mathworld.wolfram.com/ElementaryCellularAutomaton.html

Elementary cellular automata have two possible values for each cell (0 or 1), and rules that depend only on nearest neighbor values. As a result, the evolution of an elementary cellular automaton can completely be described by a table specifying the state a given cell will have in the next generation based on the value of the cell to its left, the value the cell itself, and the value of the cell to its right. Since there are 2×2×2=2^3=8 possible binary states for the three cells neighboring a given cell, there are a total of 2^8=256 elementary cellular automata, each of which can be indexed with an 8-bit binary number. For example, the table giving the evolution of rule 30 (30=00011110_2) is illustrated above. In this diagram, the possible values of the three neighboring cells are shown in the top row of each panel, and the resulting value the central cell takes in the next generation is shown below in the center. Rule 30

The evolution of a one-dimensional cellular automaton can be illustrated by starting with the initial state (generation zero) in the first row, the first generation on the second row, and so on. For example, the figure bellow illustrated the first 20 generations of the rule 30 elementary cellular automaton starting with a single black cell. Rule 30 evolution

The task

Given a ruleset n, where n is positive and less than 256, produce an image like the one above, with 15 generations (+1 starting gen-0) and 2 colors of your choice. The starting gen-0 is one active cell in the center, like in the image above. You can choose to start from the bottom and work upwards.

Input

You can take input either as a:

  • Binary number (for example, rule 30 would be 00011110 or the reverse 01111000)
  • Decimal number (rule 30 would be 30)

You cannot take images from external resources, the image should made from scratch by your program.

Output

Your output should be a 31x16 image, with each row representing a separate generation. Generations should not be given in a mixed order.

Submissions

Your submission should always contain the following:

  1. Your code
  2. An image produced by your program, representing a ruleset of your liking. Standard loopholes apply. Your program should work for any n in the range [0,256).

Scoring is done by byte count

EDIT

As requested, adding some test cases specifically for edge handling.

rule 222: rule 222

rule 201: rule 201

rule 162: rule 162

rule 16: rule 16

\$\endgroup\$
7
  • \$\begingroup\$ @newbie there we go, fixed link) \$\endgroup\$
    – Dion
    Commented Apr 12, 2020 at 8:41
  • 5
    \$\begingroup\$ You are asking for a very specific thing with little room for creativity (you even specified the exact dimensions), why popularity-contest? Is this "Do X creatively" with a restriction that you may not be creative at pretty much anything? \$\endgroup\$ Commented Apr 12, 2020 at 10:19
  • \$\begingroup\$ yep, changed it \$\endgroup\$
    – Dion
    Commented Apr 12, 2020 at 10:53
  • \$\begingroup\$ I edited out the "scoring is by votes" since this is tagged code golf. \$\endgroup\$
    – xnor
    Commented Apr 12, 2020 at 11:02
  • 4
    \$\begingroup\$ It seems like many current solutions don't handle the edge condition correctly. For example, this Python answer assumes that each row is padded with 0 on both side, which is not true for odd rules. I suggest adding the test case 243, and maybe clarify in the specification how to deal with such edge cases. \$\endgroup\$ Commented Apr 13, 2020 at 0:26

8 Answers 8

9
\$\begingroup\$

Python 2, 178 167 ... 128 bytes

-13 bytes thanks to @Surculose Sputum!

-2 bytes thanks to @dingledooper!

thanks @Surculose Sputum again for saving some bytes and fixing the boundary bug!!!!

n=input()
print'P1 31 16'
c='%061d'%10**30
exec"print' '.join(c[15:46]);c='0'+''.join(n[int(c[u:u+3],2)]for u in range(60));"*16

Try it online!

Output a 31x16 pbm image in stdout. You might need a magnifying glass to see those tinnie images though.

'01111000' => 30 (30 in reverse)
'01011000' => 26 (26 in reverse)

\$\endgroup\$
8
  • \$\begingroup\$ Those screenshots appear to be offset by 1 from your (presumably correct) program output. \$\endgroup\$
    – Neil
    Commented Apr 12, 2020 at 10:54
  • \$\begingroup\$ Yeah, seems the pbm format is a little bit different from the ppm one. @Neil Fixed, thanks. \$\endgroup\$
    – newbie
    Commented Apr 12, 2020 at 11:00
  • 1
    \$\begingroup\$ I'm not sure, but the image viewer in my computer refuses to work without the dimensions. @Morgen \$\endgroup\$
    – newbie
    Commented Apr 13, 2020 at 0:24
  • 1
    \$\begingroup\$ Would it be shorter if we just pad sufficient n[0]s on both sides? @SurculoseSputum \$\endgroup\$
    – newbie
    Commented Apr 13, 2020 at 1:38
  • 1
    \$\begingroup\$ @newbie Yep! 128 bytes. I start with a row of length 61, which make sure that after 15 iterations, the middle 31 pixels are still correct. (Each iteration loses 2 correct pixel on both end). 1 more golf added: only pad the left side, since c[u:u+3] works even when u+3 is out of bound. \$\endgroup\$ Commented Apr 13, 2020 at 1:53
8
\$\begingroup\$

Wolfram Language (Mathematica), 42 bytes

¯\_(ツ)_/¯

Image@CellularAutomaton[#,{{1},0},15]&    

n=30

enter image description here

n=26

enter image description here

Since this challenged changed to gode-golf I applied the changes that @Dan the Man proposed and saved some bytes.
The images now should have inverted colors

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Does this produce a correctly-sized image for rules that don't grow at light speed in both directions? \$\endgroup\$ Commented Apr 12, 2020 at 10:27
  • 1
    \$\begingroup\$ @mypronounismonicareinstate No, it does not; this is actually talked about in the Possible Issues section in documentation. Instead of 15 it should be {15,All}. Additionally, several bytes can be saved by replacing ArrayPlot with Image and using @ (prefix notation) rather than brackets. \$\endgroup\$
    – DanTheMan
    Commented Apr 12, 2020 at 19:12
  • \$\begingroup\$ @DanTheMan when I posted this answer, this quuestion was not a code-golf one. Now that it changed I will apply your changes. Thanks for golfing it! \$\endgroup\$
    – ZaMoC
    Commented Apr 13, 2020 at 14:27
5
\$\begingroup\$

Sledgehammer, 24 19 bytes

(alternatively, 18.625)
Obtained from the Wolfram code ExportString[ArrayPlot[CellularAutomaton[Input[], {{1}, 0}, {15, All}]], "SVG"].

Outputs via (as you could easily tell) SVG. The ExportString part can be dropped, but then it will output a Graphics object - it's basically an image, but it's hard to view without loading it into Mathematica or exporting it via Export/ExportString.

⣕⢼⡔⡼⣂⡏⢂⠌⢤⡾⣧⣾⢴⠮⣯⠴⢒⣈⣱
\$\endgroup\$
4
\$\begingroup\$

05AB1E, 57 bytes

"P1 31 16",¾16иJD"ÿ1ÿ"16E©D¦¨Sðý,31Lε<®s.$3£C7αIsè}J"0ÿ0"

a (bad) port of this python answer

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ 47 bytes. Although I don't think your current port (nor my shorter one) is a correct port of the Python answer.. If I use the inputs 11100001 (225) or 11110011 (243) I get a different output than the output of the Python TIO. \$\endgroup\$ Commented Apr 14, 2020 at 9:57
  • 1
    \$\begingroup\$ The issue is you are padding with zeros on the left and right, if I am understanding your code. This technique only works for even rules. \$\endgroup\$
    – Wheat Wizard
    Commented May 5, 2020 at 16:48
3
\$\begingroup\$

Haskell, 175 158 154 bytes

t=take 16
f=t$0:f
(a:b)!s=s<$>p(a:a:b)
p(a:b:c:d)=(4*a+2*b+c):p(b:c:d)
p[a,b]=[4*a+3*b]
m s=putStr"P1 33 16 ">>mapM_ print`mapM_`t(iterate(!(s!!))$f++1:f)

Try it online!

Outputs to a pbm file with white being off and black being on. You can switch the on and off colors at no cost to bytes.

Sample outputs

Rule 30

  • Raw

    enter image description here

  • Increased size

    enter image description here

Rule 121

  • Raw

    enter image description here

  • Increased Size

    enter image description here

\$\endgroup\$
2
  • \$\begingroup\$ Aren't there grayscale PGMs, which should be even simpler to output? (I don't remember the magic number, but it should be easy to find) \$\endgroup\$ Commented May 4, 2020 at 15:09
  • \$\begingroup\$ @mypronounismonicareinstate I had a look ant P1 reduces the size a bit. Not only does it only require 1 number per pixel it also don't require a color depth. \$\endgroup\$
    – Wheat Wizard
    Commented May 4, 2020 at 15:40
3
\$\begingroup\$

MATL, 36 bytes

Thanks to @AdHocGarfHunter for pointing out a mistake, now corrected

l30Ya!15:"GyFTYa3YC!XBQ)]v16:46Z)0YG

Input is binary in reverse order. Output is white for active cell, black for inactive.

Try it at MATL Online!

Explanation

l       % Push 1
30Ya    % Padarray: pads 1 with 30 zeros on each side. Gives a column vector.
        % This large amount of padding is necessary to avoid edge effects in
        % the output
!       % Transpose into a row vector
15:"    % Do the following 15 times
  G     %   Push input
  y     %   Duplicate from below: pushes a copy of the latest row vector
  FTYa  %   Pad with one zero to the left and one to the right
  3YC   %   Matrix of length-3 sliding blocks arranged as columns
  !     %   Transpose. Each block is now a row
  XB    %   Convert each row from binary to a number
  Q     %   Add 1 (this is needed because indexing is 1-based)
  )     %   Index the input with these numbers. This applies the automaton
        %   rule to each length-3 block, producing a new generation
]       % End
v       % Concatenate all row vectors into a matrix
16:46   % Push [16 17 ... 46]: indices of the columns to be kept
Z)      % Use as column indices
0YG     % Write to image file. This is implicitly displayed by MATL Online
\$\endgroup\$
8
  • \$\begingroup\$ This seems to behave strangely for [1 1 0 1 1 1 1 0] \$\endgroup\$
    – Wheat Wizard
    Commented May 4, 2020 at 14:43
  • \$\begingroup\$ @AdHocGarfHunter Thanks. I'll take a look later. Deleting in the meantime \$\endgroup\$
    – Luis Mendo
    Commented May 4, 2020 at 18:34
  • \$\begingroup\$ @AdHocGarfHunter I think it works fine. Did you notice the input is in reverse order? \$\endgroup\$
    – Luis Mendo
    Commented May 4, 2020 at 21:56
  • \$\begingroup\$ I'm not sure how the order can be in reverse. I was noting that it implements the edge conditions improperly. \$\endgroup\$
    – Wheat Wizard
    Commented May 5, 2020 at 0:30
  • \$\begingroup\$ @AdHocGarfHunter I don't follow. Your suggested input seems to give the same output using my code and using this other for example \$\endgroup\$
    – Luis Mendo
    Commented May 5, 2020 at 12:11
2
\$\begingroup\$

Java, 247 bytes

import java.awt.image.*;r->{BufferedImage i=new BufferedImage(31,16,1);int[]p=((DataBufferInt)i.getRaster().getDataBuffer()).getData();p[15]=-1;for(int a=31;a<496;a++)p[a]=r<<31-(p[a==31?0:a-32]<<2&4|p[a-31]<<1&2|p[a==495?0:a-30]&1)>>31;return i;}

repl.it

Before minimizing:

rule -> {
    BufferedImage image  = new BufferedImage(31, 16, BufferedImage.TYPE_INT_RGB);
    int[]         pixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();
    pixels[15]           = -1;
    for (int i = 31; i < 496; i++)
        pixels[i] = rule << 31 - (pixels[Math.max(0, a - 32)] << 2 & 4 | 
                                  pixels[i - 31] << 1 & 2 | 
                                  pixels[i == 495 ? 0 : i - 30] & 1) >> 31;
    return image;
};

Inner magic ungolfed:

BOTTOM_LEFT_PIXEL_WHICH_IS_WRITTEN = 465;
int upLeft  = pixels[Math.max(0, i - 32)];
int up      = pixels[i - 31];
int upRight = pixels[i - 30 == BOTTOM_LEFT_PIXEL_WHICH_IS_WRITTEN ? 0 : i - 30];
int code    = ((upLeft << 2) & 4) | ((up << 1) & 2) | (upRight & 1);
int newBit  = (rule >> code) & 1;
pixels[i] = newBit == 0 ? 0x00000000 : 0xFFFFFFFF;

Notes: The code could be even shorter if the output image was allowed to be 32 pixels wide instead of 31. It could be even shorter if 'active' pixels may be impossibly invisible dark blue (#000001)

It could surely be shorter with pbm output, but I like to see my stuff directly.

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

Python 3, 335 334 bytes

from PIL import Image
from numpy import*
a=zeros((16,31),dtype=uint8)
x,a[0][15]=list(map(int,input())),1
for i in range(1,16):
 a[i][15-i],a[i][15+i]=x[a[i-1][15-i]*2+a[i-1][16-i]],x[a[i-1][14+i]*4+a[i-1][15+i]*2]
 for j in range(16-i,15+i):
  a[i][j]=x[a[i-1][j-1]*4+a[i-1][j]*2+a[i-1][j+1]]
Image.fromarray(a*255,"L").save('1.png')

This is not very golfed, so no need to explain it.

Outputs to 1.png and black for 0, white for 1.

Since Python can't do image processing by itself, the packages pillow and numpy are required.

Input is reversed bits.

\$\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.