コンピュータに手を選択させるように変更してみましょう。
単純な選択方法として、乱数を使って選択させる方法があります。知能のかけらもありませんが。^^;
手順としては
となります。
サブルーチン# 手の選択サブルーチン sub select { my $b=@_; while (1) { $number=int(rand(8)); # 0から8の乱数を発生 if ($b[$number]==0) { return $number } # 重複チェック } }メインルーチンの修正# 乱数初期化(Perlのバージョンによっては必要ない srand(time());# メインループ for ($i=0; $i<9; $i++) { if ( ($i % 2) ==0 ) { $b[&select(@b)]=1; # 先手を&selectで選ぶように変更 } else { $b[&input(@b)]=-1; # 後手 } &print_board(@b); if (&check_winner(@b)!=0) { last; } }
ゲームの勝敗のルールから、「3目並べれば勝ち。3目並べられれば負け。」なのですから、戦略として
- 自分で3目並べられる場所には、その場所に置く。
- 相手に3目並べられる場所には、その場所に置く。
の2つが上げられます。このような規則を戦略的規則といいます。
手順としては
- 勝ちになるマスがあるかマス目を順に調べる。
- 空きマスかどうか調べ、空いてなければ次のマスに。
- ○を置いた状態で勝敗チェックをし、ボードから取り除く。勝ちならばマス目の番号を返す。
- 次のマスに。
- 負けになるマスがあるかマス目を順に調べる。
- 空きマスかどうか調べ、空いてなければ次のマスに。
- ×を置いた状態で勝敗チェックをし、ボードから取り除く。負けならばマス目の番号を返す。
- 次のマスに。
- 1.、2.で決まらなければとりあえず乱数で。^^;
となります。
# 手の選択サブルーチン sub select { my @b=@_; my $i; for ($i=0; $i<9; $i++) { # 勝ちマスチェック if ($b[$i]==0) { $b[$i]=1; if (&check_winner(@b)==1) { $b[$i]=0; return $i; } else { $b[$i]=0; } } } for ($i=0; $i<9; $i++) { # 負けマスチェック if ($b[$i]==0) { $b[$i]=-1; if (&check_winner(@b)==-1) { $b[$i]=0; return $i; } else { $b[$i]=0; } } } while (1) { $number=int(rand(8)); # 0から8の乱数を発生 if ($b[$number]==0) { return $number } # 重複チェック } }
# 盤面初期化
for ($i=0; $i<9; $i++) {
$b[$i]=0;
}
# メインループ
for ($i=0; $i<9; $i++) {
if ( ($i % 2) ==0 ) {
$b[&select(@b)]=1; # 先手
} else {
$b[&input(@b)]=-1; # 後手
}
&print_board(@b);
if (&check_winner(@b)!=0) {
last;
}
}
# 勝敗表示
if (&check_winner(@b)==1) {
print "○の勝ち!\n";
} elsif (&check_winner(@b)==-1) {
print "×の勝ち!\n";
} else {
print "引き分け!\n";
}
# 手の選択サブルーチン
sub select {
my @b=@_;
my $i;
for ($i=0; $i<9; $i++) { # 勝ちマスチェック
if ($b[$i]==0) {
$b[$i]=1;
if (&check_winner(@b)==1) {
$b[$i]=0;
return $i;
} else {
$b[$i]=0;
}
}
}
for ($i=0; $i<9; $i++) { # 負けマスチェック
if ($b[$i]==0) {
$b[$i]=-1;
if (&check_winner(@b)==-1) {
$b[$i]=0;
return $i;
} else {
$b[$i]=0;
}
}
}
while (1) {
$number=int(rand(8)); # 0から8の乱数を発生
if ($b[$number]==0) { return $number } # 重複チェック
}
}
# 盤面表示サブルーチン
sub print_board {
my @b=@_;
my $i;
for ( $i=0; $i<9; $i++ ) {
if ( $b[$i]==1 ) {
print "○";
} elsif ( $b[$i]==-1 ) {
print "×";
} else {
print " ";
}
if ( ($i==2) || ($i==5) || ($i==8) ) {
print "\n";
}
}
}
# 勝敗チェックサブルーチン
sub check_winner {
my @b=@_;
my $i;
for ( $i=0; $i<3; $i++ ) {
if ( $b[$i*3+0]+$b[$i*3+1]+$b[$i*3+2]==3 ) {
return 1;
} elsif ( $b[$i*3+0]+$b[$i*3+1]+$b[$i*3+2]==-3 ) {
return -1;
}
}
for ( $i=0; $i<3; $i++ ) {
if ( $b[0+$i]+$b[3+$i]+$b[6+$i]==3 ) {
return 1;
} elsif ( $b[0+$i]+$b[3+$i]+$b[6+$i]==-3 ) {
return -1;
}
}
if ( $b[0]+$b[4]+$b[8]==3 ) {
return 1;
} elsif ( $b[0]+$b[4]+$b[8]==-3 ) {
return -1;
}
if ( $b[2]+$b[4]+$b[6]==3 ) {
return 1;
} elsif ( $b[2]+$b[4]+$b[6]==-3 ) {
return -1;
}
return 0;
}
# 入力サブルーチン
sub input {
my @b=@_;
my $number;
while () { # 無限ループ
print "012\n";
print "345\n";
print "678\n";
print "0-8の数字をいれてください。";
$number=<stdin>;
chomp($number);
if ($number>=0 && $number<=8) { # 数字チェック。文字列も0として通ってしまう。TT
if ($b[$number]!=0) { # 重複チェック
print "そのマスはすでに入力済みです。\n";
} else {
return $number;
}
} else {
print "入力が正しくありません。";
}
}
}