#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define MAX_EDGE 256
#define MAX_LINE 512
#define MAX_TITLE 64
#define WORLDSIZE (worldedge.x * worldedge.y * 2)
typedef struct {
int x;
int y;
} coordination;
static coordination worldedge;
typedef char celltype;
static coordination StandardizeCoordination(coordination cd) {
if (cd.x < 0) {
cd.x = worldedge.x - 1;
}
else if (worldedge.x <= cd.x) {
cd.x = 0;
}
if (cd.y < 0) {
cd.y = worldedge.y - 1;
}
else if (worldedge.y <= cd.y) {
cd.y = 0;
}
return cd;
}
static coordination GetAroundCoordination(int n, coordination cd) {
switch (n) {
case 0:
case 3:
case 5:
cd.x--;
break;
case 2:
case 4:
case 7:
cd.x++;
break;
}
switch (n) {
case 0:
case 1:
case 2:
cd.y--;
break;
case 5:
case 6:
case 7:
cd.y++;
break;
}
return StandardizeCoordination(cd);
}
static celltype *Cell(celltype *world, coordination cd, int generation) {
int idx;
assert(-1 <= cd.x && cd.x <= worldedge.x);
assert(-1 <= cd.y && cd.y <= worldedge.y);
idx = (cd.x * worldedge.y + cd.y) * 2 + (generation & 1);
assert(0 <= idx && idx < WORLDSIZE);
return world + idx;
}
static void NextGeneration(celltype *world, int generation) {
coordination cd;
int nbr, i;
for (cd.x = 0; cd.x < worldedge.x; cd.x++) {
for (cd.y = 0; cd.y < worldedge.y; cd.y++) {
nbr = 0;
for (i = 0; i < 8; i++) {
if (*Cell(world, GetAroundCoordination(i, cd), generation)) {
nbr++;
}
}
if (nbr == 3) {
*Cell(world, cd, generation + 1) = 1;
}
else if (nbr == 2) {
*Cell(world, cd, generation + 1) = *Cell(world, cd, generation);
}
else {
*Cell(world, cd, generation + 1) = 0;
}
}
}
}
static celltype *InitWorld(const char *patternfile, char *title) {
FILE *pf;
celltype *world;
char line[MAX_LINE];
char *p;
const char delimiter[] = "\t";
coordination cd;
pf = fopen(patternfile, "rt");
if (!pf) {
perror(patternfile);
exit(3);
}
/* ヘッダを読む */
fgets(line, sizeof(line), pf);
/* タイトル */
p = strtok(line, delimiter);
if (!p) {
fputs("タイトルがない", stderr);
exit(3);
}
strncpy(title, p, MAX_TITLE);
title[MAX_TITLE - 1] = '\0';
/* edge-x */
p = strtok(NULL, delimiter);
if (!p) {
fputs("xがない", stderr);
exit(3);
}
worldedge.x = atoi(p);
if (worldedge.x <= 0 || MAX_EDGE < worldedge.x) {
fputs("xが変", stderr);
exit(3);
}
/* edge-y */
p = strtok(NULL, delimiter);
if (!p) {
fputs("yがない", stderr);
exit(3);
}
worldedge.y = atoi(p);
if (worldedge.y <= 0 || MAX_EDGE < worldedge.y) {
fputs("yが変", stderr);
exit(3);
}
/* パターン読みこみ */
world = (celltype *)malloc(WORLDSIZE);
if (!world) {
fputs("メモリ足りん", stderr);
exit(3);
}
memset(world, 0, WORLDSIZE);
for (cd.y = 0; cd.y < worldedge.y; cd.y++) {
if (!fgets(line, sizeof(line), pf)) {
break;
}
for (cd.x = 0, p = line; cd.x < worldedge.x && *p && *p != '\n'; cd.x++, p++) {
*Cell(world, cd, 0) = (*p == '*' || *p == 'O') ? 1 : 0;
}
}
fclose(pf);
return world;
}
static FILE *OpenHtml(int generation, const char *fileprefix) {
FILE *pf;
char filename[64];
assert(fileprefix);
sprintf(filename, "%s%03d.html", fileprefix, generation);
pf = fopen(filename, "wt");
if (!pf) {
perror(filename);
exit(3);
}
return pf;
}
static void PrintWorld(celltype *world, int generation, int maxgen, const char *title, const char *fileprefix) {
coordination cd;
FILE *pf;
int i, xcnt, ycnt;
pf = OpenHtml(generation, fileprefix);
fprintf(pf, "<HTML>\n<HEAD>\n<TITLE>%s</TITLE>\n", title);
fprintf(pf, "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=Shift_JIS\">\n");
fprintf(pf, "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"0; URL=%s%03d.html\">", fileprefix, generation + 1);
fprintf(pf, "\n</HEAD>\n<BODY>\n<P>%d / %d</P>\n<HR>\n<P><TT><SMALL>\n", generation + 1, maxgen);
ycnt = 0;
for (cd.y = 0; cd.y < worldedge.y; cd.y++) {
xcnt = 0;
for (cd.x = 0; cd.x < worldedge.x; cd.x++) {
if (*Cell(world, cd, generation)) {
for (i = 0; i < ycnt; i++) {
fputs("<BR>\n", pf);
}
ycnt = 0;
for (i = 0; i < xcnt; i++) {
fputs(" ", pf);
}
xcnt = 0;
fputs("●", pf);
}
else {
xcnt++;
}
}
ycnt++;
}
fputs("\n</SMALL></TT></P>\n</BODY></HTML>", pf);
fclose(pf);
}
static void Finish(int generation, const char *title, const char *fileprefix) {
FILE *pf;
pf = OpenHtml(generation, fileprefix);
fprintf(pf,
"<HTML>\n"
"<HEAD>\n"
"<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=Shift_JIS\">\n"
"<TITLE>%s</TITLE>\n"
"</HEAD>\n"
"<BODY>\n"
"<H1>おしまい</H1>\n"
"<HR>\n"
"<P><A HREF=\"./%s000.html\">もう一度</A> <A HREF=\"./\">戻る</A></P>\n"
"</BODY>\n"
"</HTML>\n"
,title ,fileprefix);
fclose(pf);
}
int main(int argc, char **argv) {
int generation, maxgen;
celltype *world;
char title[MAX_TITLE];
char *fileprefix;
if (argc != 3) {
fputs("usage: htmllife <number-generation> <pattern-file>", stderr);
return 0;
}
maxgen = (int)strtoul(argv[1], NULL, 10);
fileprefix = argv[2];
world = InitWorld(fileprefix, title);
for (generation = 0; generation < maxgen; generation++) {
PrintWorld(world, generation, maxgen, title, fileprefix);
printf("%d/%d\r", generation, maxgen);
NextGeneration(world, generation);
}
Finish(generation, title, fileprefix);
free(world);
return 0;
}