Mesoscopic Programming

タコさんプログラミング専門

ヌメロン製作講座第14回:棋譜データグリッドの作成

プレイ画面のうち前回はプレイ情報画面のみを作成しました。
今回は棋譜データ画面を作成します。

  • 棋譜グリッド表示画面

修正ソースファイル
  1. Numer0n.h
  2. Numer0n.cpp
  3. main.h
  4. main.cpp


class RecGrid

棋譜データグリッドクラスです。

class RecGrid : public Grid
{
public :

    static const Cell base[ MAX_RECORD_CELL + 1 ];

    Cell cells[ MAX_RECORD_CELL * MAX_RECORD + 1 ];
    Cell * turnCell;
    Cell * moveCell;
    int  maxCell2;

    Cell * GetCells() { return cells; }
    VOID Init( HWND hWnd );
    VOID MakeGrid();
    VOID MakeGrid( BOOL attack, BOOL defense );
    VOID MakeTable( BOOL attack, BOOL defense );
    VOID AddTable();
};

内容は以下の通りです。

  1. base[ MAX_RECORD_CELL + 1 ]
    • 棋譜データグリッドのベースとなる1行分のセル定義データです。これをコピーして使います。
  2. cells[ MAX_RECORD_CELL * MAX_RECORD + 1 ]
    • 実際に使用するセル定義データです。
  3. turnCell
    • セル定義データを作成する際に、ターン番号を表示するセルを指すポインタです。
  4. moveCell
    • セル定義データを作成する際に、各手番の情報を表示するセルを指すポインタです。
  5. maxCell2
    • セル定義データ作成時に使用するワーク変数です。
  6. GetCells()
    • セル定義データアドレスを返します。
  7. Init( HWND hWnd )
    • 表示オフセットを変更するためにオーバーライドしています。
  8. MakeGrid()
    • セル定義データを動的に作成するためにオーバーライドしています。
  9. MakeGrid( BOOL attack, BOOL defense )
    • 攻撃アイテム選択の表示の有無、防御アイテム選択の表示の有無を指定してセル定義データを作成します。
  10. MakeTable( BOOL attack, BOOL defense )
    • 現在の棋譜データに基づいて動的にセル定義データを作成します。
  11. AddTable()
    • セル定義データに新しい行を追加します。

enum RecordCellID

棋譜データグリッドの1行分のセル内容を表す識別子です。

enum RecordCellID
{
    RECORD_CELL_NULL = -1,
    RECORD_CELL_TURN,
    RECORD_CELL_FIRST,
    RECORD_CELL_SECOND,
    RECORD_CELL_NEWLINE,
    MAX_RECORD_CELL
};

内容は以下の通りです。

  1. RECORD_CELL_TURN
    • ターン番号を表示するセルです。
  2. RECORD_CELL_FIRST
    • 先攻の棋譜データや入力メッセージを表示するセルです。
  3. RECORD_CELL_SECOND
    • 後攻の棋譜データや入力メッセージを表示するセルです。
  4. RECORD_CELL_NEWLINE
    • 改行です。

VOID RecGrid :: Init()

グリッドクラスの初期化メソッドのオーバーライドです。

VOID RecGrid :: Init( HWND hWnd )
{
    CopyMemory( cells, base, sizeof base );

    Grid :: Init( hWnd );

    SetOffset( app.infoGrid.offset.x, app.infoGrid.rect.bottom + app.infoGrid.offset.y + 4 );
}

セル定義データの1行目にベース定義データをコピーしてグリッドを初期化します。
表示オフセットをプレイ情報グリッドの直下になるように調整します。

VOID RecGrid :: MakeGrid()

グリッド作成メソッドのオーバーライドです。

VOID RecGrid :: MakeGrid()
{
    MakeGrid( TRUE, TRUE );
}

攻撃アイテム選択表示の有無、防御アイテム選択表示の有無を指定して固有のグリッド作成メソッドを実行します。

VOID RecGrid :: MakeGrid()

