Game of Life: Gosper Glider Gun

Some time ago someone posted a Game Of Life thread here... I can't find it now but I had never played with it before and figured why not have some fun?

Anyway, this is the toy I hacked up to play with it. I have not been able to test it in Linux (as my PC is still dead, and I'm using my son's ATM -- great story! I'm working on two dead motherboards and four bad HDs now... I suppose I'm not allowed to have my own system right now).

In any case, the toy:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// Gosper Glider Gun

// Written by Michael Thomas Greer
// Released to the Public Domain.

// Compiling Instructions
//   Compile with C++11 mode.
//   Windows:
//     Make sure you are compiling a normal Windows console application.
//   Unix/Linux:
//     Be sure to link with -lcurses (If that doesn't work, try -lncurses or
//     -lterminfo. If those don't work, be sure to make sure you have the
//     terminfo library installed and read the man pages for how to link.)

//////////////////////////////////////////////////////////////////////////////
#ifdef _WIN32
//////////////////////////////////////////////////////////////////////////////

  #define NOMINMAX
  #include <windows.h>

  //--------------------------------------------------------------------------
  bool Initialize( int& w, int& h )
    {
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    HANDLE hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
    if (!GetConsoleScreenBufferInfo( hStdOut, &csbi ))
      return false;

    w = csbi.srWindow.Right  - csbi.srWindow.Left + 1;
    h = csbi.srWindow.Bottom - csbi.srWindow.Top  + 1;

    return true;
    }

  //--------------------------------------------------------------------------
  void Finalize()
    { }

  //--------------------------------------------------------------------------
  void ClearScreen()
    {
    HANDLE                     hStdOut;
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    DWORD                      count;
    DWORD                      cellCount;
    COORD                      homeCoords = { 0, 0 };

    hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
    if (hStdOut == INVALID_HANDLE_VALUE) return;

    /* Get the number of cells in the current buffer */
    if (!GetConsoleScreenBufferInfo( hStdOut, &csbi )) return;
    cellCount = csbi.dwSize.X *csbi.dwSize.Y;

    /* Fill the entire buffer with spaces */
    if (!FillConsoleOutputCharacter(
      hStdOut,
      (TCHAR) ' ',
      cellCount,
      homeCoords,
      &count
      )) return;

    /* Fill the entire buffer with the current colors and attributes */
    if (!FillConsoleOutputAttribute(
      hStdOut,
      csbi.wAttributes,
      cellCount,
      homeCoords,
      &count
      )) return;

    /* Move the cursor home */
    SetConsoleCursorPosition( hStdOut, homeCoords );    
    }

  //--------------------------------------------------------------------------
  void GoHome()
    {
    HANDLE hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
    COORD homeCoords = { 0, 0 };
    SetConsoleCursorPosition( hStdOut, homeCoords );
    }

  //--------------------------------------------------------------------------
  void GotoXY( int x, int y )
    {
    HANDLE hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
    COORD coords = { (SHORT)x, (SHORT)y };
    SetConsoleCursorPosition( hStdOut, coords );
    }

  //--------------------------------------------------------------------------
  bool IsKeyPressed( unsigned timeout_ms = 0 )
    {
    return WaitForSingleObject(
      GetStdHandle( STD_INPUT_HANDLE ),
      timeout_ms
      ) == WAIT_OBJECT_0;
    }

  //--------------------------------------------------------------------------
  // Emit "OEM" codes on Windows
  const char* space = " ";
  const char* block = "\xDB";
  const char* topbk = "\xDF";
  const char* botbk = "\xDC";


