program TicTacToe5; {チックタックトウ(○×ゲーム)} {学生証番号 氏名} {$APPTYPE CONSOLE} uses SysUtils; 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 var Ban : TBan; // 盤 Tesuu : Integer; // 手数(何手目か) Teban : TPlayer; // 手番(誰の番か) Basyo : TBangou; // 置く場所 Katta : Boolean; // (手番の選手が)勝った Computer : TPlayer; // コンピュータ(が○か×か) procedure BanSyokika; {盤を初期化する} var N : TBangou; begin for N := 1 to 9 do Ban[N] := Kara; end; {BanSyokika} procedure YousoWoKaku(N : TBangou); {Ban[N]の要素を書く} begin case Ban[N] of Maru : Write('○':2); Batu : Write('×':2); Kara : Write(' ':2); end; end; {YousoWoKaku} procedure BanWoKaku; {盤を書く} var N : TBangou; begin WriteLn('┌─┬─┬─┐'); for N := 1 to 9 do begin Write('│'); YousoWoKaku(N); if N in [3,6] then begin WriteLn('│'); WriteLn('├─┼─┼─┤'); end; end; WriteLn('│'); WriteLn('└─┴─┴─┘'); end; {BanWoKaku} function OkuBasyo : TBangou; {どこに置くか人に訊く} var N : TBangou; begin Write('どこに置きますか [1〜9] ? '); ReadLn(N); while not (N in [1..9]) or (Ban[N] <> Kara) do begin WriteLn('そこには置けません'); Write('どこに置きますか [1〜9] ? '); ReadLn(N); end; Result := N; end; {OkuBasyo} procedure TebanKoutai(var Player : TPlayer); {手番を交代する} begin Player := Aite[Player]; if Player = Batu then WriteLn('×の番です') else WriteLn('○の番です'); end; {TebanKoutai} 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} 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 : Result := Onaji(1,2,3) or Onaji(3,6,9) or Onaji(3,5,7); 4 : Result := Onaji(4,5,6) or Onaji(1,4,7); 5 : Result := Onaji(4,5,6) or Onaji(2,5,8) or Onaji(1,5,9) or Onaji(3,5,7); 6 : Result := Onaji(4,5,6) or Onaji(3,6,9); 7 : Result := Onaji(7,8,9) or Onaji(1,4,7) or Onaji(3,5,7); 8 : Result := Onaji(7,8,9) or Onaji(2,5,8); 9 : Result := Onaji(7,8,9) or Onaji(3,6,9) or Onaji(1,5,9); else Result := False; // 必要ないが,警告が出なくなる end; end; {Naranda} procedure SenteWoKimeru; (* どちらが先手か決める *) var YesNo : String; begin Write('コンピュータが先手でいいですか [y(Yes) / y以外(No)] ? '); ReadLn(YesNo); if YesNo = 'y' then Computer := Maru else Computer := Batu; end; {SenteWoKimeru} 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} 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} function ComputerNoTe : TBangou; {置く場所をコンピュータが選ぶ} var YoiBasyo : TBangou; begin YoiBasyo := YoiBasyoWoSagasu; if YoiBasyo > 0 then Result := YoiBasyo else Result := DetarameNiErabu; end; {ComputerNoTe} var YesNo : String; // 終了するかに対する返答 begin {Main} Randomize; repeat 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('引き分けです'); WriteLn; Write('終了しますか [y(Yes)/y以外(No)] ? '); ReadLn(YesNo); until YesNo = 'y'; end.