Code Golf: Conway's Game of Life

2019-01-10 00:11发布

The Challenge: Write the shortest program that implements John H. Conway's Game of Life cellular automaton. [link]

EDIT: After about a week of competition, I have selected a victor: pdehaan, for managing to beat the Matlab solution by one character with perl.

For those who haven't heard of Game of Life, you take a grid (ideally infinite) of square cells. Cells can be alive (filled) or dead (empty). We determine which cells are alive in the next step of time by applying the following rules:

  1. Any live cell with fewer than two live neighbours dies, as if caused by under-population.
  2. Any live cell with more than three live neighbours dies, as if by overcrowding.
  3. Any live cell with two or three live neighbours lives on to the next generation.
  4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.

Your program will read in a 40x80 character ASCII text file specified as a command-line argument, as well as the number of iterations (N) to perform. Finally, it will output to an ASCII file out.txt the state of the system after N iterations.

Here is an example run with relevant files:

in.txt:

................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
..................................XX............................................
..................................X.............................................
.......................................X........................................
................................XXXXXX.X........................................
................................X...............................................
.................................XX.XX...XX.....................................
..................................X.X....X.X....................................
..................................X.X......X....................................
...................................X.......XX...................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................

Iterate 100 times:

Q:\>life in.txt 100

Resultant Output (out.txt)

................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
..................................XX............................................
..................................X.X...........................................
....................................X...........................................
................................XXXXX.XX........................................
................................X.....X.........................................
.................................XX.XX...XX.....................................
..................................X.X....X.X....................................
..................................X.X......X....................................
...................................X.......XX...................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................

The Rules:

  • You need to use file I/O to read/write the files.
  • You need to accept an input file and the number of iterations as arguments
  • You need to generate out.txt (overwrite if it exists) in the specified format
  • You don't need to deal with the edges of the board (wraparound, infinite grids .etc)
  • EDIT: You do need to have newlines in your output file.

The winner will be determined by character count.

Good luck!

24条回答
何必那么认真
2楼-- · 2019-01-10 00:40

Another Java attempt, 361 chars

class L{public static void main(final String[]a)throws Exception{new java.io.RandomAccessFile("out.txt","rw"){{int e=88,p[]={-1,1,-80,80,-81,81,-82,82},s=3240,l=0,i=new Byte(a[1])*s+s,c;char[]b=new char[s];for(new java.io.FileReader(a[0]).read(b);i>0;seek(l=++l%s),i--){c=b[l];for(int n:p)c+=l+n>=0&l+n<s?b[l+n]/e:0;write(c>13?(c==49|(c|1)==91?e:46):10);}}};}}

And a little more readable

class L {
    public static void main(final String[]a) throws Exception {
        new java.io.RandomAccessFile("out.txt","rw"){{
            int e=88, p[]={-1,1,-80,80,-81,81,-82,82},s=3240,l=0,i=new Byte(a[1])*s+s,c;
            char[] b = new char[s];
            for (new java.io.FileReader(a[0]).read(b);i>0;seek(l=++l%s),i--) {
                c=b[l];
                for (int n:p)
                    c+=l+n>=0&l+n<s?b[l+n]/e:0;
                write(c>13?(c==49|(c|1)==91?e:46):10);
            }
        }};
    }
}

Very similar to Molehill’s version. I've tried to use a different FileWriter and to count the cell's neighbors without an additional variable. Unfortunately, RandomAccessFile is a pretty long name and it is required that you pass an file access mode.

查看更多
做个烂人
3楼-- · 2019-01-10 00:42

MATLAB 7.8.0 (R2009a) - 174 171 161 150 138 131 128 124 characters

Function syntax: (124 characters)

Here's the easier-to-read version (with unnecessary newlines and whitespace added for better formatting):

function l(f,N),
  b=char(importdata(f))>46;
  for c=1:N,
    b=~fix(filter2(ones(3),b)-b/2-3);
  end;
  dlmwrite('out.txt',char(b*42+46),'')

And here's how the program is run from the MATLAB Command Window:

l('in.txt',100)

Command syntax: (130 characters)

After a comment about calling functions with a command syntax, I dug a little deeper and found out that MATLAB functions can in fact be invoked with a command-line format (with some restrictions). You learn something new every day!

function l(f,N),
  b=char(importdata(f))>46;
  for c=1:eval(N),
    b=~fix(filter2(ones(3),b)-b/2-3);
  end;
  dlmwrite('out.txt',char(b*42+46),'')

And here's how the program is run from the MATLAB Command Window:

l in.txt 100


Additional Challenge: Tweetable GIF maker - 136 characters

I thought for fun I'd see if I could dump the output to a GIF file instead of a text file, while still keeping the character count below 140 (i.e. "tweetable"). Here's the nicely-formatted code:

function l(f,N),
  b=char(importdata(f))>46;
  k=ones(3);
  for c=1:N+1,
    a(:,:,:,c)=kron(b,k);
    b=~fix(filter2(k,b)-b/2-3);
  end;
  imwrite(~a,'out.gif')

Although IMWRITE is supposed to create a GIF that loops infinitely by default, my GIF is only looping once. Perhaps this is a bug that has been fixed in newer versions of MATLAB. So, to make the animation last longer and make the evolution steps easier to see, I left the frame delay at the default value (which seems to be around half a second). Here's the GIF output using the Gosper Glider Gun pattern:

alt text


