技術文章さくさく理解できる C/C++ コンソールアプリ入門 > 2048


 

 

2048
Nobuhide Tsuda
Sep-2014

概要

コンソールで動作する簡易な2048(下図は実行画面)をC++で書いたので、簡単に説明する。

本稿で解説する 2048 のソースコードは以下から取得できる。
ライセンスは CDDL 1.0 なので、自由に改変して再配布してOKだぞ。

2048 ソースコード

なお、オリジナル 2048 は MIT ライセンスでソースコードが公開されているが、本プログラムはそれを参照せず、 筆者が独自に実装したものなので、細部の仕様が少しことなる場合があるかもしれないのでご了承ください。

2048の遊び方

上下左右カーソルキーを押すと、盤面上のすべての数字ブロックがその方向に移動します。
同じ数字にぶつかると、ブロックが合体し、値が倍になります。

上下左右どちらかの方向に移動した場合、ランダムな位置に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[][] を参照して盤面を描画するぞ。


本プログラムで使ったテクニック