public class GameOfLife
{
  private static class Cell
  {
    private int row; // any +/0/- value
    private int col; // any +/0/- value

    ...any constructors, accessors, or mutators that you wish...

    // override the inherited Object.equals(Object)
    ...

    // override the inherited Object.hashCode()
    ...
  }

  // key is the row/column, value is an 'x' (always)
  private static MyDictionary<Cell, Character> grid;
  private static int minRow, maxRow; // range of rows ever used in the simulation
  private static int minCol, maxCol; // range of columns ever used in the simulation

  private static int neighborCount(Cell c)
  {
    Cell temp = new Cell();
    int count = 0;
    for (temp.row = c.row - 1; temp.row <= c.row + 1; temp.row++)
      for (temp.col = c.col - 1; temp.col <= c.col + 1; temp.col++)
        if (temp.row != c.row || temp.col != c.col)
          if (...the grid contains a match to "temp"...)
            ++count;
    return count;
  }

  private static void initialize()
  {
    // explain the simulation to the user in these words
    Welcome to Conway's game of Life.
    This game uses a grid in which
    each cell can either be occupied by an organism or not.
    The occupied cells change from generation to generation
    according to the number of neighboring cells which are alive.

    List the coordinates for living cells.
    Terminate the list with a special pair -1 -1.

    while (true)
    {
      Cell temp = new Cell(); // cell to be added to grid at...

      // read two int values: temp.row and temp.col
      ...

      if (temp.row == -1 && temp.col == -1)
        break;
      grid.add(temp, 'x'); // put an 'x' at selected row/col
    }

    // initialize ranges for rows and columns all to zero
    minRow = ...
    ...
  }

  private static void setScope()
  {
    // update the row/column ranges
    ...if any cell in the grid has a row less than minRow, reset minRow...
    ...
  }

  private static void print()
  {
    setScope();

    // use this header, with at least one line of separation from whatever is above
    The current Life configuration is:

    Cell temp = new Cell();
    for (temp.row = minRow; temp.row <= maxRow; temp.row++)
    {
      for (temp.col = minCol; temp.col <= maxCol; temp.col++)
        if (...the grid contains a match to "temp"...) 
          System.out.print(the value associated with the key "temp");
        else
          System.out.print(one blank space);
      System.out.println();
    }
    System.out.println();
  }

  private static void update()
  {
    setScope();

    // create the next generation
    MyDictionary<Cell, Character> newGrid = new MyHashTable<Cell, Character>(...);

    Cell temp = new Cell();
    for (temp.row = minRow - 1; temp.row <= maxRow + 1; temp.row++)
    {
      for (temp.col = minCol - 1; temp.col <= maxCol + 1; temp.col++)
      {
        switch (neighborCount(temp))
        {
          case 2: // existing cell survives
            if (...the grid contains a match to "temp"...)
            {
              add a 'x' in new grid at same location as temp in old grid
            }
            break;
          case 3: // existing cell survives OR new cell is born
            add a 'x' in new grid at same location as temp in old grid
            break;
        }
      }
    }
    grid = newGrid; // next generation replaces old
  }

  public static void main(String[] args)
  {
    // use a hash table for the dictionary with capacity of your choosing
    grid = new MyHashTable<Cell, Character>(...);

    initialize();
    print();

    loop while the grid is not empty
    {
      // tell user "Press ENTER to continue..." and wait for him to press ENTER
      // ...or to press Ctrl-C to stop
      ...

      update();
      print();
    }
  }
}