Improvements

  • Update 1: Changed the matrix b from a logical (i.e. "boolean") type to a numerical one to get rid of a few conversions.
  • Update 2: Shortened the code for loading the file and used the function MAGIC as a trick to create the convolution kernel in fewer characters.
  • Update 3: Simplified the indexing logic, replaced ~~b+0 with b/42, and replaced 'same' with 's' as an argument to CONV2 (and it surprisingly still worked!).
  • Update 4: I guess I should have searched online first, since Loren from The MathWorks blogged about golfing and the Game of Life earlier this year. I incorporated some of the techniques discussed there, which required me to change b back to a logical matrix.
  • Update 5: A comment from Aslak Grinsted on the above mentioned blog post suggests an even shorter algorithm for both the logic and performing the convolution (using the function FILTER2), so I "incorporated" (read "copied") his suggestions. ;)
  • Update 6: Trimmed two characters from the initialization of b and reworked the logic in the loop to save 1 additional character.
  • Update 7: Eric Sampson pointed out in an e-mail that I could replace cell2mat with char, saving 4 characters. Thanks Eric!
查看更多
Bombasti
4楼-- · 2019-01-10 00:43

Mathematica - 179 163 154 151 chars

    a = {2, 2, 2};
    s = Export["out.txt", 
       CellularAutomaton[{224, {2, {a, {2, 1, 2}, a}}, {1,1}}, 
                (ReadList[#1, Byte, RecordLists → 2>1] - 46)/ 42, #2]〚#2〛
       /. {0 → ".", 1 → "X"}, "Table"] &
Spaces added for readability

Invoke with

    s["c:\life.txt", 100]

Animation:

alt text

You can also get a graph of the mean population over time:

alt text

A nice pattern for generating gliders from Wikipedia

aa

AFAIK Mathematica uses a Cellular Automaton to generate random numbers using Rule 30.

查看更多
Rolldiameter
5楼-- · 2019-01-10 00:43

Ruby 1.8: 178 175 chars

f,n=$*;b=IO.read f
n.to_i.times{s=b.dup
s.size.times{|i|t=([82,1,-80].map{|o|b[i-o,3]||''}*'').count 'X'
s[i]=t==3||b[i]-t==?T??X:?.if s[i]>13};b=s}
File.new('out.txt','w')<<b

Newlines are significant (although all can be replaced w/ semicolons.)

Edit: fixed the newline issue, and trimmed 3 chars.

查看更多
再贱就再见
6楼-- · 2019-01-10 00:43

Java, 556 532 517 496 472 433 428 420 418 381 chars


  • Update 1: replaced 1st StringBuffer by Appendable and 2nd by char[]. Saved 24 chars.

  • Update 2: found a shorter way to read file into char[]. Saved 15 chars.

  • Update 3: replaced one if/else by ?: and merged char[] and int declarations. Saved 21 chars.

  • Update 4: replaced (int)f.length() and c.length by s. Saved 24 chars.

  • Update 5: made improvements as per hints of Molehill. Major one was hardcoding the char length so that I could get rid of File. Saved 39 chars.

  • Update 6: minor refactoring. Saved 6 chars.

  • Update 7: replaced Integer#valueOf() by new Integer() and refactored for loop. Saved 8 chars.

  • Update 8: Improved neighbour calculation. Saved 2 chars.

  • Update 9: Optimized file reading since file length is already hardcoded. Saved 37 chars.


 import java.io.*;class L{public static void main(String[]a)throws Exception{int i=new Integer(a[1]),j,l,s=3240;int[]p={-82,-81,-80,-1,1,80,81,82};char[]o,c=new char[s];for(new FileReader(a[0]).read(c);i-->0;c=o)for(o=new char[j=s];j-->0;){l=0;for(int n:p)l+=n+j>-1&n+j<s?c[n+j]/88:0;o[j]=c[j]>13?l==3|l+c[j]==90?88:'.':10;}Writer w=new FileWriter("out.txt");w.write(c);w.close();}}

More readable version:

import java.io.*;
class L{
 public static void main(String[]a)throws Exception{
  int i=new Integer(a[1]),j,l,s=3240;
  int[]p={-82,-81,-80,-1,1,80,81,82};
  char[]o,c=new char[s];
  for(new FileReader(a[0]).read(c);i-->0;c=o)for(o=new char[j=s];j-->0;){
   l=0;for(int n:p)l+=n+j>-1&n+j<s?c[n+j]/88:0;
   o[j]=c[j]>10?l==3|l+c[j]==90?88:'.':10;
  }
  Writer w=new FileWriter("out.txt");w.write(c);w.close();
 }
}

Closing after writing is absoletely mandatory, else the file is left empty. It would otherwise have saved another 21 chars.

Further I could also save one more char when I use 46 instead of '.', but both javac and Eclipse jerks with a compilation error Possible loss of precision. Weird stuff.


Note: this expects an input file with \n newlines, not \r\n as Windows by default uses!

查看更多
Evening l夕情丶
7楼-- · 2019-01-10 00:45

R 340 chars

cgc<-function(i="in.txt",x=100){
    require(simecol)
    z<-file("in.txt", "rb")
    y<-matrix(data=NA,nrow=40,ncol=80)
    for(i in seq(40)){
        for(j in seq(80)){
            y[i,j]<-ifelse(readChar(z,1) == "X",1,0)
        }
        readChar(z,3)
    }
    close(z)
    init(conway) <- y
    times(conway)<-1:x
    o<-as.data.frame(out(sim(conway))[[100]])
    write.table(o, "out.txt", sep="", row.names=FALSE, col.names=FALSE)
}
cgc()

I feel it's slightly cheating to have an add in package that does the actual automata for you, but I'm going with it cos I still had to thrash around with matricies and stuff to read in the file with 'X' instead of 1.

This is my first 'code golf', interesting....

查看更多
登录 后发表回答