「棋譜」と「待った」をサポートする

「棋譜」を取って Scrool Bar でプレイを再現します。
また再現中の局面からプレイを続けることもできます。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プロジェクトの作成

  1. Miyama.cpp の先頭に次のコードを追加して下さい。
    NUM は手数のカウンタです。
        #define     ID_TIMER (WM_APP + 0)
    
        Miyama     *App= NULL;          // Miyama Object Class
        LPSTR       BmpFile= { "jewel.bmp" };
        POINT       pt;                 // CLICK の位置を記録
        short       NUM;                // T[] の次の記録位置
        char        Rule[]=
        { "三個の山に石が積まれています。\n"
          "この石を私とあなたが交互に取り除きます。\n"
          "一度に一つの山からであれば、幾つでも取り除くことができます。\n"
          "最後の石を取らされた方が負けです。"
        };
        
  2. WM_CREATE: で手数のカウンタを初期化します。
        	case WM_CREATE:
                App= new Miyama(hWnd,BmpFile);
                App->Start();
                NUM= 1;
                break;
        
  3. WM_LBUTTONDOWN: でマウスがクリックされた座標を調べて石を取り除きます。
    (App->down!=0 || (NUM&1)==0) はアニメーションの終了確認と手番の判定です。
    App->Log(NUM) で棋譜を取ります。
    NUM を指定した場合は「棋譜テーブルの NUM 番目」に格納され、次の格納位置は NUM+1 になります。
    コンピュータが勝ったとき「キャンセル」をクリックすると「再現モード」に入ります。
            case WM_LBUTTONDOWN:
                if (App->down!=0 || (NUM&1)==0)  break;
                pt.x= LOWORD(lParam);
                pt.y= HIWORD(lParam);
                if (App->ManPlay(&pt)==0)
                {   MessageBox(hWnd,"エラーです","確認", MB_OK);
                    return TRUE;
                }
                App->Log(NUM);
                if (App->Stone()==0)
                {   if (MessageBox(hWnd,"私の勝ちです(次 | 待った)","勝ち", MB_OKCANCEL | MB_ICONQUESTION)==IDOK)
                    {   App->Win_c++;
                        App->Start();
                        NUM= 1;
                        return TRUE;
                    }
                    else
                    {   App->Saigen(NUM);
                        return TRUE;
                    }
                }
                // コンピュータがプレイする
                App->Play();
                if (App->down<=0)  return TRUE;
                SetTimer(hWnd,ID_TIMER,500,NULL);
                return TRUE;
        
  4. WM_TIMER: で石を取り除くアニメーションを行います。
    アニメーションが終了すると App->Log() で棋譜を取ります。
    引数を省略した場合は「棋譜テーブルの次の位置」に格納され、現在の手数(次の格納位置)が返されます。
    SetScrollRange() と SetScrollPos() でScrollBar を設定します。
    コンピュータが負けたときは「再現モード」に入らずに、次のゲームを開始します。
            case WM_TIMER:
                if (App->CntDown())
                {   KillTimer(hWnd,ID_TIMER);
                    NUM= App->Log();
                    //スクロールバーの設定
                    SetScrollRange(GetDlgItem(App->hDlg,IDC_SCROLLBAR1),SB_CTL,0,NUM-1,TRUE);
                    SetScrollPos(GetDlgItem(App->hDlg,IDC_SCROLLBAR1),SB_CTL,NUM-1,TRUE);
                    if (App->Stone()==0)
                    {   MessageBox(hWnd,"私の負けです","負け", MB_OK);
                        App->Lose_c++;
                        App->Start();
                        NUM= 1;
                    }
                }
                return TRUE;
        
  5. WM_PAINT: に対戦成績と山の石を描画するコードを記述します。
        char    buf[16];
    
        case WM_PAINT:
            hdc = BeginPaint (hWnd, &ps);
            // TODO: この位置に描画用のコードを追加してください...
            wsprintf(buf,"%d",App->Win_c);
            SetDlgItemText(App->hDlg,IDC_WIN,buf);
            wsprintf(buf,"%d",App->Lose_c);
            SetDlgItemText(App->hDlg,IDC_LOSE,buf);
            App->Disp(hdc);
            EndPaint( hWnd, &ps );
            break;
        
  6. MyDlgProc() に「開始」ボタンと「説明」ボタンがクリックされたときのソースコードを記述します。
    WM_HSCROLL: に ScrollBar が操作されたときのソースコードを記述します。
    NUM に再現する局面の番号を設定して App->Saigen(NUM) で局面を表示します。
    SetScrollPos() で ScrollBar のポジションを設定します。
        //★ DialogBox の CALLBACK 関数
        LRESULT CALLBACK MyDlgProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
        {
            switch(msg)
            {   case WM_COMMAND:
                    switch(LOWORD(wp))
                    {   case IDC_END:       //終了  
                            PostMessage(hWnd,WM_CLOSE,0,0L);
                            return TRUE;
                        case IDC_RULE:      //説明
                            MessageBox(NULL,Rule,"Miyama",MB_OK);
                            break;
                        case IDC_START:     //開始
                            App->Start();
                            break;
                    }
                    break;
                case WM_HSCROLL:
                    switch(LOWORD(wp))
                    {   case SB_LINELEFT:   NUM--;     break;
                        case SB_LINERIGHT:  NUM++;     break;
                        case SB_PAGELEFT:   NUM-= 5;   break;
                        case SB_PAGERIGHT:  NUM+= 5;   break;
                        case SB_THUMBTRACK: NUM= (int)(HIWORD(wp)); break;
                    }
                    if (NUM<=0)          NUM= 1;
                    if (NUM>=App->CNT)   NUM= App->CNT;
                    App->Saigen(NUM);
                    SetScrollPos(GetDlgItem(App->hDlg,IDC_SCROLLBAR1),SB_CTL,NUM-1,TRUE);
                    break;
        
  7. プロジェクトの設定は 勝敗判定とゲームの繰り返し を参照して下さい。
    Dialog Box の設定は Dialog Box を表示する を参照して下さい。
    コンピュータが負けたとき「キャンセル」をクリックすると「再現モード」に入ります。
    また、ゲーム中に ScrollBar を操作して「再現モード」に入ることもできます。
    「再現モード」では ScrollBar の操作で過去の局面が再現されます。
    再現モード中に人間の手番で石をクリックすると、その局面からゲームを継続することができます。

[Next Chapter ↓] 「音楽」と「効果音」を鳴らす
[Previous Chapter ↑] Dialog Box に対戦成績を表示する

超初心者のプログラム入門(Win32API C++)