Weird nagging bug in game of life variant.

edited January 2016 in Questions about Code

Hi guys, I'm new here, so I hope I'm posting this in the right place. For a while now I've been experimenting with Processing and have been learning a lot about it. Recently I started working on a multiplayer (more than just two states of a cell) and I ran in some weird bugs. When running the code, it randomly seems to function or not function. Sometimes I have to hit the run button about 6 times before I get a rendering that changes over time. Weirdly though, never 2 colors seem to react in 1 game, it is always "one or the other". Am I missing some kind of feature? Maybe you guys could try running it and tell me if you are experiencing the same problem? For the code i've made, i put in 2 3x1 bars in the colors red and yellow. If the program was functioning correctly, these bars should rotate every tick (giving it a frequency of 0.5). This doesn't seem to work on my end. I'm Running a macbook pro 2012 model with processing 2.0.3

Here is my code:

import java.awt.Color;
import java.lang.Integer;

enum State
{
  RED(84, 0, 0),
  GREEN(58, 97, 0),
  YELLOW(222, 148, 0),
  DEAD(255,255,255);

  Color color;

  State(int red, int green, int blue)
  {
    color = new Color(red, green, blue);
  }

  public int getRGB()
  {
    return color.getRGB();
  }

}

This is the Enum class i use in a separate java file.

import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.lang.Integer;
import java.lang.String;

PVector     loc;
PVector     size;
Grid        g;

void setup()
{
    frameRate(1);
    size(400,400);
    background(255);
    g = new Grid(16, 16, 20);
    g.change(1,4, State.RED);
    g.change(2,4, State.RED);
    g.change(3,4, State.RED);
    g.change(3,3, State.RED);
    g.change(2,2, State.RED);
    g.display();
}

void draw()
{
    background(255);
    g.step();
}

/**
 * Grid of Cells that plays game of life
 */
class Grid
{
    PVector     size;
    Cell[][]    grid;
    Cell[][]    nextGrid;

