La vie peut être colorée!

30

Chaque cellule d'un automate cellulaire réaliste n'a besoin que d'un bit pour la représenter car elle ne peut être vivante ou morte. Cela signifie qu'il n'y a que deux couleurs; Plutôt ennuyeux.

Les images normales ont 24 bits par pixel (8 dans chaque RVB). Cela signifie que dans une image normale avec des pixels comme cellules, vous pouvez simuler 24 jeux réalistes à la fois!

Défi

Votre tâche consiste à écrire un programme qui appliquera une génération des règles d'un automate cellulaire réaliste à une image de profondeur 24 bits (dans n'importe quel format bien connu que vous aimez), et à sortir l'image résultante.

Chacune des 24 couches utilisera le même ensemble de règles réaliste, strictement dans sa propre couche. Les 24 couches n'interagissent pas entre elles.

Également

  • Les zéros sont des cellules mortes et les uns sont des cellules vivantes.
  • Les conditions aux limites sont périodiques (formant un tore).
  • Toutes les dimensions de l'image devraient fonctionner.

Entrée sortie

Votre programme doit accepter 3 arguments, via stdin ou la ligne de commande (ou l'équivalent le plus proche de votre langue):

  1. Nom du fichier image d'entrée.
  2. Une chaîne des chiffres 0 à 8 dans l'ordre croissant qui indique la naissance de nouvelles cellules:
    • Si le chiffre d est dans la chaîne, les cellules mortes s'animent lorsqu'elles ont d voisins vivants.
    • Exemple: 3la vie est normale - les cellules mortes avec exactement 3 voisins vivants prennent vie.
  3. Une chaîne des chiffres 0 à 8 dans l'ordre croissant qui indique quand les cellules existantes survivent:
    • Si le chiffre d est dans la chaîne, les cellules vivantes avec d voisins vivants survivent jusqu'à la génération suivante, sinon elles meurent.
    • Exemple: 23la vie est normale - seules les cellules avec exactement 2 ou 3 voisins survivent au tour suivant.

Notez que le quartier Moore est toujours utilisé. Lisez ceci ou cela pour plus d'informations sur ce qui définit précisément un automate réaliste et de nombreux jeux de règles intéressants.

L'image de sortie 1 génération plus tard doit être affichée ou enregistrée sous out.png(ou bmpou autre).

Soumission

Le code le plus court en octets gagne.

Vous devez inclure au moins une image de test et de ses trois générations suivantes immédiates pour certains ruleset non trivial. Utilisez votre avatar et les règles de vie normales si vous ne trouvez rien de mieux.

Si vous le souhaitez, vous pouvez utiliser ce Gosper Glider Gun où les seuls bits vivants sont dans la couche verte 128 (il ne fonctionne que dans la vie normale):

pistolet planeur

La publication de séquences intéressantes ou même d'animations est fortement encouragée.

Poignée de porte
la source
1
Je pense que c'est un doublon - les seules nouvelles parties lisent à partir d'un autre format de fichier et divisent les couches - les deux sont basiques et ne représentent pas un défi en soi.
Howard
1
@Howard Mais n'êtes-vous pas intéressé à voir les images?
3
Ouais. PPCG.SE est un lieu de douleur et d'agonie, pas d' images amusantes et jolies . S'il fait de l'idée de bonus une exigence, alors la question doit être suffisamment originale?
Flonk
3
L'intérêt clair de la communauté est que les programmes ne soient pas copiés-collés avec des changements mineurs par rapport aux réponses à d'autres questions. Ce site ne fonctionne pas sur la base de "Je pense que cela pourrait être amusant, donc ça va". C'est 4chan.
Peter Taylor
4
@Howard, je ne pense plus que cela compte comme un doublon. Certes, si codegolf.stackexchange.com/questions/34505/simulate-rule-110 et codegolf.stackexchange.com/questions/4370/… peuvent coexister, ce n'est pas du tout un doublon.
Calvin's Hobbies

Réponses:

16

MATLAB: 275

Mon préféré des paramètres que j'ai essayé est 45678, 568qui , après un résultat de désintégration progressive dans un ciel d'étoiles scintillantes. Cette image représente «la désintégration de la persistance de la mémoire».

Code de production de gif non golfé (accepte PNG sans 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

Code golfé qui accepte un nom de fichier complet (qui peut être GIF, JPEG et peut-être d'autres choses) et écrit dans 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')

Un fait précédemment découvert est que les paramètres 12, 1peuvent être utilisés pour générer un tapis comme Sierpinski fractale. En voici un avec un point de départ placé au hasard dans chaque bit:

feersum
la source
14

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

Je saisis les invites de chaîne dans l'ordre (1) les règles de naissance, (2) les règles de survie, (3) le nom du fichier, et j'affiche le résultat directement dans Mathematica.

Cela devrait être en mesure de traiter les formats les plus populaires, tant que le fichier a une profondeur de 24 bits.

Voici une version quelque peu non golfée:

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

Voici deux exemples utilisant l'avatar de Rainbolt :

Rainbolt

20 générations utilisant le Game of Life standard [3,23]:

entrez la description de l'image ici

20 générations utilisant [456,34567]:

entrez la description de l'image ici

Et voici un GIF des 200 premières générations de cette dernière règle. Le GIF saute toutes les trois images, car je ne pourrais pas le compresser en dessous de 2 Mo autrement:

entrez la description de l'image ici

Martin Ender
la source
2
quelle règle intéressante
fier haskeller
10

Python 2, 427

Pour ceux qui n'ont pas 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')

Il demande le nom de fichier, puis les cas de naissance, puis les cas de survie. Donc, pour les règles de vie normales, vous pouvez entrer test.bmp, alors 3, alors 23(pas de guillemets ou quoi que ce soit nécessaire).

J'ai utilisé le formatage de chaînes pour indexer et recombiner les bits de couleur, bien que je crains que ce ne soit probablement pas optimal.

Notez que c'est assez lent.

Exemple

Haute vie et grand mélange d'art, non? (Règle 36/ 23.)

Mona Lisa Original génération 1 Original / Génération 1

génération 2 génération 3 Génération 2 / Génération 3

Les passe-temps de Calvin
la source
6

Java, 1085 octets

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"));}}

Exemples (règle 368/245):

Gen 0:

entrez la description de l'image ici

Gen 1:

entrez la description de l'image ici

Gen 2:

entrez la description de l'image ici

Gen 3:

entrez la description de l'image ici

Gen 4:

entrez la description de l'image ici

SuperJedi224
la source