[PR]50IwZ]E:iヤ猝炸賞歡

ココのジャンケン・ポン

=Perl, =結果


ジャンケンって単純で作りやすいかな? と思って作ってみました。でも作り始めると、意外に苦労してしまいました。単純すぎて、こうしたいとか、あれもしたいと考えだけが膨らんでしまいました。

 CGIを実行しますココのジャンケン・ポン


ジャンケンは乱数を使ってコンピュータのグーチョキパーを決めればいいですよね。相手は入力フォームから選択してもらえばいいですね。

$coco_jyan = int(rand(3));

これで0か1か2の三種類の値が乱数で得られますから、それぞれをグー=0, チョキ=1, パー=2 に当てはめれば出来上がりです。

でも、これでは1回戦しかできませんから、せめて5回戦くらいにしたいですね。ジャンケン経過のファイルを作って、そこに毎回書き込めばいいのでしすが、それほどの内容でもありませんのでCGIに結果データを渡すことにしました。

それから何勝何敗かも途中表示したいから、毎回の両者の選択内容もCGIに渡す必要がありますね。
5回までの勝ち負けの経過もあると便利ですよね。勝ったほうのジャンケンを色付きで表示します。

前置きが長くなってしまいました。これからPerlのスクリプトを示していきます。

#!/usr/local/bin/perl

###############################
#FORMからの文字を取得
require 'stdin.txt';
###############################
#初期設定
@jyanken = ("グー", "チョキ", "パー");
$aite_flg = 0;#START時の設定
$images1 = "../images/sancoco_l.jpg";#INPUT画面の写真
$images2 = "../images/gu_l.gif";#グーの画像
$images3 = "../images/cyoki_l.gif";#チョキの画像
$images4 = "../images/pa_l.gif";#パーの画像

