Tom Says: Safe code is boring code!
Any computer scientist probably knows Conway's Game of Life. Anyone reading this blog is probably a computer scientist. Thus, this page probably needs no further introduction.
For the mildly curious, I've implemented a very simple client in D using ArcLib (a 2D game library powered by Derelict, which is powered by OpenGL/SDL). It should compile on all the platforms supported by Derelict, which I daresay should cover most everyone.
I recommend using this tutorial for instructions on how to build ArcLib programs using DSSS.
module main;
import arc.input;
import arc.time;
import arc.window;
import arc.font;
import arc.math.point;
import arc.math.size;
import arc.draw.color;
import arc.draw.shape;
import std.random;
import std.stdio;
const int rows = 90, cols = 144;
const int grid_size = 5; // pixels per grid edge
const int sprinkle_percent = 10;
bool[cols][rows] grid;
int steps = 0, fps = 12;
/+ SHAPES +/
struct Shape
{
int width, height;
char[][] shape;
}
enum Shapes { BLOCK, GLIDER };
Shape[] cool_shapes = [
{ width:2, height:2, // 0: Boat
shape:[ "xx",
"xx" ] },
{ width:3, height:3, // 1: Glider
shape:[ " x ",
" x",
"xxx" ] }
];
/+ HELPER FUNCTIONS +/
int wrap_row(int row) { return (row + rows) % rows; }
int wrap_col(int col) { return (col + cols) % cols; }
int live_neighbors(int row, int col)
{
int neighbors = 0;
for(int r = -1; r <= 1; r++)
for(int c = -1; c <= 1; c++)
if(r != 0 || c != 0)
neighbors += grid[wrap_row(row+r)][wrap_col(col+c)] ? 1 : 0;
return neighbors;
}
void life_step()
{
bool[cols][rows] next;
for(int row = 0; row < rows; row++)
for(int col = 0; col < cols; col++)
{
int neighbors = live_neighbors(row, col);
if(neighbors < 2 || neighbors > 3)
next[row][col] = false;
else if(neighbors == 3)
next[row][col] = true;
else
next[row][col] = grid[row][col];
}
for(int row = 0; row < rows; row++)
for(int col = 0; col < cols; col++)
grid[row][col] = next[row][col];
}
void draw(int row, int col) { grid[wrap_row(row)][wrap_col(col)] = true; }
void draw_shape(int row, int col, Shape shape)
{
for(int r = 0; r < shape.width; r++)
for(int c = 0; c < shape.height; c++)
if(shape.shape[r][c] == 'x')
draw(row+r, col+c);
}
void draw_random_shape()
{
int shape = rand() % (Shapes.max + 1);
draw_shape(rand() % rows, rand() % cols, cool_shapes[shape]);
}
void sprinkle_life()
{
// (rows * cols) * (sprinkle_percent / 100)
int quota = rows * cols * sprinkle_percent / 100;
for(int i = 0; i < quota; i++)
draw(rand() % rows, rand() % cols);
}
/+ GAME LOOPS +/
int main()
{
arc.window.open("Life (keys: left, right, space, q, x)", cols*grid_size, rows*grid_size, 0 );
arc.input.open();
arc.time.open();
while(!arc.input.keyDown(ARC_QUIT))
{
arc.input.process();
arc.time.process();
// draw
arc.window.clear();
for(int row = 0; row < rows; row++)
for(int col = 0; col < cols; col++)
drawRectangle(Point(col*grid_size, row*grid_size),
Size(grid_size, grid_size), grid[row][col] ? Color.White :
Color.Black, true);
// paint
arc.window.swap();
if(arc.input.keyReleased(ARC_SPACE))
sprinkle_life();
if(arc.input.keyReleased(ARC_x))
draw_random_shape();
if(arc.input.keyReleased(ARC_RIGHT))
fps += 3;
if(arc.input.keyReleased(ARC_LEFT))
fps = (fps - 3 > 1) ? fps - 3 : 1;
if(arc.input.keyReleased(ARC_q))
break;
// progress life
life_step();
steps++;
limitFPS(fps);
}
arc.window.close();
return 0;
}
Posted Aug 15, 2007, in the night.