技術文章> さくさく理解できる C/C++ コンソールアプリ入門 > 2048
コンソールで動作する簡易な2048(下図は実行画面)をC++で書いたので、簡単に説明する。
本稿で解説する 2048 のソースコードは以下から取得できる。
ライセンスは CDDL 1.0 なので、自由に改変して再配布してOKだぞ。
なお、オリジナル 2048 は MIT ライセンスでソースコードが公開されているが、本プログラムはそれを参照せず、 筆者が独自に実装したものなので、細部の仕様が少しことなる場合があるかもしれないのでご了承ください。
上下左右カーソルキーを押すと、盤面上のすべての数字ブロックがその方向に移動します。
同じ数字にぶつかると、ブロックが合体し、値が倍になります。
上下左右どちらかの方向に移動した場合、ランダムな位置に2または4のブロックが出現します。
上下左右どの方向にも移動できなくなったら q で終了します。
ソースコードには数値を直接書くのはなるべく避けなくてはいけない。
ソースを読むときに、数値の意味が分からないことがあるし、後で変更したいときにどこを変えていいかわからず、保守性に問題があるからだ。
※ 変更したい時は全置換すればいいと思うかもしれないが、同じ数字が使ってあると、そううまくはいかない。
#define WALL -1 // 番人 #define BOARD_WD 4 // ボード幅 #define BOARD_HT 4 // ボード高さ #define CELL_WIDTH 8 // セル表示幅 #define KEY_ARROW 0xe0 #define KEY_UP 0x48 #define KEY_LEFT 0x4b #define KEY_RIGHT 0x4d #define KEY_DOWN 0x50
キーの読込には _getc() を使っているが、矢印キーを押した場合は 0xe0 がまず返ってきて、次の呼び出しでキーに対応するコードが返ってくる。
上記はその定義である。
std::random_device g_rnd; // 非決定的な乱数生成器 intg_score = 0; intg_board[BOARD_WD+2][BOARD_HT+2]; // 番人付きボード2次元配列
グローバル変数として、乱数生成器、スコア、盤面を定義している。
一般的にグローバル変数の多様はあまりよろしくないとされている。特に大規模プロジェクトではよろしくないと考えるが、
速度が遅いので、筆者はあまり2次元配列は好きではないのだが、わかりやすさを優先することとし、 本プログラムでは盤面のデータ構造に2次元配列を採用することにした。 グローバルな2次元配列で表現している。
配列サイズは、縦横共に +2 していることに注意してほしい。
これは、境界チェックを省くために、上下左右にそれぞれ1マス余計に確保しているのだ。
ひとマス余計に確保しているので、x, y の有効範囲は [1, BD_WD], [1, BD_HT] となる。
このように実際に表示される部分より余分にデータを確保するテクニックはとてもよく使う。
ぜひマスターして使えるようになって欲しいテクニックのひとつだ。
void init_board() は盤面初期化を行う関数だ。
g_board 配列の初期化を行う。
まずは、全範囲について、全てのマス目を閉じた状態、爆弾は無し、周りの爆弾数は0に設定する。
ソースコードは下記のようになる。
void init_board() { for (int x = 0; x < BOARD_WD+2; ++x) { for (int y = 0; y < BOARD_HT+2; ++y) { if( x == 0 || x == BOARD_WD + 1 || y == 0 || y == BOARD_HT + 1 ) { g_board[x][y] = WALL; } else { g_board[x][y] = 0; } } } }
void print_board() は盤面を表示する関数だ。
g_board[][] を参照して盤面を描画するぞ。