攻撃アイテム選択表示の有無、防御アイテム選択表示の有無を指定して棋譜データグリッドを作成します。

VOID RecGrid :: MakeGrid( BOOL attack, BOOL defense )
{
    MakeTable( attack, defense );

    Grid :: MakeGrid();
}

動的セル定義データを作成して基底クラスのグリッド作成メソッドを呼びます。

VOID RecGrid :: MakeTable()

セル定義データを動的に作成します。

VOID RecGrid :: MakeTable( BOOL attack, BOOL defense )
{
    BOOL    attacks[ MAX_MOVE ];
    BOOL    defenses[ MAX_MOVE ];

    MoveID  move        = MOVE_NULL;
    MoveID  move0       = move;
    DataID  did         = DATA_NULL;
    DataID  did0        = did;
    CellID  cid         = CELL_ATTACK;
    int     turn        = 0;
    int     doubling    = 0;
    BOOL    finish      = FALSE;

    for ( int move2 = 0; move2 < MAX_MOVE; move2++ )
    {
        attacks[ move2 ]    = attack;
        defenses[ move2 ]   = defense;

        for ( int item = 0;; item++ )
        {
            if ( item >= ITEM_SHUFFLE )
            {
                attacks[ move2 ] = FALSE;

                break;
            }
            else if ( numer0n.players[ move2 ].items[ item ] > 0 )
            {
                break;
            }
        }

        for ( int item = ITEM_SHUFFLE;; item++ )
        {
            if ( item >= MAX_ITEM )
            {
                defenses[ move2 ] = FALSE;

                break;
            }
            else if ( numer0n.players[ move2 ].items[ item ] > 0 )
            {
                break;
            }
        }
    }

    maxCell2 = 0;

    AddTable();

    turnCell->data = ++turn;

    for ( int n = 0; n < numer0n.maxRecord; n++ )
    {
        Record & record = numer0n.records[ n ];

        move0   = move;
        move    = record.move;
        did0    = did;
        did     = record.did;

        if ( did < DATA_ITEM_SHUFFLE )
        {
            if ( move0 != MOVE_NULL )
            {
                if ( move == MOVE_FIRST && move0 == MOVE_SECOND )
                {
                    AddTable();

                    turnCell->data = ++turn;
                }
                else if ( move == move0 )
                {
                    AddTable();

                    if ( ( did0 >= DATA_ITEM_SHUFFLE && did0 <= DATA_ITEM_CHANGE ) && move == MOVE_FIRST )
                    {
                        turnCell->data = ++turn;
                    }
                }
            }

            moveCell[ move ].cid    = CELL_RECORD;
            moveCell[ move ].data   = n;

            if ( did == DATA_CALL )
            {
                if ( record.call.eat == numer0n.maxColumn )
                {
                    finish = TRUE;

                    break;
                }
                else if ( doubling == 1 )
                {
                    doubling++;

                    cid         = CELL_CALL;
                    move0       = move;
                }
                else
                {
                    doubling    = 0;
                    cid         = CELL_DEFENSE;
                    move0       = move;
                }
            }
            else
            {
                if ( did == DATA_ITEM_DOUBLE )
                {
                    doubling    = 1;
                }

                cid     = CELL_CALL;
                move0   = move;
            }
        }
        else
        {
            if ( move == MOVE_SECOND )
            {
                AddTable();
            }

            move                    = Enemy( move );
            moveCell[ move ].cid    = CELL_RECORD;
            moveCell[ move ].data   = n;
            move0                   = move;
            cid                     = CELL_ATTACK;
        }
    }

    if ( ! finish )
    {
        if ( move == MOVE_NULL )
        {
            move0   = move;
            move    = MOVE_FIRST;
        }

        if ( cid == CELL_DEFENSE )
        {
            if ( ! defenses[ move ] )
            {
                move0   = move;
                move    = Enemy( move );
                cid     = CELL_ATTACK;
            }
        }

        if ( cid == CELL_ATTACK && ! attacks[ move ] )
        {
            cid = CELL_CALL;
        }

        if ( move0 != MOVE_NULL )
        {
            if ( move0 == MOVE_NULL )
            {
                move0 = move;
            }

            if ( move == MOVE_FIRST && move0 == MOVE_SECOND )
            {
                AddTable();

                turnCell->data = ++turn;
            }
            else if ( move == move0 )
            {
                AddTable();
            }
        }

        moveCell[ move ].cid = cid;
    }
}

