31
\$\begingroup\$

Each cell in a life-like cellular automaton only needs one bit to represent it since it can only be alive or dead. That means there are only two colors; pretty boring.

Normal images have 24 bits per pixel (8 in each of R G B). This means in a normal image with pixels as cells you could simulate 24 life-like games at once!

Challenge

Your task is to write a program that will apply one generation of the rules of a life-like cellular automaton to a 24-bit depth image (in any well known format you like), and output the resulting image.

Each of the 24 layers will use the same life-like ruleset, strictly within it's own layer. The 24 layers do not interact with each other.

Also

  • Zeros are dead cells and ones are live cells.
  • Boundary conditions are periodic (forming a torus).
  • Any image dimensions should work.

Input/Output

Your program needs to take in 3 arguments, via stdin or command line (or your language's closest equivalent):

  1. The name of the input image file.
  2. A string of the digits 0 to 8 in increasing order that denotes when new cells are born:
    • If the digit d is in the string then dead cells come alive when they have d living neighbors.
    • Example: 3 is normal Life - Dead cells with exactly 3 living neighbors come to life.
  3. A string of the digits 0 to 8 in increasing order that denotes when existing cells survive:
    • If the digit d is in the string then living cells with d living neighbors survive to the next generation, otherwise they die.
    • Example: 23 is normal Life - Only cells with exactly 2 or 3 neighbors survive to the next round.

Note that the Moore neighborhood is always used. Read this or this for more info on what precisely defines a life-like automaton and many interesting rulesets.

The 1-generation-later output image should either be displayed or saved as out.png (or bmp or whatever).

Submission

The shortest code in bytes wins.

You are required to include at least one test image and its three immediate subsequent generations for some non-trivial ruleset. Use your avatar and the normal Life rules if you can't think of anything better.

If you like you may use this Gosper Glider Gun where the only living bits are in the green 128 layer (it's only sure to work in normal Life):

glider gun

Posting interesting sequences or even animations is highly encouraged.

\$\endgroup\$
18
  • 1
    \$\begingroup\$ I think it is a duplicate - the only new parts are reading in from another file format and splitting the layers - both are basic and no challenge by themselves. \$\endgroup\$
    – Howard
    Aug 27, 2014 at 5:52
  • 1
    \$\begingroup\$ @Howard But aren't you interested in seeing the images? \$\endgroup\$
    – user31074
    Aug 27, 2014 at 7:08
  • 3
    \$\begingroup\$ Yeah. PPCG.SE is a place of pain and agony, not fun and pretty images. If he makes the bonus idea a requirement, then surely the question must be original enough? \$\endgroup\$
    – Flonk
    Aug 27, 2014 at 7:39
  • 3
    \$\begingroup\$ The community's clear interest is that programs not be copy-pasted with minor changes from answers to other questions. This site does not operate on the basis of "I think it might be fun, so it's ok". That's 4chan. \$\endgroup\$ Aug 27, 2014 at 22:26
  • 4
    \$\begingroup\$ @Howard I don't think this counts as a duplicate anymore. Surely if codegolf.stackexchange.com/questions/34505/simulate-rule-110 and codegolf.stackexchange.com/questions/4370/… can coexist then this is not a duplicate at all. \$\endgroup\$ Sep 16, 2014 at 10:03

4 Answers 4

17
\$\begingroup\$

MATLAB: 275

My favorite of the parameters I tried is 45678, 568 which following a gradual disintegration results in a sky of twinkling stars. This image depicts, "the disintegration of the persistence of memory."

Ungolfed gif-producing code (accepts PNG without extension):

B = input('B', 's') - 48;
S = input('S', 's') - 48;
f0 = input('file: ', 's');
frames = 60;

f = sprintf('%s.png',f0);
fout = sprintf('%s.gif',f0);
first = 1;
img = imread(f);
for i = 1:60
    out = img * 0;
    [r, c, turd] = size(img);
    for b=0:7
        bimg = ~~bitand(img,2^b);
        pimg = [bimg,bimg,bimg;bimg,bimg,bimg;bimg,bimg,bimg];
        fun = @(ro,co) pimg(r+ro:r+r+ro-1,c+co:c+c+co-1,:);
        sum = fun(0,0)+fun(0,1)+fun(0,2)+fun(1,0)+fun(1,2)+fun(2,0)+fun(2,1)+fun(2,2);
        bnew = uint8(bimg & ismember(sum,S) | ~bimg & ismember(sum, B));
        out = out + 2^b * bnew;
    end
    %imwrite(out,'out.png');
       if first
           [img1,img2] = rgb2ind(img,256);
           imwrite(img1,img2,fout,'gif','Loop',Inf);
          imwrite(img1,img2,fout,'gif','WriteMode','append');
           first = 0;
       end
       img = out;
       [img1,img2] = rgb2ind(img,256);
       imwrite(img1,img2,fout,'gif','WriteMode','append');%,'DelayTime', 2*delay);
end

Golfed code that accepts a full filename (which can be GIF, JPEG, and perhaps other stuff) and writes to out.png:

I=@()input('','s');B=I();S=I();i=imread(I());o=0;[r,c,t]=size(i);for b=0:7
g=~~bitand(i,2^b);p=repmat(g,3);F=@(z,Z)p(r+z:r+r+z-1,c+Z:c+c+Z-1,:);M=@(A)ismember(F(0,0)+F(0,1)+F(0,2)+F(1,0)+F(1,2)+F(2,0)+F(2,1)+F(2,2),A-48);o=o+2^b*uint8(g&M(S)|~g&M(B));end
imwrite(o,'out.png')

A previously discovered fact is that parameters 12, 1 can be used to generate a Sierpinski carpet-like fractal. Here is one with a randomly placed seed point in each bit:

\$\endgroup\$
14
\$\begingroup\$

Mathematica, 359

i=InputString;f=Transpose;b=(p=FromDigits/@Characters@#&)@i[];s=p@i[];Map[FromDigits[#,2]&/@#~ArrayReshape~{3,8}&,f[(g=#;{#,Total[g~RotateRight~#&/@Drop[Join@@Table[{i,j},{i,-1,1},{j,-1,1}],{5}],1]}~f~{3,1,2}/.{l_,n_}:>Boole[l<1&&!b~FreeQ~n||l>0&&!s~FreeQ~n])&/@Apply[Join,IntegerDigits[ImageData[Import@i[],y="byte"],2,8],{2}]~f~{2,3,1},{3,1,2}],{2}]~Image~y

I'm taking input from string prompts in the order (1) birth rules, (2) survival rules, (3) file name, and I'm displaying the result right in Mathematica.

This should be able to deal with most popular formats, as long as the file actually has 24-bit depth.

Here is a somewhat ungolfed version:

i = InputString;
f = Transpose;
b = (p = FromDigits /@ Characters@# &)@i[];
s = p@i[];
Map[
  FromDigits[#,2] & /@ #~ArrayReshape~{3, 8} &,
  f[
   (
      g = #;
      {#, 
         Total[g~RotateRight~# & /@ 
           Drop[Join @@ Table[{i, j}, {i, -1, 1}, {j, -1, 1}], {5}], 
          1]}~f~{3, 1, 2} /. {l_, n_} :> 
        Boole[l < 1 && ! b~FreeQ~n || l > 0 && ! s~FreeQ~n]
      ) & /@ 
    Apply[Join, 
      IntegerDigits[ImageData[Import@i[], y = "byte"], 2, 8], {2}]~
     f~{2, 3, 1},
   {3, 1, 2}
   ],
  {2}
  ]~Image~y

Here are two examples using Rainbolt's avatar:

Rainbolt

20 generations using the standard Game of Life [3,23]:

enter image description here

20 generations using [456,34567]:

enter image description here

And here is a GIF of the first 200 generations of the latter rule. The GIF skips every third frame, because I couldn't compress it below 2MB otherwise:

enter image description here

\$\endgroup\$
1
  • 2
    \$\begingroup\$ what an interesting rule \$\endgroup\$ Sep 25, 2014 at 23:56
11
\$\begingroup\$

Python 2, 427

For those who don't have Mathematica ;)

import Image as I
t=raw_input
r=range
A=I.open(t())
G=map(int,t())
S=map(int,t())
w,h=A.size
B=I.new('RGB',(w,h))
A=[[map(int,("{:08b}"*3).format(*A.load()[x,y]))for y in r(h)]for x in r(w)]
for x in r(w):
 for y in r(h):
  p=''
  for i in r(24):
    c=A[x][y][i]
    n=sum(A[(x+k-1)%w][(y+j-1)%h][i]for j in r(3)for k in r(3))-c
    p+=str(~~[n in G,n in S][c])
  B.load()[x,y]=tuple(int(p[i*8:i*8+8],2)for i in r(3))
B.save('out.bmp')

It prompts for the filename, then the birth cases, then the survival cases. So for normal life rules you might input test.bmp, then 3, then 23 (no quotes or anything needed).

I used string formatting to index into and recombine the color bits, though I fear that's probably not optimal.

Note that's it's pretty slow.

Example

High life and great art mix right? (Rule 36 / 23.)

Mona Lisa Original generation 1 Original / Generation 1

generation 2 generation 3 Generation 2 / Generation 3

\$\endgroup\$
7
\$\begingroup\$

Java, 1085 bytes

import java.awt.image.*;import java.io.*;import javax.imageio.*;class F{static int n(boolean[][][]a,int x,int y,int z){int k=0;for(X=Math.max(x-1,0);X<Math.min(x+2,w);X++)for(Y=Math.max(y-1,0);Y<Math.min(y+2,h);Y++)if(a[X][Y][z])k++;return k-(a[x][y][z]?1:0);}static int p(String k){return Integer.parseInt(k,2);}static int w,h,x,y,z,X,Y;public static void main(String[]a)throws Exception{BufferedImage i=ImageIO.read(new File(a[0]));w=i.getWidth();h=i.getHeight();boolean[][][]G=new boolean[w][h][24];for(x=0;x<w;x++)for(y=0;y<h;y++){String k="".format("%24s",Integer.toBinaryString(0xFFFFFF&i.getRGB(x,y)));for(z=0;z<24;z++){G[x][y][z]=k.charAt(z)>48;}}for(x=0;x<w;x++)for(y=0;y<h;y++){String r="",g="",b="",k;for(z=0;z<8;){k=""+n(G,x,y,z);r+=(-1!=(G[x][y][z++]?a[1].indexOf(k):a[2].indexOf(k)))?1:0;}for(;z<16;){k=""+n(G,x,y,z);g+=(-1!=(G[x][y][z++]?a[1].indexOf(k):a[2].indexOf(k)))?1:0;}for(;z<24;){k=""+n(G,x,y,z);b+=(-1!=(G[x][y][z++]?a[1].indexOf(k):a[2].indexOf(k)))?1:0;}i.setRGB(x,y,new java.awt.Color(p(r),p(g),p(b)).getRGB());}ImageIO.write(i,"png",new File("out.png"));}}

Examples (rule 368/245):

Gen 0:

enter image description here

Gen 1:

enter image description here

Gen 2:

enter image description here

Gen 3:

enter image description here

Gen 4:

enter image description here

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