# 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. 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. 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:

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.

• @newbie there we go, fixed link)
– Dion
Apr 12 '20 at 8:41
• 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? Apr 12 '20 at 10:19
• yep, changed it
– Dion
Apr 12 '20 at 10:53
• I edited out the "scoring is by votes" since this is tagged code golf.
– xnor
Apr 12 '20 at 11:02
• 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. Apr 13 '20 at 0:26

# 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 in reverse)
'01011000' => (26 in reverse)

• Those screenshots appear to be offset by 1 from your (presumably correct) program output.
– Neil
Apr 12 '20 at 10:54
• Yeah, seems the pbm format is a little bit different from the ppm one. @Neil Fixed, thanks. Apr 12 '20 at 11:00
• I'm not sure, but the image viewer in my computer refuses to work without the dimensions. @Morgen Apr 13 '20 at 0:24
• Would it be shorter if we just pad sufficient ns on both sides? @SurculoseSputum Apr 13 '20 at 1:38
• @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. Apr 13 '20 at 1:53

# Wolfram Language (Mathematica), 42 bytes

¯\_(ツ)_/¯

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


n=30

n=26 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

• Does this produce a correctly-sized image for rules that don't grow at light speed in both directions? Apr 12 '20 at 10:27
• @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. Apr 12 '20 at 19:12
• @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! Apr 13 '20 at 14:27

# 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.

⣕⢼⡔⡼⣂⡏⢂⠌⢤⡾⣧⣾⢴⠮⣯⠴⢒⣈⣱


"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! • 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. Apr 14 '20 at 9:57 • 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. May 5 '20 at 16:48 # Haskell, 175158 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_ printmapM_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 121

• 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) May 4 '20 at 15:09
• @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. May 4 '20 at 15:40

# 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

• This seems to behave strangely for [1 1 0 1 1 1 1 0] May 4 '20 at 14:43
• @AdHocGarfHunter Thanks. I'll take a look later. Deleting in the meantime May 4 '20 at 18:34
• @AdHocGarfHunter I think it works fine. Did you notice the input is in reverse order? May 4 '20 at 21:56
• I'm not sure how the order can be in reverse. I was noting that it implements the edge conditions improperly. May 5 '20 at 0:30
• @AdHocGarfHunter I don't follow. Your suggested input seems to give the same output using my code and using this other for example May 5 '20 at 12:11

# Java, 247 bytes

import java.awt.image.*;r->{BufferedImage i=new BufferedImage(31,16,1);int[]p=((DataBufferInt)i.getRaster().getDataBuffer()).getData();p=-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           = -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.