//////////////////////////////////////////////////////////////////////////////
#else  // POSIX (presumably)
//////////////////////////////////////////////////////////////////////////////

  #include <unistd.h>
  #include <term.h>
  #include <termios.h>
  #include <sys/ioctl.h>
  #include <poll.h>

  struct termios initial_settings;

  //--------------------------------------------------------------------------
  bool Initialize( int& w, int& h )
    {
    if (!cur_term)
      {
      int result;
      setupterm( NULL, STDOUT_FILENO, &result );
      if (result <= 0) return false;
      }

    struct winsize ws;
    ioctl( 0, TIOCGWINSZ, &ws );
    w = ws.ws_col;
    h = ws.ws_row;

    return (0 == tcgetattr( STDIN_FILENO, &initial_settings ));
    }

  //--------------------------------------------------------------------------
  void Finalize()
    {
    tcsetattr( STDIN_FILENO, TCSANOW, &initial_settings );
    }

  //--------------------------------------------------------------------------
  void ClearScreen()
    {
    putp( tigetstr( "clear" ) );
    }

  //--------------------------------------------------------------------------
  void GoHome()
    {
    putp( tigetstr( "home" ) );
    }

  //--------------------------------------------------------------------------
  void GotoXY( int x, int y )
    {
    putp( tparm( tigetstr( "cup" ), y, x, 0, 0, 0, 0, 0, 0, 0 ) ); 
    }

  //--------------------------------------------------------------------------
  bool IsKeyPressed( unsigned timeout_ms = 0 )
    {
    struct pollfd pls[ 1 ];
    pls[ 0 ].fd     = STDIN_FILENO;
    pls[ 0 ].events = POLLIN | POLLPRI;
    return poll( pls, 1, timeout_ms ) > 0;
    }

  //--------------------------------------------------------------------------
  // Emit UTF-8 codes on Linux
  const char* space = " ";
  const char* block = "\xE2\x96\x88";  // U+2588
  const char* topbk = "\xE2\x96\x80";  // U+2580
  const char* botbk = "\xE2\x96\x84";  // U+2584

#endif
(continued)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/* ///////////////////////////////////////////////////////////////////////////
main program
/////////////////////////////////////////////////////////////////////////// */

#include <algorithm>
#include <iostream>
#include <limits>
#include <sstream>
#include <string>
using namespace std;

//----------------------------------------------------------------------------
bool* board[ 2 ] = { NULL, NULL };
int   active = 0;
int   w, h;

//----------------------------------------------------------------------------
bool& index( int active, int x, int y )
  {
  return *(board[ active ] + ((y + 1) * (w + 2)) + (x + 1));
  }

//----------------------------------------------------------------------------
void draw()
  {
  for (int y = 0; y < h; y += 2)
    {
    for (int x = 0; x < w; x++)
      {
      bool newtop = index( active,     x, y     );
      bool newbot = index( active,     x, y + 1 );
      bool oldtop = index( active ^ 1, x, y     );
      bool oldbot = index( active ^ 1, x, y + 1 );

      if ((newtop != oldtop) or (newbot != oldbot))
        {
        GotoXY( x, (y / 2) + 1 );
        if (newtop && newbot) cout << block;
        else if (newtop)      cout << topbk;
        else if (newbot)      cout << botbk;
        else                  cout << space;
        }
      }
    }
  }

//----------------------------------------------------------------------------
int neighbors( int x, int y )
  {
  int result = 0;
  bool* p = &(index( active, x - 1, y - 1 ));

  result += p[ 0 ] + p[ 1 ] + p[ 2 ];  p += w + 2;
  result += p[ 0 ]          + p[ 2 ];  p += w + 2;
  result += p[ 0 ] + p[ 1 ] + p[ 2 ];

  return result;
  }

//----------------------------------------------------------------------------
void update()
  {
  int inactive = active ^ 1;

  for (int x = 0; x < w; x++)
  for (int y = 0; y < h; y++)
    {
    int n = neighbors( x, y );
    if (index( active, x, y )) index( inactive, x, y ) = (n == 2) || (n == 3);
    else                       index( inactive, x, y ) =             (n == 3);
    }

  active ^= 1;

  fill_n( &(index( active, -1, 0 )), w + 2, false );
  fill_n( &(index( active,  0, h )), w,     false );
  for (int y = 1; y < h; y++)
    {
    index( active, -1, y ) = false;
    index( active,  w, y ) = false;
    }
  }

