プログラミングU 第1回

プログラミングTの復習


チックタックトウ(○×ゲーム)のプログラムを作りながら, プログラミングTで習った諸事項の復習をする.

チックタックトウ
3×3の枡からなる盤に,2人のプレイヤーが交互に○と×を置いていく.
先に3つ一直線に並べた方が勝ちである.
× 
 ×
×
どちらも一直線に並べられなかったら,引き分けである.
×
×
××

プログラムは一度に完全なものを作るのではなく,徐々に組み立てていく.

プログラム1 TicTacToe1.dpr

まずは,盤を表すデータ構造を定義し,盤の初期状態をを書く.
データ構造を定義する.
        type
          TBangou = 1..9;                          // 部分範囲型
          TYouso  = (Kara,Maru,Batu);              // 列挙型
          TBan    = array [TBangou] of TYouso;     // 配列型
        var
          Ban : TBan;
       
盤は3×3の枡からなるが,9つの枡に1〜9の通し番号をつけて表している.
123
456
789

メインルーチン 大まかな流れをプロシージャの名前を並べて書く.
        begin {Main}
          BanSyokika;
          BanWoKaku;
          ReadLn;
        end.
       
個々のプロシージャを細かく(メインルーチンの上に)書く.
盤を初期化する(すべて空にする)プロシージャ
        procedure BanSyokika;                      // プロシージャ
                  {盤を初期化する}
          var
            N : TBangou;
          begin
            for N := 1 to 9 do                     // for ループ
              Ban[N] := Kara;
          end; {BanSyokika}
       
盤全体を書くプロシージャ
        procedure BanWoKaku;
                  {盤を書く}
          var
            N : TBangou;
          begin
            WriteLn;
            WriteLn('+−+−+−+');
            for N := 1 to 9 do
              begin
                Write('|');
                YousoWoKaku(N);
                if N mod 3 = 0                     // if 分岐
                  then begin
                         WriteLn('|');
                         WriteLn('+−+−+−+');
                       end;
              end;
          end; {BanWoKaku}
       
この中で使っているプロシージャをさらに細かく(この上に)書く.
1つの枡の要素を書くプロシージャ
        procedure YousoWoKaku(N : TBangou);
                  {Ban[N]を書く}
          begin
            case Ban[N] of                         // case 分岐
              Maru : Write('○':2);
              Batu : Write('×':2);
              Kara : Write('  ':2);
            end;
          end; {YousoWoKaku}
       
実行して空の盤が書かれることを確認する.
初期化ルーチンに,次の文を仮に追加して,○や×も書かれることを確認しよう.
        Ban[3] := Maru;
        Ban[7] := Batu;
       

プログラム2 TicTacToe2.dpr

2人のプレイヤーに,どこに置くか訊いて○と×を置いていく.
データ構造を追加する.
        type
          TBangou = 1..9;
          TYouso  = (Kara,Maru,Batu);
          TBan    = array [TBangou] of TYouso;
          TPlayer = Maru..Batu;                    // 部分範囲型
       
メインルーチンを変更.
        var
          Tesuu : Integer;                         // 何手目か
          Teban : TPlayer;                         // 手番のプレイヤー,○,×
          Basyo : TBangou;                         // 置く場所,1〜9
        begin {Main}
          BanSyokika;
          BanWoKaku;
          Tesuu := 0;                              // 手数を0に初期化する
          Teban := Batu;                           // 手番を×(後手)とする
          repeat                                   // repeat ループ
            Inc(Tesuu);                            // 手数を+1する
            WriteLn;
            Write(Tesuu, '手目: ');
            TebanKoutai(Teban);                    // 手番を交代する
            Basyo := OkuBasyo;                     // 置く場所を訊く
            Ban[Basyo] := Teban;                   // 置く
            BanWoKaku;                             // 盤を書く
          until Tesuu = 9;
          ReadLn;
        end.
       
ここで使われているプロシージャ,ファンクションを書く.
手番を交代するプロシージャ
        procedure TebanKoutai(var Player : TPlayer);
                  {手番を交代する}
          begin
            case Player of
              Maru : begin
                       Player := Batu;
                       WriteLn('×の番です');
                     end;
              Batu : begin
                       Player := Maru;
                       WriteLn('○の番です');
                     end;
            end;
          end; {TebanKoutai}
       
置く場所を人に訊いて,その場所を返すファンクション
        function  OkuBasyo : TBangou;
                  {どこに置くか人に訊く}
          var
            N : TBangou;
          begin
            Write('どこに置きますか [1〜9] ? ');
            ReadLn(N);
            while not (N in [1..9]) or (Ban[N] <> Kara) do  // while ループ
              begin                                         // 集合 [1..9]
                WriteLn('そこには置けません');
                Write('どこに置きますか [1〜9] ? ');
                ReadLn(N);
              end;
            Result := N;                                    // 返す値
          end; {OkuBasyo}
       
実行する.まだ,勝ち負けの判定をしないので,必ず9手するまで行う.

プログラム3 TicTacToe3.dpr

勝ち負けの判定を加える.
メインルーチンを変更
        var
          Tesuu : Integer;
          Teban : TPlayer;
          Basyo : TBangou;
          Katta : Boolean;                         // 勝ちが決まったかどうか
        begin
          BanSyokika;
          BanWoKaku;
          Tesuu := 0;
          Teban := Batu;
          repeat
            Inc(Tesuu);
            WriteLn;
            Write(Tesuu, '手目: ');
            TebanKoutai(Teban);
            Basyo := OkuBasyo;
            Ban[Basyo] := Teban;
            BanWoKaku;
            Katta := Naranda(Basyo);               // 勝ったかどうか調べる
          until (Tesuu = 9) or Katta;
          if Katta
            then WriteLn('勝ちました')
            else WriteLn('引き分けです');
          ReadLn;
        end.
       
新しく使われたファンクションを書く.
勝ったかどうか調べるファンクション
        function  Naranda(N : TBangou) : Boolean;
                  {N 番を含む列に同じマークが3つ並んだか調べる}
          begin
            case N of
              1 : Result := Onaji(1,2,3) or Onaji(1,4,7) or Onaji(1,5,9);
              2 : Result := Onaji(1,2,3) or Onaji(2,5,8);
              3 : ; // 完成させてください
              4 : ; // 完成させてください
              5 : ; // 完成させてください
              6 : ; // 完成させてください
              7 : ; // 完成させてください
              8 : ; // 完成させてください
              9 : ; // 完成させてください
            end;
          end; {Naranda}
       
さらに,この中で使われているファンクションを書く.
3つの枡に同じマークが入っているか調べるファンクション.
        function  Onaji(I,J,K : TBangou) : Boolean;
                  {Ban[I],Ban[J],Ban[K] に同じマークが入っているか調べる}
          begin
            Result := (Ban[J] = Ban[I]) and (Ban[K] = Ban[I]);
          end; {Onaji}
       
実行する.今度は,3つ並ぶと終了する.

このように,本格的なプログラムを書くときは,つぎのように作っていくことを心がけよう.
少しずつ徐々にふくらませていく.
1つのルーチンが何十行にもなると理解しにくくなるので, プロシージャ,ファンクションをうまく使ってコンパクトにまとめる.