[#FORMからの文字を取得]の require は「決り文句を呼び込む」、
【→Perl Reference: require
stdin.txt については「テキストの色替え」のPOSTとGETを参照してください。入力フォームから送られてくるデータを受取る際の取り決めをしている、スクリプトを読み込んでいます。
[#初期設定]部分は#の後ろに説明を付けておきました。写真を自分の環境に合わせて使ってください。
###############################
#ジャンケン選択の取得
$jyan = $FORM{'jyan'};#相手が選択したジャンケン
$kaisu = $FORM{'kai'};#何回目のジャンケンか
@coco_jyanken = $FORM{'c'};#ココのジャンケン内容
@aite_jyanken = $FORM{'a'};#相手のジャンケン内容
$coco_kachi = $FORM{'ck'};#ココの勝ち数
$aite_kachi = $FORM{'ak'};#相手の勝ち数
###############################
#HTMLタイトル表示
print "Content-type: text/html\n\n";
$title = "ココとジャンケン・ポン";
require './heder.txt';
print "<center>";
print "<h2>ココとジャンケン・ポン</h2>";
print "</center>";
[#ジャンケン選択の取得]部分は入力フォームから送られてくるデータを変数に代入するものです。 [#HTMLタイトル表示]部分ではHTML文の<title>タイトル内容</title>部分などのヘッダー部分などです。
###############################
#ジャンケン・メイン処理
&kaisu_handan;#5回戦のうち何回目かの判断ルーチンへ
&kaisu_chk;#回数の判断ルーチンへ
&input_rtn;#対戦相手のジャンケン入力ルーチンへ
print qq|
<table border="0" bgcolor="#DDFFDD"><tr><td>
|;
&kaisu_disp;#回数毎の表示ルーチンへ
print qq|
</table>
<p align="right"><font size="-1">このページの解説は
<a href="../l_jyanken.html">こちら→</a></font></p>
|;
require './fotter.txt';

exit;
[#ジャンケン・メイン処理]という割には何もしていません。 "&xxxxx" で各々のサブルーチンに飛ばしています。"&xxxxx" ではスクリプトの中の "sub xxxxx{ }"部分を実行します。
"print qq| |" は「画面に文字を表示しよう」を参照してください。
ココから先はサブルーチン部分です。
###############################
#ゲーム開始前の判断&経過表示
sub kaisu_handan{
if ($kaisu eq ""){#ゲーム開始前処理
   $kaisu = 0;#アイコを除いた対戦数
   $coco_kachi = 0;#ココの勝ち数
   $aite_kachi = 0;#あなたの勝ち数
} else {
   &get_rand;#乱数発生のサブルーチンへ
   &jyanken_handan;#ジャンケン判断のサブルーチンへ
}
}
[#ゲーム開始前の判断&経過表示]は先ほどの[#ジャンケン・メイン処理]から呼び出されたサブルーチンです。初めて"l_janken.cgi"を呼び出されたのか、それとも続けて5回戦の途中なのかを判断しています。初めてなら初期設定をして、そうでなければ[#乱数発生のサブルーチンへ]飛び、その後[#ジャンケン判断のサブルーチンへ]の処理をします。
###############################
#回数による表示の設定
sub kaisu_chk{
if ($kaisu < 1 and $aiko ne 1) {#ジャンケン開始以前
   $disp_msg1 = "それでは第一回戦です。<br>5回戦ですからね!";
} elsif ($jyan eq "") {#グー・チョキ・パー無選択の処理
   $disp_msg1 = "<p>グー・チョキ・パーを選んでから押してください</p>";
}
}
このサブルーチンでは、一番最初に"l_janken.cgi"が呼び出されたときの表示と"アイコ"の時の表示部分です。
###############################
#回数による表示
sub kaisu_disp{
if ($kaisu eq 0 and $aiko ne 1 or $jyan eq "") {
   print $disp_msg1;
} elsif ($aiko ne 1) {
   print "第$kaisu戦は";
   &printm;
   print "\n<br>", $disp_msg1;
} elsif ($aiko eq 1) {
   &printm;
   print "\n<br>", $disp_msg1;
}   
print "<br>\n<center><font size=\"+1\"><b>$disp_msg2</b></font><center>\n";

if ($kaisu eq 5){
   print "<hr>5回戦終了です。結果はココの$coco_kachi勝$aite_kachi負です。
   <br>\n";
   if ($coco_kachi > $aite_kachi){
      print qq|
可哀想だから<a href="./l_jyanken.cgi">もう一回</a>遊んであげようか?
|;
   }else{
      print qq|
悔しい!! お願い!<a href="./l_jyanken.cgi">もう一回</a>
      |;
   }
}
}
このサブルーチンでは、ココのメッセージを表示する部分です。初めての場合や5回戦の途中ごとの表示、5回戦った後のメッセージを判断しています。メッセージの内容は $disp_msg1 は先ほどの[#回数による表示の設定]、 $disp_msg2 はこの後に出てくる[#ジャンケン判断]のサブルーチンで設定されています。
###############################
#対戦相手のジャンケン入力・対戦経過置換え・表示
sub input_rtn{
#対戦相手のジャンケン入力
print qq|
<center>
</td><td>
<table border="0"><tr><td>
<table border="1"><tr>
<form action="./l_jyanken.cgi" method="post">
<td rowspan="3" valign="center" background="$images1">
<br><br>
<input type="submit" value="ジャンケンポン"></td>
<td><input type="radio" name="jyan" value="0"></td>
<td><img src="$images2" alt="グー"></td></tr>
<tr><td><input type="radio" name="jyan" value="1"></td>
<td><img src="$images3" alt="チョキ"></td></tr>
<tr><td><input type="radio" name="jyan" value="2"></td>
<td><img src="$images4" alt="パー"></td></tr>
|;
if ($kaisu > 4){
   print qq|
   <input type="hidden" name="kai" value="0">
   <input type="hidden" name="c" value="">
   <input type="hidden" name="a" value="">
   <input type="hidden" name="ck" value="0">
   <input type="hidden" name="ak" value="0">
   </form>
   </table>
   |;
} else {
   print qq|
   <input type="hidden" name="kai" value="$kaisu">
   <input type="hidden" name="c" value="@coco_jyanken">
   <input type="hidden" name="a" value="@aite_jyanken">
   <input type="hidden" name="ck" value="$coco_kachi">
   <input type="hidden" name="ak" value="$aite_kachi">
   </form>
   </table>
   |;
}
このサブルーチンでは3つの部分に分かれています。先ずは入力フォームの表示部分です。このページ右上にある画像のようなものを表示します。下の if文で、5回船終了後かどうか判断をしてCGIに送るデータを決めています。
上のサブルーチンの続きです。
#対戦経過置換え・表示
$kaisen = length($aite_jyanken[0]);
for ($i = 0; $i < $kaisen; $i++){
   $aite[$i] = substr(@aite_jyanken[0],$i,1);
   $coco[$i] = substr(@coco_jyanken[0],$i,1);
if ($aite[$i] eq 0 and $coco[$i] eq 1) {
   $aite[$i] = "<td bgcolor=\"pink\">$aite[$i]";
   $coco[$i] = "<td>$coco[$i]";
} elsif ($aite[$i] eq 1 and $coco[$i] eq 2) {
   $aite[$i] = "<td bgcolor=\"pink\">$aite[$i]";
   $coco[$i] = "<td>$coco[$i]";
} elsif ($aite[$i] eq 2 and $coco[$i] eq 0) {
   $aite[$i] = "<td bgcolor=\"pink\">$aite[$i]";
   $coco[$i] = "<td>$coco[$i]";
} else {
   $coco[$i] = "<td bgcolor=\"pink\">$coco[$i]";
   $aite[$i] = "<td>$aite[$i]";
}
   $aite[$i] =~ s/0/<img src=\"$images2\">/g;
   $aite[$i] =~ s/1/<img src=\"$images3\">/g;
   $aite[$i] =~ s/2/<img src=\"$images4\">/g;
   $coco[$i] =~ s/0/<img src=\"$images2\">/g;
   $coco[$i] =~ s/1/<img src=\"$images3\">/g;
   $coco[$i] =~ s/2/<img src=\"$images4\">/g;
}

$kaisen = length($aite_jyanken[0]);
では$aite_jyanken[0] つまり、相手のジャンケンの今までのグー・チョキ・パーの履歴です。例えば今までに3回戦って、1回目がグーで2回目がチョキで3回目がパーなら$aite_jyanken[0]の内容は 012 となっています。length で文字数を調べています。この場合は3となります。その結果を $kaisen に代入しています。
【→Perl Reference: length
そしてその回数だけ for ($iが0から始まって$iが$kaisenより小さい場合処理をする 処理ごとに$iに1を加える){処理内容} となります。

   $aite[$i] = substr(@aite_jyanken[0],$i,1);
ここではsubstrを使って、@aite_jyanken[0]左から1バイトずつ取り出して$aite[$i]に代入しています。先ほどの例でいえば、$aite_jyanken[0]が012なら$aite[0]に0が、$aite[1]に1が、$aite[2]に2が入ることになります。自分と相手の今までのジャンケンの選択を取り出しているのです。if else で勝者を分かりやすく表示するためテーブルの背景に色をつけています。
【→Perl Reference: substr

   $aite[$i] =~ s/0/<img src=\"$images2\">/g;
これは s/A/B / でAをBに置き換えます。最後の g は何度出てきても全て置き換えることになります。単に012だった文字を一文字ずつ配列に格納しています。これで012がグーチョキパーとなり、勝者は背景色をピンクで表示できるようになりました。
すみません、長くなってしまいました。もう少しですからお付き合いください。
[対戦相手のジャンケン入力・対戦経過置換え・表示]サブルーチンの最後です。
#対戦経過表示
print qq|
</td><td width="20"></td><td valign="top">
<table border="1">
<tr align="center"><td height="32"></td>
   <td width="32">1</td><td width="32">2</td>
   <td width="32">3</td><td width="32">4</td>
   <td width="32">5</td>
<tr align="center"><td height="32">あなた</td>
   $aite[0]</td>$aite[1]</td>$aite[2]</td>$aite[3]</td>$aite[4]</td></tr>
<tr align="center"><td height="32">ココ</td>
   $coco[0]</td>$coco[1]</td>$coco[2]</td>$coco[3]</td>$coco[4]</td></tr>
</table>
</td></tr></table>
<br>
|;
}
ここで、先ほど置き換えた結果を表示させています。
あなた
ココ
こんな感じになります。
続いてジャンケンの勝ち負けを判断して、各々のメッセージを変えるサブルーチンです。
###############################
#ジャンケン判断
sub jyanken_handan{
$kaisu++;
if ($jyan eq ""){
   $disp_msg2 = "最初はグー";
   $kaisu--;
} elsif ($jyan == $coco_jyan){
   $disp_msg2 = "アイコ!";
   $kaisu--;
   $aiko = 1;
} elsif ($jyan == 0 and $coco_jyan == 1){
   $disp_msg2 = "残念!";
   $aite_kachi++;
} elsif ($jyan == 0 and $coco_jyan == 2){
   $disp_msg2 = "ココの勝ち!";
   $coco_kachi++;
} elsif ($jyan == 1 and $coco_jyan == 0){
   $disp_msg2 = "やったね!";
   $coco_kachi++;
} elsif ($jyan == 1 and $coco_jyan == 2){
   $disp_msg2 = "悔しい!";
   $aite_kachi++;
} elsif ($jyan == 2 and $coco_jyan == 0){
   $disp_msg2 = "負けた!";
   $aite_kachi++;
} elsif ($jyan == 2 and $coco_jyan == 1){
   $disp_msg2 = "ココ強い!!";
   $coco_kachi++;
}
if ($aiko ne 1 and $jyan ne "") {
   @coco_jyanken = "@coco_jyanken" . "$coco_jyan";
   @aite_jyanken = "@aite_jyanken" . "$jyan";
}
}
if else で、ココから見た勝敗に対するメッセージを決めています。

   @coco_jyanken = "@coco_jyanken" . "$coco_jyan";
これは、次の勝負に渡す入力フォームの値を決めています。
先ほどまで2回戦っていれば、@coco_jyankenの中には例えば01(1回目がグーで2回目がパー) 、続いて今回の闘いがチョキだとすると2が$coco_jyanに代入されています。そこで@coco_jyankenの01と$coco_jyanの2をつなげて@coco_jyankenを012に置き換えています。
###################################
#0から2までの乱数発生
###################################
sub get_rand
{
$coco_jyan = int(rand(3));
}
このサブルーチンは短いです。なにもサブルーチン化することもなかったのですが!
rand(3)で0-2までの乱数を発生させていますが、randで作られる数は整数ではないので int で整数に(切り捨て)しています。
【→Perl Reference: int
【→Perl Reference: rand
###################################
#ジャンケン表示
###################################
sub printm {
print "ココが[";
print $jyanken[$coco_jyan];
print "]で、あなたは[";
print $jyanken[$jyan];
print "]ですから・・・";
}
これで最後です。このサブルーチンではお互いが選択したジャンケンの内容を言葉で表示させています。初期設定で
@jyanken = ("グー", "チョキ", "パー");
としてありますので、この配列から表示をさせています。
これで全て終了です! バラバラで分かりにくいので下に全ソースをまとめておきます。ご自分のPCで試される方は、l_jyanken_cgi.txtをl_jyanken.cgiに名前を変えてお試しください。サーバに移される時は757のパーミッションにしてください。その他のファイルの名前はそのままで結構です。
l_jyanken_cgi.txt(本体) (757)(文字化けする方EUCで見てください)

stdin.txt(GET・POST対応スクリプト) (644)
その他に下の2つのファイルが必要です。自分で適当に修正して使ってみてください。
l_jyanken.cgiとstdin.txt、heder.txt、fotter.txtはCGIの実行できる同じディレクトリに置いてください。
heder.txt(644)
print qq|
<html>
<head><title>$title</title>
<meta http-equiv="Content-Type" content="text/html; charset=x-euc-jp">
<link rel="stylesheet" type="text/css" href="../cocohomestyle.css">
</head>
<body LINK="#006EFF" VLINK="#006EFF">
|;

1

fotter.txt(644)
print qq(
<hr>
<center>
<font size="1">| <a href="Javascript:history.back()">Back</a>
 | | <a href="../../index.html">Coco's Home</a> | | 
<a href="../index.html">ココとPerlで遊びませんか |
<hr>
Copyright 2001-2002 Coco's Home. All rights reserved.</font>
</center>
</body>
</html>
);

1;


| Back | Coco's Home | ココとPerlで遊びませんか |

Copyright 2001-2002 Coco's Home. All rights reserved.

[PR]tDl:]Et綮可CI