/* Simulator for discrete-space system of repelling particles
 * Copyright 2006 Will Stevens 
 *
 * Usage: comprepel x y <input-file> iterations
 *        where
 *        x = x-offset, y = y-offset
 *        <input-file> contains an initial pattern to be placed at offset (x,y)
 *        iterations = number of iterations to run before producing output
 *
 * Input file consists of lines containing O and X characters to represent
 * moveable and fixed particles. Each character in the file corresponds to
 * a cell in the discrete grid. e.g. a Type 1 Corner:


                      X
                    X
                     O O O O
                   X
                     O

                     O

                     O

 *
 */

#include <stdio.h>
#include <stdlib.h>

const unsigned arraySizeX = 50, arraySizeY = 50;

typedef enum {empty = 0, moveable = 1, fixed = 2} cellState;

cellState array[arraySizeX][arraySizeY][2];

enum {active0 = 0, active1 = 1} active = active0, inactive = active1;

cellState activeArray(int x, int y)
{
  return array[(x+arraySizeX)%arraySizeX][(y+arraySizeY)%arraySizeY][active];
}

void process(void)
{
  for(int x = 0; x<arraySizeX; x++)
  {
    for(int y = 0; y<arraySizeY; y++)
    {
      array[x][y][inactive] = array[x][y][active];

      if (activeArray(x,y) == empty)
      {
        if (activeArray(x-1,y) == moveable && activeArray(x-2,y) != empty)
          array[x][y][inactive] = moveable;

        if (activeArray(x+1,y) == moveable && activeArray(x+2,y) != empty)
          array[x][y][inactive] = moveable;

        if (activeArray(x,y-1) == moveable && activeArray(x,y-2) != empty)
          array[x][y][inactive] = moveable;

        if (activeArray(x,y+1) == moveable && activeArray(x,y+2) != empty)
          array[x][y][inactive] = moveable;
      }
      else if (array[x][y][active] == moveable)
      {
        if (activeArray(x-1,y) != empty && activeArray(x+1,y) == empty &&
            activeArray(x,y-1) == empty && activeArray(x,y+1) == empty)
          array[x][y][inactive] = empty;

        if (activeArray(x-1,y) == empty && activeArray(x+1,y) != empty &&
            activeArray(x,y-1) == empty && activeArray(x,y+1) == empty)
          array[x][y][inactive] = empty;

        if (activeArray(x-1,y) == empty && activeArray(x+1,y) == empty &&
            activeArray(x,y-1) != empty && activeArray(x,y+1) == empty)
          array[x][y][inactive] = empty;

        if (activeArray(x-1,y) == empty && activeArray(x+1,y) == empty &&
            activeArray(x,y-1) == empty && activeArray(x,y+1) != empty)
          array[x][y][inactive] = empty;
      }
    }
  }

  active = active ? active0 : active1;
  inactive = inactive ? active0 : active1;
}

int main(int argc, char *argv[])
{
  if (argc != 5)
  {
    fprintf(stderr,"Usage: comprepel x y <input-file> iterations\n"
                  "       where\n"
                  "       x = x-offset, y = y-offset\n"
                  "       <input-file> contains an initial pattern to be placed at offset (x,y)\n"
                  "       iterations = number of iterations to run before producing output\n");
    return -1;
  }
  else
  {
    int x,y,iterations;

    x = atoi(argv[1]);
    y = atoi(argv[2]);
    iterations = atoi(argv[4]);

    if (x<0 || y<0 || x>=arraySizeX || y>=arraySizeY || iterations < 0)
    {
      fprintf(stderr,"Invalid parameters\n");
      return -2;
    }

    FILE *finput = fopen(argv[3],"r");

    if (finput)
    {
      int xoffset = x;
      int xpos = xoffset, ypos = y;

      for(int c = fgetc(finput); c != EOF; c = fgetc(finput))
      {
        if (c=='O' || c=='o' || c=='0')
          array[x][y][active] = moveable;
        else if (c=='X' || c=='x')
          array[x][y][active] = fixed;

        if (c=='\n')
        {
          y += 1;
          x = xoffset;
        }
        else if (c != '\f')
          x += 1;

        if (x>=arraySizeX || y>=arraySizeY)
          break;
      }

      fclose(finput);

      while(iterations--)
      {
        process();
      }

      for(y=0; y<arraySizeY; y++)
      {
        for(x=0; x<arraySizeX; x++)
        {
          switch(array[x][y][active])
          {
            case fixed:
              putchar('X');
              break; 
            case moveable:
              putchar('O');
              break;
            default:
              putchar(' ');
              break;
          }
        }
        printf("\n");
      }
    }
    else
    {
      fprintf(stderr,"Unable to open input file\n");
      return -2;
    }
  }

  return 0;
}