現在の棋譜データをセル定義データとして展開します。
まだ勝敗がついていない場合は次の手番の入力プロンプトを表示します。

VOID RecGrid :: AddTable()

セル定義データに1行分の棋譜データ行を追加します。

VOID RecGrid :: AddTable()
{
    CopyMemory( & cells[ maxCell2 ], base, sizeof base );

    turnCell    = & cells[ maxCell2 + RECORD_CELL_TURN ];
    moveCell    = & cells[ maxCell2 + RECORD_CELL_FIRST ];

    moveCell[ MOVE_FIRST ].data     = EDIT_NULL;
    moveCell[ MOVE_SECOND ].data    = EDIT_NULL;

    maxCell2 += MAX_RECORD_CELL;
}

1行分のベースセル定義データをコピーしてセル定義データ数をカウントアップします。


  • ヌメロンクラス関係の修正点

Numer0n.h

以下のマクロを追加しました。

  1. MAX_RECORD マクロの定義
    • 最大棋譜データ数です。
  2. Enemy() マクロの定義
    • 手番識別子から相手の手番識別子を取得します。

class Numer0n

棋譜データ変数とメソッドを追加しました。

  1. Record records[ MAX_RECORD ];
  2. SHORT maxRecord;
  3. BOOL AddRecord( const Record & record );
    • 棋譜データ追加メソッドです。


  • セル構造体関係の修正点

enum CellID

以下の識別子を追加しました。

  1. CELL_RECORD
    • 棋譜データセルです。
  2. CELL_CALL
    • コール入力セルです。
  3. CELL_ATTACK
    • 攻撃アイテム選択入力セルです。
  4. CELL_DEFENSE
    • 防御アイテム選択入力セルです。

enum ParamID

以下の識別子を追加しました。

  1. PARAM_RECORD_TURN
    • ターン番号です。
  2. PARAM_RECORD_FIRST
    • 先攻棋譜データです。
  3. PARAM_RECORD_SECOND
    • 後攻棋譜データです。

enum EditModeID

棋譜データの入力では1つのセルに対して複数の項目を入力する必要があるので、現在の入力モードを示すための編集モード識別子を追加しました。

  1. EDIT_BEGIN
    • 初期状態です。
  2. EDIT_EAT
    • イート数入力中です。
  3. EDIT_BYTE
    • バイト数入力中です。
  4. EDIT_RANK
    • 位を選択中です。
  5. EDIT_HIGHLOW
    • ハイまたはローを選択中です。
  6. EDIT_HIGH
    • ハイの数を入力中です。
  7. EDIT_LOW
    • ローの数を入力中です。
  8. EDIT_DIGIT
    • カードの番号を入力中です。
  9. EDIT_SLASH
    • スラッシュナンバーを入力中です。
  10. EDIT_NUMBER
    • 設定ナンバー入力中です。
  11. EDIT_DIGIT2
    • チェンジ後のカード番号を入力中です。

struct Cell

以下のメンバ変数とメソッドを追加しました。

  1. SHORT data
    • 棋譜データ番号などのセル固有データを格納するための変数です。
  2. BOOL GetRecordText()
    • 棋譜データセルの表示文字列を取得します。


  • アプリケーションクラス関係の修正点

class Application

以下のメンバ変数を追加しました。

  1. RecGrid recGrid
    • 棋譜データグリッドオブジェクトです。
  2. Grid * playFocus
    • プレイ画面のフォーカス所有グリッドのアドレスです。

以上です。
次回は未定です。