「MTでPerlを学ぶ(その11)」の問題の解答

5月31日の「MTでPerlを学ぶ(その11・for文による繰り返し)」で出した問題の回答をお送りします。

1.問題

問題の内容は以下の通りです。

サイコロのプログラムを改造して、以下のように出力するプログラムを作ってみてください。

<ul>
<li>1回目 : -3戻る : 現在位置 後ろに-3</li>
<li>2回目 : 3進む : 現在位置 スタート</li>
<li>3回目 : そのまま : 現在位置 スタート</li>
<li>4回目 : -2戻る : 現在位置 後ろに-2</li>
<li>5回目 : -1戻る : 現在位置 後ろに-3</li>
<li>6回目 : -2戻る : 現在位置 後ろに-5</li>
<li>7回目 : -1戻る : 現在位置 後ろに-6</li>
<li>8回目 : 3進む : 現在位置 後ろに-3</li>
<li>9回目 : 2進む : 現在位置 後ろに-1</li>
<li>10回目 : 3進む : 現在位置 前に2</li>
</ul>

上の出力例は、以下のような処理を想定したものです。

  • カードを10回引きます。
  • カードには-3、-2、-1、0、1、2、3のどれかの数字が書いてあります。
  • プラスの数字が出たら、その数だけ前に進みます。
  • マイナスの数字が出たら、その数だけ後ろに戻ります。
  • 10回のそれぞれで、繰り返しの回数と、進む(戻る)数、そして現在の位置を表示します。
    0のカードを引いたときは、進む(戻る)数の代わりに「そのまま」と表示します。
    また、現在の位置が0(スタート位置)に戻ったときは「スタート位置」と表示します。

2.解答

問題の解答例は、以下のようになります。

my $pos = 0;
print "<ul>\n";
for (my $i = 0; $i < 10; $i++) {
    my $x = int(rand(7)) - 3;
    print "<li>" . ($i + 1) . "回目 : ";
    if ($x > 0) {
        print "$x進む";
    }
    elsif ($x < 0) {
        print "$x戻る";
    }
    else {
        print "そのまま";
    }
    $pos += $x;
    print " : 現在位置 ";
    if ($pos > 0) {
        print "前に$pos";
    }
    elsif ($pos < 0) {
        print "後ろに$pos";
    }
    else {
        print "スタート";
    }
    print "</li>\n";
}
print "</ul>\n";

上記を含むインデックステンプレートのサンプルをダウンロード

プログラムの内容は以下の通りです。

1行目

変数$posを宣言し、値を0に初期化します。
この変数に、現在の位置を記憶します。

2行目

<ul>タグを出力します。

3行目

for文を使って10回の繰り返しを行います。

4行目

-3以上3以下の整数の乱数を作り、変数$xに代入します。
この乱数を作る手順は、以下の通りです。

  • 1.-3から3の間の整数は7個ありますので、まずrand関数で0以上~7未満の乱数を作ります。
  • 2.1.の乱数の小数点以下をint関数で切り捨てて、0から6の整数の乱数を作ります。
  • 3.2.の値から3を引くことで、-3から3の整数の乱数になります。

5行目

<li>タグと、「○回目」を出力します。
「○」の部分は「($i + 1)」になっていて、また$iは繰り返しの回数を数える変数です。
そのため、繰り返しが進むごとに、「○」の部分には「1」「2」・・・と順に出力されます。

6行目~8行目

乱数が0より大きいときは(6行目)、「○進む」のように、進む数を出力します(7行目)。
「○」の部分に変数$xを入れていますので、乱数の値がそのまま出力されます。

9~11行目

乱数が0より小さいときは(9行目)、「○進む」のように、進む数を出力します(10行目)。

12~14行目

乱数($x)の値が0のときは、6行目と9行目のどちらの条件も満たしません。
そのときは、12行目のelseによって、13行目が実行され、「そのまま」と出力します。

15行目

現在の位置(変数$pos)に、乱数($x)の値を足して、現在の位置を更新します。

16行目

「: 現在位置」と出力します。

17~25行目

6~14行目と同じ考え方で、現在位置が0より大きい/0より小さい/それ以外(0)の3つの場合に分けて、現在位置を出力します。

26行目

行の最後の</li>タグを出力します。

28行目

最後の</ul>タグを出力します。