#
# life.jako
#
# Play Conway's (no, not *him*. The other Conway) game of life.
#
# Based on life.pasm, Hacked by Leon Brocard <acme@astray.com> to use curses.
#
# The original version of 2002-12-05 can be found here:
#
#     http://archive.develooper.com/perl6-internals@perl.org/msg13935.html
#

use sys;
use string;
use Curses;

var int foo; # Store result from above functions here.

const int G = 100; # Generation count.

const int WIDTH  = 15;
const int HEIGHT = 15;
var int ARRAY_SIZE;

ARRAY_SIZE = WIDTH * HEIGHT;

const str r00 = "               ";
const str r01 = "               ";
const str r02 = "               ";
const str r03 = "               ";
const str r04 = "   **          ";
const str r05 = " *    *        ";
const str r06 = "       *       ";
const str r07 = " *     *       ";
const str r08 = "  ******       ";
const str r09 = "               ";
const str r10 = "               ";
const str r11 = "               ";
const str r12 = "               ";
const str r13 = "               ";
const str r14 = "               ";

#const str r00 = "  *            ";
#const str r01 = "   *           ";
#const str r02 = " ***           ";
#const str r03 = "               ";
#const str r04 = "               ";
#const str r05 = "               ";
#const str r06 = "               ";
#const str r07 = "               ";
#const str r08 = "               ";
#const str r09 = "               ";
#const str r10 = "               ";
#const str r11 = "               ";
#const str r12 = "               ";
#const str r13 = "               ";
#const str r14 = "               ";


#
# at()
#
# Return 1 if the cell at row, col is alive, otherwise 0.
#

sub int at (str cells, int row, int col)
{
  var str temp;
  var int offset;

  row += HEIGHT; # In case they are slightly negative.
  col += WIDTH;

  row %= HEIGHT;
  col %= WIDTH;

  offset = row * WIDTH;
  offset += col;

  temp = string::substr(cells, offset, 1);

  return 1 if (temp == "*");
  return 0;
}


#
# generate()
#

sub str generate (str cells)
{
  var str temp = "";

  var int row = 0;

  while (row < HEIGHT) {
    var int col = 0;

    while (col < WIDTH) {
      var int count;
      var int r;
      var int c;
      var int cell;

      count = 0;

      r = row - 1; c = col - 1; cell = at(cells, r, c); count += cell; # NW
      r = row - 1; c = col    ; cell = at(cells, r, c); count += cell; # N
      r = row - 1; c = col + 1; cell = at(cells, r, c); count += cell; # NE

      r = row    ; c = col - 1; cell = at(cells, r, c); count += cell; # W
      r = row    ; c = col + 1; cell = at(cells, r, c); count += cell; # E

      r = row + 1; c = col - 1; cell = at(cells, r, c); count += cell; # SW
      r = row + 1; c = col    ; cell = at(cells, r, c); count += cell; # S
      r = row + 1; c = col + 1; cell = at(cells, r, c); count += cell; # SE

      var int current;
      current = at(cells, row, col);

      var str ch;
      if (current == 0) {
        ch = string::substr("   *     ", count, 1);
      }
      else {
        ch = string::substr("  **     ", count, 1);
      }

      temp ~= ch;

      col++;
    }

    row++;
  }

  return temp;
}


#
# dump()
#

sub dump(str cells, int g)
{
  foo = Curses::move(0, 0);
  foo = Curses::addstr("Generation $g of $G:");
  foo = Curses::move(1, 0);

  var int row = 0;
  while (row < HEIGHT) {
    var int col = 0;
    while (col < WIDTH) {
      var int current;
      current = at(cells, row, col);

      if (current == 1) {
        Curses::addstr("*");
      }
      else {
        Curses::addstr(" ");
      }
      col++;
    }
    Curses::addstr("\n");
    row++;
  }

  foo = Curses::move(0, 25);
  foo = Curses::refresh();
}

#
# Main program:
#

var str cells = "";

cells ~= r00;
cells ~= r01;
cells ~= r02;
cells ~= r03;
cells ~= r04;
cells ~= r05;
cells ~= r06;
cells ~= r07;
cells ~= r08;
cells ~= r09;
cells ~= r10;
cells ~= r11;
cells ~= r12;
cells ~= r13;
cells ~= r14;

var int len;
len = string::length(cells);

if (len != ARRAY_SIZE) {
  sys::print("ERROR! Cell array size is $len instead of $ARRAY_SIZE!\n");
  sys::exit(1);
}

foo = Curses::initscr();
foo = Curses::curs_set(0);

dump(cells, 0);

var int g = 0; # Number of generations so far.

while (g <= G) {
  cells = generate(cells);
  dump(cells, g);
  g++;
}

foo = Curses::move(16, 0);
foo = Curses::addstr("(Press any key to exit)");
foo = Curses::refresh();

foo = Curses::getch();

foo = Curses::curs_set(1);
foo = Curses::endwin();

