EGGXを使って
ライフゲームの処理系を作る。
以下は、グローバル変数が多い、読みにくいコード。状態が遷移した回数だけgif画像を出力する(要ImageMagick)。
LIM回状態が遷移するか、状態が変わらなかったとき、終了する。ダブルバッファリングなどの洒落た機能は入れて無いので、画面がチラチラするかもしれない。
#include <stdio.h>
#include <string.h>
#include <eggx.h>
#define EGGX_BLACK 0
#define EGGX_WHITE 1
/* 最大100*100マスまで許容する */
#define MAX_SIZE 100
#define CELL_WIDTH 20
#define CELL_HEIGHT 20
#define DEAD 0
#define LIVE 1
/* 最大1000回まで状態を遷移させる */
#define LIM 1000
/* 状態遷移間隔(ミリ秒) */
#define DELAY 200
int win;
int w, h;
int width, height;
int board[MAX_SIZE][MAX_SIZE];
int prev[MAX_SIZE][MAX_SIZE];
void init(void);
int next_state(int y, int x);
void change_cells(void);
void draw_cell(int y, int x);
void draw_cells(void);
void init(void)
{
int x, y;
memset(prev, -1, sizeof(prev));
scanf("%d %d", &w, &h);
width = w*CELL_WIDTH;
height = h*CELL_HEIGHT;
for (y = 0; y < h; y++)
for (x = 0; x < w; x++)
scanf("%d", &board[y][x]);
}
int next_state(int y, int x)
{
int i, live;
int dy[] = { -1, 0, 1, -1, 1, -1, 0, 1 };
int dx[] = { -1, -1, -1, 0, 0, 1, 1, 1 };
live = 0;
for (i = 0; i < 8; i++) {
int ty = y+dy[i], tx = x+dx[i];
if (!(0 <= ty && ty < h)) continue;
if (!(0 <= tx && tx < w)) continue;
if (board[ty][tx] == LIVE) live++;
}
switch (live) {
case 2: return board[y][x];
case 3: return LIVE;
default: return DEAD;
}
}
void change_cells(void)
{
int y, x;
int buf[MAX_SIZE][MAX_SIZE];
memset(buf, 0, sizeof(buf));
for (y = 0; y < h; y++)
for (x = 0; x < w; x++)
buf[y][x] = next_state(y, x);
memcpy(board, buf, sizeof(buf));
}
void draw_cell(int y, int x)
{
int kind;
int px, py;
kind = board[y][x];
newpen(win, kind==DEAD?EGGX_WHITE:EGGX_BLACK);
px = x*CELL_WIDTH;
py = (h-1-y)*CELL_HEIGHT;
fillrect(win, px, py, CELL_WIDTH, CELL_HEIGHT);
}
void draw_cells(void)
{
int y, x;
for (y = 0; y < h; y++)
for (x = 0; x < w; x++)
if (board[y][x] != prev[y][x])
draw_cell(y, x);
newpen(win, EGGX_BLACK);
drawrect(win, 0, 0, width-1, height-1);
}
int main(void)
{
int i;
init();
win = gopen(width, height);
for (i = 0; i < LIM; i++) {
if (memcmp(board, prev, sizeof(board))==0)
break;
winname(win, "turn %d", i);
draw_cells();
saveimg(win, 0, 0, 0, width-1, height-1, "convert", 16, "img%d.gif", 1000+i);
memcpy(prev, board, sizeof(board));
change_cells();
msleep(DELAY);
}
gclose(win);
return 0;
}
入力例と、それに対応する出力された画像をまとめたgif動画。入力のはじめ一行の二値は、それぞれ幅と高さを意味する。それに続くデータは、0なら死、1なら生を表す。
10 10
0 1 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0