kuruton_ternのブログ

プログラミングのアウトプットブログ。

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」が返ってきます。

f:id:kuruton_tern:20190915032131p:plain




なぜ「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';
    }
?>

f:id:kuruton_tern:20190915032328p:plain


$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';
    }

    ?>



これを実行すると、下の画像のようになります。

f:id:kuruton_tern:20190915233443p:plain

ここで「!」を登場させます。

if (false) {}
を
if (!false) {}

にすれば、このif文の評価は「true」になります。
そしてfalseは$testのことだから、

if (!false) {}
を
if (!$test) {}

に変えれば$test = 0のときtrueが返ってくるif文の完成!

※trueのときは「1」、falseのときは「””(空文字)」が返ってきます。
(参考記事:https://wemo.tech/623

wemo.tech




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(09);
    echo 'testの中身は' . $test .'です。';
    echo '<br>';
    if ($test) {
        echo 'test is true。10分の1の方です';
    } else {
        echo 'test is false!10分の9の方です';
    }

?>



1〜9ならこの画面が出ます。

f:id:kuruton_tern:20190915032842p:plain



0ならこの画面が出ます。

f:id:kuruton_tern:20190915032916p:plain

なので、  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」が出たとき。

f:id:kuruton_tern:20190916000238p:plain

↓こちらが「1〜9」が出たとき。

f:id:kuruton_tern:20190916000339p:plain




注意点


・If (!mt_rand(0,9)){}ができるのは、phpの言語仕様のおかげ。0がfalseやemptyとして評価されるから。多言語で同じことをしたいときは使用を必ずチェックすること!
・可読性は良くないが、今回のように書いているエンジニアもいる。
・本家の魔法「スカラ」は失敗しても防御力は下がりません。

必ずしもきれいなコードに出会えるわけではないと思うので、今回のこの問題(?)は良い勉強になりました!