190 likes | 346 Views
プログラミング Ⅱ 第3回. TicTacToe のバージョンアップ. TicTacToe4. コンピュータ VS 人 の対戦型にする 先手をどちらにするか訊いて決める コンピュータの手をランダムに決める. メインルーチンを変更. 今までメインルーチンのすぐ上にあった変数宣言を,最上部の他の変数宣言と一緒にまとめる. コンピュータが先手(○)か後手( × )かを示す変数 Computer : TPlayer を追加する.. var Ban : TBan; Tesuu : Integer;
E N D
プログラミングⅡ 第3回 TicTacToe のバージョンアップ
TicTacToe4 コンピュータ VS 人 の対戦型にする 先手をどちらにするか訊いて決める コンピュータの手をランダムに決める
メインルーチンを変更 今までメインルーチンのすぐ上にあった変数宣言を,最上部の他の変数宣言と一緒にまとめる. コンピュータが先手(○)か後手(×)かを示す変数 Computer : TPlayer を追加する. var Ban : TBan; Tesuu : Integer; Teban : TPlayer; Basyo : TBangou; Katta : Boolean; Computer : TPlayer; // コンピュータ(が○か×か)
メインルーチンを変更 begin {Main} SenteWoKimeru; // どちらが先手か決める BanSyokika; BanWoKaku; Tesuu := 0; // 手数を0に初期化する Teban := Batu; // 手番を×(後手)とする repeat Inc(Tesuu); // 手数を+1する WriteLn; Write(Tesuu, '手目: '); TebanKoutai(Teban); // 手番を交代する if Teban = Computer then Basyo := ComputerNoTe // 置く場所をコンピュータが決める else Basyo := OkuBasyo; // 置く場所を訊く Ban[Basyo] := Teban; // 置く BanWoKaku; // 盤を書く Katta := Naranda(Basyo); // 勝ったかどうか調べる until (Tesuu = 9) or Katta; if Katta then WriteLn('勝ちました') else WriteLn('引き分けです'); ReadLn; end.
注意 これ以降,プロシージャやファンクションを追加していきますが,どこに書くか考えて正しい位置に追加してください.
プロシージャ SenteWoKimeru procedure SenteWoKimeru; (* どちらが先手か決める *) var YesNo : String; begin Write('コンピュータを先手(○)にしますか [y(Yes) / y以外(No)] ? '); ReadLn(YesNo); if YesNo = 'y' then Computer := Maru else Computer := Batu; end; {SenteWoKimeru} コンピュータを先手にするか後手にするか,人に選んでもらう. 後手を選ぶことが多いので, 先手を選ぶときは y 後手を選ぶときは y以外 を入れればよいようにする.
ファンクション ComputerNoTe function ComputerNoTe : TBangou; {置く場所をコンピュータが選ぶ} begin Result := DetarameNiErabu; end; {ComputerNoTe} コンピュータが置く場所を決める. とりあえず,ランダムに空桝を選ぶ.
ファンクション DetarameNiErabu 1~n(残っている空桝の個数) の乱数をrとする. 1番目から桝を調べていき,空ならrを1減らす. rが0になったときの桝を選ぶ. function DetarameNiErabu : TBangou; {でたらめに選ぶ} var R,K : TBangou; begin R := Random(10-Tesuu)+1; // r=1~空枡の個数 の乱数 // 空枡のうちr番目を選ぼう K := 0; // k=0に初期設定する repeat Inc(K); // kを1増やす(次の枡を調べる) if Ban[K] = Kara // 空枡だったらrを1減らす then Dec(R); until R = 0; // r=0になるまで繰り返す Result := K; // Ban[k]がr番目の空枡 end; {DetarameNiErabu}
ファンクション DetarameNiErabu 前ページのプログラムの中で,変数 K,R の値が0になることがあります. 0は実際の番号ではないのですが,TBangou に含めることにします. type TBangou = 0..9; // 枡につけた通し番号,0は便宜上 TYouso = (Kara,Maru,Batu); // 枡の要素=(空,○,×) TBan = array [1..9] of TYouso; // 盤=9つの枡(3×3) TPlayer = Maru..Batu; // 選手=(○,×)
実行する コンピュータはでたらめに置いていくので弱いでしょう. ところで何回やってもコンピュータは同じ置き方をするのに気がつきましたか. 「でたらめ」というのに変ですね. いつも同じ乱数系列を使うからなのです. 乱数系列を変える Randomize をメインルーチンに追加します. begin {Main} Randomize; SenteWoKimeru; // どちらが先手か決める
TicTacToe5 3つ並ぶ場合を考慮して決める 優先度 • 自分のこまが3つ並ぶように置ける場所があればそこを選ぶ-勝つ手 • 相手のこまが3つ並ぶように置ける場所があればそこを選ぶ-負けない手 • ランダムに選ぶ
プロシージャ TebanKoutai 配列定数Aite を使って簡単にする. 定数を定義する. type TBangou = 0..9; // 枡の通し番号,0は特殊 TYouso = (Kara,Maru,Batu); // 枡の要素=(空,○,×) TBan = array [TBangou] of TYouso; // 盤=9つの枡(3×3) TPlayer = Maru..Batu; // 選手=(○,×) const Aite : array [TPlayer] of TPlayer // 配列定数 = (Batu,Maru); // Aite[Maru]=Batu, // Aite[Batu]=Maru
プロシージャ TebanKoutai 配列定数Aite を使って簡単にする. TebanKoutai を変更する procedure TebanKoutai(var Player : TPlayer); {手番を交代する} begin Player := Aite[Player]; if Player = Batu then WriteLn('×の番です') else WriteLn('○の番です'); end; {TebanKoutai}
ファンクション ComputerNoTe 善い手を選ぶようにする. function ComputerNoTe : TBangou; {置く場所をコンピュータが選ぶ} var YoiBasyo : TBangou; begin YoiBasyo := YoiBasyoWoSagasu; if YoiBasyo > 0 then Result := YoiBasyo else Result := DetarameNiErabu; end; {ComputerNoTe}
ファンクション YoiBasyoWoSagasu 勝つあるいは負けを防ぐ場所を探して, あったらその場所を答えます. なかったら0を答えます.
function YoiBasyoWoSagasu : TBangou; {善い場所を探す} var Katu : TBangou; // 自分のこまが3つ並ぶ場所 Makenai : TBangou; // 相手のこまが3つ並ぶ場所(を防ぐ) Basyo : TBangou; begin Katu := 0; Makenai := 0; Basyo := 0; repeat Inc(Basyo); if Ban[Basyo] = Kara then begin Ban[Basyo] := Computer; // 自分のこまを置いてみる if Naranda(Basyo) // 3つ並べば勝ち then Katu := Basyo; Ban[Basyo] := Aite[Computer]; // 相手のこまを置いてみる if Naranda(Basyo) // 3つ並べば負け then Makenai := Basyo; Ban[Basyo] := Kara; // 元に戻す end; until (Basyo = 9) or (Katu > 0); // 勝つ手が見つかれば終わる if Katu > 0 then Result := Katu else Result := Makenai; // 負けない手もなければ0 end; {YoiBasyoWoSagasu}
実行 このゲームは両者が最善手を選べば引き分けになります. しかし,コンピュータは最善手を選ぶようにはなっていないので,人が勝つ可能性があります. さあ,あなたはどのくらい勝てるでしょうか. まさか負けることはないでしょうね.
問題 繰り返し実行できるように,メインルーチンを変更してください. 1回ゲームが終わったら 終了しますか [y(Yes) / y以外(No)] ? と訊いて,y以外を入れたら繰り返すようにしてください.
問題 勝負がついたとき(引き分けでないとき),今は, 勝ちました と,主語(手番の選手)を省略して書きますが, あなたが勝ちました または あなたが負けました と,人を主語にして書くように変更してください.