MinGW キャラクタベース
キャラクタベースの出力
コマンドプロンプトのようなキャラクタベースでプログラムを作る場合に、少しでも見栄えをよくしようとすると、画面の消去、カーソル位置制御、文字色の設定ぐらいは最低限ほしいところです。そこで、これらを実現する関数を作成し、ライフゲームを動かします。
画面制御プログラム
以下の3つの関数を作成しました。
- cls : 画面消去
- locate : カーソル位置設定
- color : 表示文字色、背景色設定
以下にソースを示します。このプログラムは、Linux のターミナルプログラムでも動作するように作られています。
#ifdef _WINDOWS_H
#ifndef _WINDOWS_
#define _WINDOWS_
#endif
#endif
void locate(int, int);
void cls();
void color(int, int);
void locate(int lx, int ly) { // Move cursor at (lx,ly)
#ifdef _WINDOWS_
static HANDLE h;
COORD st;
lx = (lx < 1) ? 0 : (lx - 1);
ly = (ly < 1) ? 0 : (ly - 1);
h=GetStdHandle(STD_OUTPUT_HANDLE);
st.X = (short)lx;
st.Y = (short)ly;
SetConsoleCursorPosition(h, st);
#else
if(lx < 1) lx = 1;
if(ly < 1) ly = 1;
printf("\033[%d;%dH", lx, ly);
fflush(stdout);
#endif
}
void cls() { // Clear screen
#ifdef _WINDOWS_
system("cls");
#else
printf("\033[2J");
printf("\033[1;1H");
fflush(stdout);
#endif
}
// Black:0 Red:1 Green:2 Yellow:3 Blue:4 Magenta:5 Cyan:6 White:7
void color(int fgc, int bgc) { // Change text foreground and background color
#ifdef _WINDOWS_
int cl = 7;
static HANDLE h;
if(fgc < 0) fgc = 0;
if(bgc < 0) bgc = 0;
// Defined below at wincon.h
// FOREGROUND_BLUE 1
// FOREGROUND_GREEN 2
// FOREGROUND_RED 4
// FOREGROUND_INTENSITY 8
// BACKGROUND_BLUE 16
// BACKGROUND_GREEN 32
// BACKGROUND_RED 64
// BACKGROUND_INTENSITY 128
if(fgc == 0) cl = 0;
if(fgc == 1) cl = 4;
if(fgc == 2) cl = 2;
if(fgc == 3) cl = 6;
if(fgc == 4) cl = 1;
if(fgc == 5) cl = 5;
if(fgc == 6) cl = 3;
if(fgc == 7) cl = 7;
if(fgc == 9) cl = 7;
if(bgc == 0) cl += 0;
if(bgc == 1) cl += 64;
if(bgc == 2) cl += 32;
if(bgc == 3) cl += 96;
if(bgc == 4) cl += 16;
if(bgc == 5) cl += 80;
if(bgc == 6) cl += 48;
if(bgc == 7) cl += 112;
if(bgc == 9) cl += 0;
h=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(h, cl);
#else
if(fgc < 0) fgc = 0;
if(bgc < 0) bgc = 0;
printf("\033[3%1dm", fgc);
printf("\033[4%1dm", bgc);
fflush(stdout);
#endif
}
ライフゲームプログラム
上述した画面制御関数(ファイル名を cui.c とする)を利用したライフゲーム(ファイル名を life2c.c とする)を作成しました。2つのソースプログラムは同一のディレクトリに置いて下さい。
コンパイルは、MinGW の環境では、以下のように行います。
> cc life2c.c
以下に、ライフゲームのソースを示します。
#include <stdio.h>
#include <windows.h>
#include "cui.c"
#define MAXSTEP 500 // Step
#define BMX 79 // Max x size of board
#define BMY 23 // Max y size of board
int b[BMX+2][BMY+2]; // Board Empty:0 Marked:3
void inputboard() {
int x;
int y;
for(y = 0; y < BMY+2; y++) {
for(x = 0; x < BMX+2; x++) {
b[x][y] = 0;
}
}
b[40][14] = 3;
b[40][15] = 3;
b[40][16] = 3;
b[41][14] = 3;
b[39][15] = 3;
}
void outputboard(int i) {
int x;
int y;
char buf[BMX+1];
locate(1, 1);
for(y = 1; y <= BMY; y++) {
for(x = 1; x <= BMX; x++) {
if(b[x][y] == 0) {
buf[x-1] = ' ';
} else {
buf[x-1] = '*';
}
}
buf[BMX] = '\0';
printf("%s\n", buf);
}
color(3, 0);
printf("Step : %5d\n", i);
color(9, 9);
}
void initscreen() {
cls();
}
int countalive(int x, int y) {
int cal = 0;
if(b[x-1][y-1] > 1) cal ++;
if(b[x-1][y] > 1) cal ++;
if(b[x-1][y+1] > 1) cal ++;
if(b[x][y-1] > 1) cal ++;
if(b[x][y+1] > 1) cal ++;
if(b[x+1][y-1] > 1) cal ++;
if(b[x+1][y] > 1) cal ++;
if(b[x+1][y+1] > 1) cal ++;
return cal;
}
void nextstep() {
int x;
int y;
int cal;
for(y = 1; y <= BMY; y++) {
for(x = 1; x <= BMX; x++) {
cal = countalive(x, y);
if(b[x][y] == 0) {
if(cal == 3) b[x][y] = 1;
} else if(b[x][y] == 3) {
if(cal < 2) b[x][y] = 2;
if(cal > 3) b[x][y] = 2;
} else {
printf("Unknown code of board[%d][%d]\n", x, y);
}
}
}
for(y = 1; y <= BMY; y++) {
for(x = 1; x <= BMX; x++) {
if(b[x][y] == 1) b[x][y] = 3;
if(b[x][y] == 2) b[x][y] = 0;
}
}
}
int main() {
int i = 0;
inputboard();
initscreen();
for(i = 1; i <= MAXSTEP; i++) {
outputboard(i);
nextstep();
}
return 0;
}