リバーシ(ボードゲーム)
#! /usr/local/bin/perl
loadForm(); #フォームデータ取り込み
loadData(); #データ処理
printData(); #HTML出力
exit;
#====================================================================#データ処理
sub loadData
{
my ($i, $max, $no, $color);
if($FORM{'lv'} eq "") {
$FORM{'lv'} = "1";
}
if($FORM{'data'}) {
$DATA = $FORM{'data'};
if($FORM{'no'} eq "" or $FORM{'no'} eq "pass") { #コンピュータの一手
$NEXT = "use";
if($FORM{'no'} eq "pass") { #パスの場合 手詰りチェック
for($i = 0 ; $i < length($DATA) ; $i++) {
if(substr($DATA, $i, 1) eq "0" and changeData($i, $FORM{'color'})) {
$MSG = "エラー:パスできません。";
return;
}
}
}
if($FORM{'color'} eq "1") {
$color = "2";
}
else {
$color = "1";
}
for($i = 0 ; $i < length($DATA) ; $i++) {
if(substr($DATA, $i, 1) eq "0") { #反転枚数チェック
my $count = changeData($i, $color);
if($count > 0) {
$count = checkLv($i, $color, $count); #レベルごとの評価
$count += (rand 0.1);
if($count > $max) { #反転枚数最大チェック
$max = $count;
$no = $i;
}
}
}
}
if($no eq "") { #手詰りの場合 パス
if($FORM{'no'} eq "pass") {
gameOver(); #互いにパスの場合 ゲームオーバー
}
else {
$MSG = "コンピュータ:パス";
}
return;
}
else {
changeData($no, $color, 1); #ひっくり返す
}
}
else { #プレイヤーの一手
$NEXT = "com";
if(!changeData($FORM{'no'}, $FORM{'color'}, 1)) { #ひっくり返す(枚数チェック)
$NEXT = "use"; #0枚の場合 エラー
$DATA = $FORM{'data'};
$MSG = "エラー:手詰りの場合パスしてください。";
return;
}
}
if(!($DATA =~ /0/) or !($DATA =~ /1/) or !($DATA =~ /2/)) {
gameOver(); #ゲームオーバー
}
}
else { #ゲームスタート
$DATA = "0000000000000000000000000001200000021000000000000000000000000000";
$FORM{'color'} = int(rand 2) + 1; #色を決める
if($FORM{'color'} == 1) { #2が先手(白)
$NEXT = "com";
}
else {
$NEXT = "use";
}
}
}
#====================================================================レベルごとの評価
sub checkLv
{
my ($i, $j);
my @check = ( [0, 1, 8, 9], [7, 6, 14, 15],
[56, 48, 49, 57], [63, 54, 55, 62] ); #チェック箇所
if($FORM{'lv'} eq "2" or $FORM{'lv'} eq "3") { #レベル2・3
for($i = 0 ; $i < @check ; $i++) {
if($_[0] == $check[$i][0]) {
$_[2] += 4; #プラス評価
return $_[2];
}
if($FORM{'lv'} eq "3") { #レベル3
for($j = 1 ; $check[$i][$j] ; $j++) {
if($_[0] == $check[$i][$j]) {
if(substr($DATA, $check[$i][0], 1) eq $_[1]) {
$_[2] += 3; #プラス評価
}
elsif(substr($DATA, $check[$i][0], 1) eq "0") {
$_[2] /= 5; #マイナス評価
}
else {
$_[2] /= 2; #マイナス評価
}
return $_[2];
}
}
}
}
}
return $_[2];
}
#====================================================================反転・枚数チェック
sub changeData
{
my ($i, $n, $count);
my @check = (-9, -1, 7, 8, -8, -7, 1, 9); #チェック箇所
if($_[2]) {
substr($DATA, $_[0], 1, $_[1]); #反転
}
for($i = 0 ; $i < @check ; $i++) { #反転箇所を探す
for($n = $_[0] + $check[$i] ;; $n += $check[$i]) {
if($i <= 2 and $n % 8 == 7) {
last;
}
if($i >= 5 and $n % 8 == 0) {
last;
}
if($n < 0 or $n >= length($DATA)) {
last;
}
if(substr($DATA, $n, 1) eq "0") {
last;
}
if(substr($DATA, $n, 1) eq $_[1]) {
for($n -= $check[$i] ; $n != $_[0] ; $n -= $check[$i]) {
if($_[2]) {
substr($DATA, $n, 1, $_[1]); #反転
}
$count++; #反転枚数+1
}
last;
}
}
}
return $count; #反転枚数を返す
}
#====================================================================ゲームオーバー・点数集計
sub gameOver
{
my ($i, $com, %point);
my $use = $FORM{'color'};
$NEXT = "end";
if($use eq "1") {
$com = "2";
}
else {
$com = "1";
}
for($i = 0 ; $i < length($DATA) ; $i++) { #点数集計
$point{substr($DATA, $i, 1)}++;
}
if($point{$use} > $point{$com}) { #勝敗チェック
$MSG = "WIN"
}
elsif($point{$use} < $point{$com}) {
$MSG = "LOSE"
}
else {
$MSG = "DRAW"
}
$MSG .= sprintf(" %d - %d", $point{$use}, $point{$com});
}
#====================================================================HTML出力
sub printData
{
if($FORM{'color'} eq "1") {
$USE = "●";
$COM = "<font color=\"#ffffff\">●</font>";
}
else {
$USE = "<font color=\"#ffffff\">●</font>";
$COM = "●";
}
print qq(Content-type: text/html; charset=UTF-8\n\n);
print <<" END";
<!DOCTYPE html>
<html>
<head>
END
if($NEXT eq "com") {
print <<" END";
<meta http-equiv="refresh"
content="2;url=$ENV{'SCRIPT_NAME'}?data=$DATA&color=$FORM{'color'}&lv=$FORM{'lv'}">
END
}
print <<" END";
<title>リバーシ</title>
<style type="text/css">
<!--
table { margin-bottom:10px; width:400px; background:#6c6; border:1px solid #666 }
th { padding:3px; background:#99f }
td { width:12%; height:50px; font-size:40px; text-align:center; border:1px solid #666 }
td a { width:100%; height:100% }
a { text-decoration:none }
.msg { padding:3px; color:red; font-size:25px; font-weight:bold; text-align:center }
//-->
</style>
</head>
<body>
<table cellspacing="0" align="center">
<tr>
<th colspan="4" align="left"></th>
<th colspan="4" align="right">
END
if($NEXT eq "com") {
print <<" END";
<a href="$ENV{'SCRIPT_NAME'}?data=$DATA&color=$FORM{'color'}&lv=$FORM{'lv'}">コンピュータ</a>
END
}
else {
print <<" END";
コンピュータ
END
}
print <<" END";
[ Lv$FORM{'lv'} ] $COM
</th>
</tr>
</table>
<table cellspacing="0" align="center">
END
for($i = 0 ; $i < length($DATA) ; $i++) {
if($i % 8 == 0) {
print qq(<tr>\n);
}
if(substr($DATA, $i, 1) eq "0") {
if($NEXT eq "use") {
print <<" END";
<td>
<a href="$ENV{'SCRIPT_NAME'}?data=$DATA&color=$FORM{'color'}&lv=$FORM{'lv'}&no=$i"> </a>
</td>
END
}
else {
print <<" END";
<td> </td>
END
}
}
elsif(substr($DATA, $i, 1) eq $FORM{'color'}) {
print qq(<td>$USE</td>\n);
}
else {
print qq(<td>$COM</td>\n);
}
if(($i + 1) % 8 == 0) {
print qq(</tr>\n);
}
}
print <<" END";
</table>
<table cellspacing="0" align="center">
<tr>
<th colspan="4" align="left">$USE プレイヤー</th>
<th colspan="4" align="right">
[
END
if($NEXT eq "use") {
print <<" END";
<a href="$ENV{'SCRIPT_NAME'}?data=$DATA&color=$FORM{'color'}&lv=$FORM{'lv'}&no=pass">
パス
</a>
END
}
else {
print <<" END";
パス
END
}
print <<" END";
]
[再スタート
<a href="$ENV{'SCRIPT_NAME'}">Lv1</a>
<a href="$ENV{'SCRIPT_NAME'}?lv=2">Lv2</a>
<a href="$ENV{'SCRIPT_NAME'}?lv=3">Lv3</a>
]
</th>
</tr>
</table>
<div class="msg">$MSG</div>
</body>
</html>
END
}
#====================================================================フォームデータ取り込み
sub loadForm
{
my ($query, $pair);
if($ENV{'REQUEST_METHOD'} eq 'POST') {
read(STDIN, $query, $ENV{'CONTENT_LENGTH'});
}
else {
$query = $ENV{'QUERY_STRING'};
}
foreach $pair (split(/&/, $query)) {
my ($key, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%([0-9a-fA-F][0-9a-fA-F])/chr(hex($1))/eg;
$FORM{$key} = $value;
}
}
〔 実行する 〕