program TicTacToe4; {チックタックトウ(○×ゲーム)} {学生証番号 氏名} {$APPTYPE CONSOLE} uses SysUtils; type TBangou = 0..9; // 枡につけた通し番号,0は便宜上 TYouso = (Kara,Maru,Batu); // 枡の要素=(空,○,×) TBan = array [1..9] of TYouso; // 盤=9つの枡(3×3) TPlayer = Maru..Batu; // 選手=(○,×) 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 if Player = Maru then begin Player := Batu; WriteLn('×の番です'); end else begin Player := Maru; WriteLn('○の番です'); end; 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 : Char; 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 : Integer; 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 ComputerNoTe : TBangou; {置く場所をコンピュータが選ぶ} begin Result := DetarameNiErabu; end; {ComputerNoTe} begin {Main} Randomize; 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.