    /**
     * Initializes a grid of width columns and height rows
     */
    Grid(int width, int height, int size)
    {
        this.size = new PVector(width, height);
        grid = new Cell[width][height];
        nextGrid = new Cell[width][height];
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++){
                PVector location = new PVector(x*(size+size/2),y*(size+size/2));
                PVector cellSize = new PVector(size, size);
                grid[x][y] = new Cell(location, cellSize, State.DEAD);
                nextGrid[x][y] = new Cell(location, cellSize, State.DEAD);
            }
        }
    }

    /**
     * Renders the grid to the screen
     */
    public void display()
    {
        for (int x = 0;x < grid.length; x++)
        {
            for (int y = 0; y < grid[0].length; y++)
            {
                grid[x][y].render();
            }
        }
    }

    /**
     * Loops through each cell and decides the next state for it, 
     * then renders it to the screne
     */
    public void step()
    {
        for (int x = 0; x < grid.length; x++) {
            for (int y =0; y < grid[0].length; y++) {
                nextState(x, y);
            }
        }

        for (int x =0; x < grid.length; x++) {
            for (int y=0; y <grid[0].length; y++) {
                nextGrid[x][y].render();
                grid[x][y].setState(nextGrid[x][y].getState());
            }
        }
    }


    /**
     * Decides the next state for the given cell
     * @param x [description]
     * @param y [description]
     */
    private void nextState(int x, int y) {
        State s = grid[x][y].getState();
        Map<State, Integer> n = new HashMap<State, Integer>();
        n.put(State.RED, 0);
        n.put(State.YELLOW, 0);
        n.put(State.GREEN, 0);
        n.put(State.DEAD, 0);

        for (int i = -1; i <= 1; i++) {
            for (int j = -1; j <= 1; j++) {
                if ((this.checkXRange(x+i) && this.checkYRange(y+j)) && !(i == 0 && j ==0)) {
                    State c = grid[x+i][y+j].getState();
                    n.put(c, n.get(c)+1);
                }
            }
        }

        for (State key : n.keySet()) {
            if (key != State.DEAD) {
                int val = n.get(key).intValue();
                if ((val > 3 || val < 2) && s == key) {
                    println("Dies: " + x + ", " + y + " color: " + key);
                    nextGrid[x][y].setState(State.DEAD);
                } else if (s == State.DEAD && val == 3) {
                    println("Born: " + x +", " + y + " color: " + key);
                    nextGrid[x][y].setState(key);
                } else {
                    nextGrid[x][y].setState(s);
                }
            }
        }
    }

    /**
     * checks if int is within possible x values of the grid
     * @param  i [description]
     * @return   [description]
     */
    private boolean checkXRange(int i)
    {
        if (i < 0) {
            return false;
        } else if (i >= grid.length) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * Checks if int is within possible y values of the grid
     * @param  i [description]
     * @return   [description]
     */
    private boolean checkYRange(int i)
    {
        if (i < 0) {
            return false;
        } else if (i >= grid[0].length) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * Changes the state of the cell with the given coordinates
     * @param x [description]
     * @param y [description]
     * @param s [description]
     */
    public void change(int x, int y, State s)
    {
        grid[x][y].setState(s);
    }
}

/**
 * Cell that contains state and rendering information
 */
class Cell
{
    PVector     loc;
    PVector     size;
    State       state;


    /**
     * Initializes the cell on location (x,y) on the processing grid
     */
    Cell(PVector loc, PVector size, State state)
    {
        this.loc = loc;
        this.size = size;
        this.state = state;
    }

    /**
     * Renders the cell onto the processing window
     */
    public void render()
    {
        stroke(70);
        fill(this.state.getRGB());
        rect(loc.x, loc.y, size.x, size.y);
    }

    /**
     * Changes the state of the cell
     * @param s [description]
     */
    public void setState(State s)
    {
        this.state = s;

    }

    /**
     * get the current state of the cell
     * @return [description]
     */
    public State getState()
    {
        return this.state;
    }

}

And this is the code in the sketch file.

I hope you guys can help me out, as this has been nagging me for about 2 weeks now, and i can't seem to find why and where this code seems to break.

Tagged:

Answers

  • edited October 2013

    After many experimentations and heavy modifications, I guess at least made it to work every time consistently! 8-X
    Also, there's no imports anymore nor any separate .java tab. :bz
    Well, check it out:

    /** 
     * Game of Life (v2.10)
     * by  Berend (2013/Oct)
     * mod GoToLoop
     * 
     * forum.processing.org/two/discussion/135/
     * weird-nagging-bug-in-game-of-life-variant-
     */
    
    final Grid pattern = new Grid(16, 16, 20);
    
    void setup() {
      size(471, 471);
      frameRate(1);
      stroke(0120);
      background(-1);
    
      pattern.change(1, 4, State.RED);
      pattern.change(2, 2, State.RED);
      pattern.change(2, 4, State.RED);
      pattern.change(3, 3, State.RED);
      pattern.change(3, 4, State.RED);
    
      pattern.display();
    }
    
    void draw() {
      background(-1);
      pattern.step();
    }
    
    interface State {
      int RED = 0, GREEN = 1, YELLOW = 2, DEAD = 3;
    
      color[] colors = {
        #600000, #406000, #E09000, -1
      };
    }
    
    class Grid implements State {
      final Cell[][] grid, nextGrid;
      final int[] states = new int[colors.length];
    
      Grid(int w, int h, int sz) {
        grid = new Cell[w][h];
        nextGrid = new Cell[w][h];
    
        final PVector location = new PVector();
        final PVector cellSize = new PVector();
    
        for (int x = 0; x != w; x++)   for (int y = 0; y != h; y++) {
          location.set(x*(sz + sz/2), y*(sz + sz/2));
          cellSize.set(sz, sz);
    
          grid[x][y]     = new Cell(location, cellSize, DEAD);
          nextGrid[x][y] = new Cell(location, cellSize, DEAD);
        }
      }
    
      void display() {
        for (int x = grid.length; x-- != 0;) {
          final Cell[] cols = grid[x];
          for (int y = cols.length; y-- != 0; cols[y].render());
        }
      }
    
      void step() {
        for (int x = grid.length; x-- != 0;)
          for (int y = grid[0].length; y-- != 0; nextState(x, y));
    
        for (int x = grid.length; x-- != 0;) {
          final Cell[] cols = grid[x], nextCols = nextGrid[x];
    
          for (int y = cols.length; y-- != 0;) {
            nextCols[y].render();
            cols[y].setState(nextCols[y].getState());
          }
        }
    
        println();
      }
    
      void nextState(int x, int y) {
        final int  s = grid[x][y].getState();
        final Cell c = nextGrid[x][y];
    
        for (int i = states.length; i-- != 0; states[i] = 0);
    
        for (int i = -1; i <= 1; i++)   for (int j = -1; j <= 1; j++)
          if (checkXRange(x + i) && checkYRange(y + j) && (i | j) != 0) {
            final int k = grid[x + i][y + j].getState();
            ++states[k];
          }
    
        for (int k = states.length - 1; k-- != 0;) {
          final int v = states[k];
    
          if (v > DEAD | v < YELLOW && s == k) {
            println("Dies: (" + x + "," + y + ")\t state: " + v);
            c.setState(DEAD);
          }
    
          else if ((v & s) == DEAD) {
            println("Born: (" + x + "," + y + ")\t state: " + v);
            c.setState(k);
          }
    
          else c.setState(s);
        }
      }
    
      boolean checkXRange(int i) {
        return i >= 0 & i < grid.length;
      }
    
      boolean checkYRange(int i) {
        return i >= 0 & i < grid[0].length;
      }
    
      void change(int x, int y, int s) {
        grid[x][y].setState(s);
      }
    }
    
    class Cell implements State {
      final PVector loc = new PVector(), dim = new PVector();
      int state;
    
      Cell(PVector pos, PVector sz, int s) {
        loc.set(pos);
        dim.set(sz);
        state = s;
      }
    
      void render() {
        fill(colors[state]);
        rect(loc.x, loc.y, dim.x, dim.y);
      }
    
      void setState(int s) {
        state = s;
      }
    
      int getState() {
        return state;
      }
    }
    
  • edited October 2013

    It would appear that the problem lies in the nextState method, it appears to calculate the cells being born and the cells to die correctly the problem is setting the colour of the cell.

    Recently I started working on a multiplayer (more than just two states of a cell)

    Is each colour supposed to be a different player? If that is true then

    (1) there are still only 2 states, alive and dead.

    (2) the only difference in the alive cells is who owns them.

    (3) in which case it would be better to use separate attributes in the Cell class for alive/dead (state) and owner.

Sign In or Register to comment.