mt_rand()に「!」をつけると?
mt_rand()という乱数発生の関数があります。これを「!」で否定するとどうなるのでしょうか?
先に結論から言ってしまうと
mt_rand(0,9)に「!」をつけると、0がtrueで返ってきて1〜9がfalseで返ってきます。
つまり10分の1の確率を出すことができます。
mt_rand()という関数についてですが、
mt_rand()は「乱数を発生」する関数です。
()の中に入る引数をコンマで区切ると乱数の範囲を指定できます。
mt_rand(10,40)なら10〜40までの間のランダムな数、となります。
mt_rand(0,9)を実行すると0〜9の間の10個の数がランダムに発生しますよね。
以下のコードを実行すると
<?php $a = mt_rand(0,9); echo '変数aには「'.$a.'」がはいっています。<br>'; $b =!mt_rand(0,9); echo '!mt_randの変数bには「'.$b.'」がはいっています。<br>'; ?>
変数bには、だいたい10回に1回、下の画像のように「1」が返ってきます。
なぜ「1」なの?
10回に1回の確率で、!mt_randの変数bには「1」が入っていました。
以下のコードを書いてみると、
<?php $test = 0; echo 'testの中身は' . $test .'です。'; echo '<br>'; if ($test) { echo 'test is true'; } else { echo 'test is false'; } echo '<br>'; $test = 1; echo 'testの中身は' . $test .'です。'; echo '<br>'; if ($test) { echo 'test is true'; } else { echo 'test is false'; } ?>
↑
$test = 0;
なのに、「test is false」が返ってくるんです。
これはなぜかというと、
「phpでは中身が0の変数をif文で評価すると、falseになる」ためです。
なので、さっきの「!mt_rand(0,9)」のコードを書くと
だいたい10回に1回、「1」が返ってきていたのは10回に1回「0」が返ってきていたからです。
じゃあ、「!mt_rand(0,9)」の「!」はなにを否定してるのでしょうか?
mt_rand(0,9)でランダムな数が返ってくると頭が混乱するので、さっきの「$test」を使いましょう。
【 $test = 0のとき】
変数$testに、 0 を入れます。
そうすると、
if ($test) {} は if (false) {}
になります。
(※phpでは中身が0の変数をif文で評価すると、falseになるから)
もっと具体的に言うと、、、
<?php $test = 0; echo 'testの中身は' . $test .'です。'; echo '<br>'; if ($test) { echo 'test is true'; } else { echo 'test is false'; } echo '<br>'; $test = 0; echo 'testの中身は' . $test .'です。'; echo '<br>'; if (false) { echo 'test is true'; } else { echo 'test is false'; } ?>
これを実行すると、下の画像のようになります。
ここで「!」を登場させます。
if (false) {} を if (!false) {}
にすれば、このif文の評価は「true」になります。
そしてfalseは$testのことだから、
if (!false) {} を if (!$test) {}
に変えれば$test = 0のときtrueが返ってくるif文の完成!
※trueのときは「1」、falseのときは「””(空文字)」が返ってきます。
(参考記事:https://wemo.tech/623)
mt_rand(0,9)を「$test = 0」の代わりに使ってみる
$test = 0のときにfalseになるから、 if文に入れるときに
if (!$test) {}
としました。これで$test = 0のとき、trueになりますよね。
じゃあ、【!mt_rand(0,9)】にすると?
数字が0のときはtrue それ以外(1〜9)のときはfalse
が返ってきます。
$test = !mt_rand(0, 9);
として、以下のコードを実行してみると
<?php $test = !mt_rand(0, 9); echo 'testの中身は' . $test .'です。'; echo '<br>'; if ($test) { echo 'test is true。10分の1の方です'; } else { echo 'test is false!10分の9の方です'; } ?>
1〜9ならこの画面が出ます。
0ならこの画面が出ます。
なので、
if(!mt_rand(0,9)){ }
と書けば10分の1の確率で0(true)が出て、10分の9の確率で1〜9(false)が出る
ということになります。
可読性を上げるなら
$is_critical = (0 == mt_rand(0,9)); if($is_critical){}
と書いた方がわかりやすいと思います。
$is_critical = (0 == mt_rand(0,9)); →意味:「ランダムに発生する0〜9の数字のうち、0のとき」を変数$is_criticalに入れる
「防御力を5分の1の確率でアップさせる(5分の4でダウン)。」
これを使って、
「防御力を5分の1の確率でアップさせる(5分の4でダウン)。」
というコードを書くと
<?php $defensePower = 100; function Defense(){ global $defensePower; echo 'あなたの防御力は'.$defensePower.'です<br>'; echo 'ス○ラを唱えた!<br>'; // 5分の1の確率で防御力を上げたい $is_critical = (mt_rand(0,4) == 0); if($is_critical){ $defensePower = $defensePower * 1.5; echo '魔法成功!防御力アップ!<br>'; echo 'あなたの防御力は'.$defensePower.'になった!'; }else{ $defensePower = $defensePower * 0.5; echo '魔法失敗。。。<br>'; echo 'あなたの防御力は'.$defensePower.'になった!'; } } echo Defense(); ?>
というような感じになります。
画面にはリロードしまくると、どちらかが出ます。
↓こちらが「0」が出たとき。
↓こちらが「1〜9」が出たとき。
注意点
・If (!mt_rand(0,9)){}ができるのは、phpの言語仕様のおかげ。0がfalseやemptyとして評価されるから。多言語で同じことをしたいときは使用を必ずチェックすること!
・可読性は良くないが、今回のように書いているエンジニアもいる。
・本家の魔法「スカラ」は失敗しても防御力は下がりません。
必ずしもきれいなコードに出会えるわけではないと思うので、今回のこの問題(?)は良い勉強になりました!