//----------------------------------------------------------------------------
#define _ 0
bool glider_gun[ 11 ][ 38 ] =
  {
  { _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ },
  { _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,1,_,_,_,_,_,_,_,_,_,_,_,_ },
  { _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,1,_,1,_,_,_,_,_,_,_,_,_,_,_,_ },
  { _,_,_,_,_,_,_,_,_,_,_,_,_,1,1,_,_,_,_,_,_,1,1,_,_,_,_,_,_,_,_,_,_,_,_,1,1,_ },
  { _,_,_,_,_,_,_,_,_,_,_,_,1,_,_,_,1,_,_,_,_,1,1,_,_,_,_,_,_,_,_,_,_,_,_,1,1,_ },
  { _,1,1,_,_,_,_,_,_,_,_,1,_,_,_,_,_,1,_,_,_,1,1,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ },
  { _,1,1,_,_,_,_,_,_,_,_,1,_,_,_,1,_,1,1,_,_,_,_,1,_,1,_,_,_,_,_,_,_,_,_,_,_,_ },
  { _,_,_,_,_,_,_,_,_,_,_,1,_,_,_,_,_,1,_,_,_,_,_,_,_,1,_,_,_,_,_,_,_,_,_,_,_,_ },
  { _,_,_,_,_,_,_,_,_,_,_,_,1,_,_,_,1,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ },
  { _,_,_,_,_,_,_,_,_,_,_,_,_,1,1,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ },
  { _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ },
  };
int ggh = extent                <decltype( glider_gun )>         ::value;
int ggw = extent <remove_extent <decltype( glider_gun )> ::type> ::value;
#undef _

//----------------------------------------------------------------------------
int main()
  {
  if (!Initialize( w, h ))
    {
    cout << "Fooey! I couldn't start terminal control properly.\n";
    return 1;
    }

  w =  (w - 1) & ~1;
  h = ((h - 2) & ~1) * 2;

  if ((ggh > h) || (ggw > w))
    {
    cout << "Hey! Your console must be sized larger than "
         << ggw << " by " << ggh << "!\n";
    return 2;
    }

  cout << "speed in ms (default 150)? ";
  int speed = 150;
  {
  string s;
  getline( cin, s );
  if (!s.empty())
    {
    istringstream ss( s );
    ss >> speed;
    if (!ss.eof() or (speed < 0) or (speed > 2000))
      {
      cout << "Foo, that's not a valid speed!\n";
      return 3;
      }
    }
  }

  board[ 0 ] = new bool[ (w + 2) * (h + 2) ];
  board[ 1 ] = new bool[ (w + 2) * (h + 2) ];

  fill_n( board[ active ], (w + 2) * (h + 2), false );

  ClearScreen();
  string title = "Gosper Glider Gun (press ENTER to quit)";
  cout << title << string( w - title.length(), ' ' ) << "\n";

  for (int y = 0; y < ggh; y++)
  for (int x = 0; x < ggw; x++)
    index( active, x, y ) = glider_gun[ y ][ x ];

  do {
    draw();
    update();
    }
  while (!IsKeyPressed( speed ));
  cin.ignore( numeric_limits <streamsize> ::max(), '\n' );

  delete[] board[ 0 ];
  delete[] board[ 1 ];
  Finalize();
  return 0;
  }

Let me know if you have problems on *nix.
Works fine on openSUSE 12.1, GCC 4.6.2. Good work...
http://i45.tinypic.com/xp3ng2.png
Yay! Thanks!
I would comment, when it asks for "speed" it's actually asking for "refresh rate". Also, a default speed of <50 would look nicer IMO.
It isn't even that. The "speed" is actually the delay time between update-and-refresh cycles. If it takes your terminal longer to refresh than mine, then yours will run more slowly than mine.
Topic archived. No new replies allowed.