Quick and Dirty Conway's Game of Life



A single class Java ASCI implementation of Conway's Game of Life. Speed coding challenge.

Just a Quick Experiment

I haven't implemented Conway's Game of Life before and feel it's about time now.

This is not going to be great code or revolutionary in any way. Rather I'll code it as quickly as I can (ended up taking about 20-30min).

I've recently made some new life of my own. My daughter is asleep. But not for long. Time is of the essence!

The Code

package tech.olof.gameoflife;

import java.util.ArrayList;
import java.util.List;

public class World {
    // ========== STATIC SECTION ==========

    public static void main(String[] args) {
        run();
    }

    public static void run() {
        int width = 100;
        int height = 20;
        double density = 0.3;
        int millis = 500;
        run(width, height, density, millis);
    }

    public static void run(int width, int height, double density, int sleepMillis) {
        World world = new World(width, height);
        world.randomizeAll(density);
        while (true) {
            System.out.println("=============================");
            world = world.getNextWorld();
            world.print();
            sleep(sleepMillis);
        }
    }

    private static void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    // ========== OBJECT ORIENTED SECTION ==========

    private final int width;
    private final int height;
    private final boolean[] pixels;

    public World(int width, int height) {
        this.width = width;
        this.height = height;
        this.pixels = new boolean[width * height];
    }

    private int getIndex(int x, int y) {
        if (x < 0 || y < 0 || x >= width | y >= height) {
            return -1;
        }
        return width * y + x;
    }

    public boolean getPixel(int x, int y) {
        int index = getIndex(x, y);
        if (index >= 0) {
            return pixels[index];
        } else {
            return false;
        }
    }

    public void setPixel(int x, int y, boolean pixel) {
        int index = getIndex(x, y);
        if (index >= 0) {
            pixels[index] = pixel;
        }
    }

    public void randomize(int x, int y, double density) {
        boolean pixel = Math.random() < density;
        setPixel(x, y, pixel);
    }

    public void randomizeAll(double density) {
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                randomize(x, y, density);
            }
        }
    }

    public String renderLine(int y) {
        StringBuilder stringBuilder = new StringBuilder(width);
        for (int x = 0; x < width; x++) {
            char c = (getPixel(x, y) ? '#' : ' ');
            stringBuilder.append(c);
        }
        return stringBuilder.toString();
    }

    public List<String> renderLines() {
        List<String> lines = new ArrayList<>(height);
        for (int y = 0; y < height; y++) {
            String line = renderLine(y);
            lines.add(line);
        }
        return lines;
    }

    public void print() {
        renderLines()
                .forEach(System.out::println);
    }

    public int getSurrounding(int x, int y) {
        int surrounding = 0;
        for (int y1 = y - 1; y1 <= y + 1; y1++) {
            for (int x1 = x - 1; x1 <= x + 1; x1++) {
                if (!(x == x1 && y == y1) && getPixel(x1, y1)) {
                    surrounding++;
                }
            }
        }
        return surrounding;
    }

    // https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life#Rules
    public static boolean getNextPixel(boolean currentPixel, int surrounding) {
        if (currentPixel) {
            // Currently Alive
            if (surrounding == 2 || surrounding == 3 ) {
                return true;
            }
        } else {
            // Currently Dead
            if (surrounding == 3) {
                return true;
            }
        }
        return false;
    }

    public World getNextWorld() {
        World next = new World(width, height);
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                boolean currentPixel = getPixel(x, y);
                int surrounding = getSurrounding(x, y);
                boolean nextPixel = getNextPixel(currentPixel, surrounding);
                next.setPixel(x, y, nextPixel);
            }
        }
        return next;
    }
}

Example Output

                                                                                                    
      ##       ##                                                               ##                  
      # #      ##                                                                 #                 
        ##           #                 ##              ###                     #  #                 
       ##           # #                ##         ###     #    ##                #                  
    # ##            ##  ##                        #  #     #  # ##                #                 
     ##                 ##      ##          ##     #  ##  ###   #                 ##  #             
  ####                         #  #         ##    #         # #                  #  #    ###        
 # #                    #       #  #            ##     ### ## # #                 #                 
  ##                        # ###   #          #   #   ###     #   #      ###     ##              # 
                             # ###  #          ## ## #  #      #          ###           #   #    # #
                         #  #    #  #             ## #### #####  # #         #                    ##
                         #  # #####            ###    ## #  ###                          # #        
                         ## ##                #       ## #     #          ##      ##      #         
                          ###                #####    ## #   #        ###  #     # #          ##    
                           #               ## ##      ##       #          #    ##           ##  #   
                    ##                       #        #  # # ##                ##         ## # ##   
               ##  #  #                                ##   ###             ## #         #     #    
               ##   # #            ##                                       ####         # # ##     
                     #             ##                                          #          ####