Friction River Software

  • お問い合わせ

CakePHP5入門【WebAPI編⑬】引っ張りを可視化

A子

今回はついに当選番号の予想アルゴリズムを考えていくよ
(そもそもの目的はこれだからね)

C菜

曜日(七曜)や六曜ごとの偏りを利用するんですか~?

A子

いや、あれじゃ当たらないってことが分かったからね
(それが分かっただけでも無駄じゃなかったけどさ(苦笑))

B美

世の中でよく利用されてるのが「引っ張り」理論ね
(いや「理論」ってほどのものじゃないけど…)

C菜

それって、どういうものでしょうか~?

B美

前回、前々回に登場した数字が(割と頻繁に)当選番号内に出現する…って考え方よ

もちろん、同じ桁とは限らないけどね

A子

あと、隣接した数字がよく出るってのもあるよ

「12」とか「54」とか…

B美

あとは(ナンバーズ3の場合)三つの数字の合計が「13」や「16」になることが多い…とか

その合計って「000」だと「0」、「999」では「27」なんだけど、その28通りの中で8%が「13」になってるの
(統計的に…)

C菜

8%って低いように見えますけど、だいたい一割ですからね~

思ったよりも高いです~

B美

二つのサイコロを振って出目の合計が「7」になる確率が最も高い…ってのと同じ考え方だけどね
(単なる数学的な必然…)

C菜

その間にある「14」や「15」はどうなんですか~?

B美

当然のことながら、そこそこ高いわよ

まぁ、「13」という合計がほんの少しだけ(出現頻度が)高いってだけよ

A子

だとしたら、こういうアルゴリズムはどうかな?
(ナンバーズ3の場合ね)

1.「引っ張り」で軸となる数字を一つ決める
2.その数字の前後の数字を二つ決める(軸が「5」ならば「4」と「6」)
3.最後の一つは数字の合計が「13」になるものを選ぶ

例えば、軸が「3」とするよね
前後の数字は「2」と「4」だから、三つ目の数字は「8」と「6」ってこと

つまり予想は「238」と「346」ってことになるわけ

C菜

それでは「軸」の数字さえ決まれば、あとは固定じゃないですか~

「0」から「9」の10通りの「軸」において、20個の予想数字をあらかじめ決めておけますよ~

A子

あ、たしかに…(苦笑)

うーん、そうねぇ
「軸」を二つにしてみる?

B美

まぁ、その辺りはおいおい考えるとして、「引っ張り」を可視化したいわね

本当によく発生しているのか…

C菜

ある「実施回」の配列をこのように準備するとして、出現数字と配列の添字を同じものとします~

[0][1][2][3][4][5][6][7][8][9]
0000000000

例えば、

実施回当選番号
第6943回690
第6944回319
第6945回191
第6946回619
第6947回141

のとき、第6945回の集計データはこうです~

[0][1][2][3][4][5][6][7][8][9]
0300000003

A子

なるほどね

「1」という数字が前回、次回、次々回に出てて、「9」という数字が前回、前々回、次回に出てるね
どちらも3回ずつだ…)

B美

「実施回」と「当選番号」を付け加えれば、表示する際に分かりやすいかもね

[0][1][2][3][4][5][6][7][8][9][10][11]
03000000036945191

A子

まずは「実施回」の昇順で全レコードを取得しよう
んで、それをループで回して、上記の配列を作っていくと…

あとは、最終的にそれを一つにまとめていけば良いんじゃない?

C菜

良いと思います~

//ナンバーズ3の引っ張りを可視化
public function pulling3()
{
    //numbersテーブルを検索(「実施回」の昇順)
    $numbers = $this->Numbers->find()->order(['lottery_time' => 'asc']);

    //全件数分、ループを回す
    foreach ($numbers as $val) {

        ・・・(集計処理)・・・

    }
}

これを誰でも見れるように「src/Controller/TopController.php」内に作りましょう~

A子

あ、そこ(TopController.php)に書くんだったら、これ(テーブルのフェッチ)も必要だよ

private $Numbers;

public function initialize(): void
{
    parent::initialize();

    $this->Numbers = $this->fetchTable('Numbers');
}

さて、問題はここからだね
「前々回」「前回」「次回」「次々回」のデータを見るにはどうしたら…?

C菜

こうしたらどうでしょう~?

//ナンバーズ3の引っ張りを可視化
public function pulling3()
{
    //numbersテーブルを検索(「実施回」の昇順)
    $numbers = $this->Numbers->find()->order(['lottery_time' => 'asc']);
    $total = $numbers->count();
    $numbers_array = $numbers->toArray();


    //全件数分、ループを回す
    foreach ($numbers as $idx => $val) {

        //前々回
        $prepre_idx = $idx - 2;
        if ($prepre_idx >= 0) {
            //$numbers_array[$prepre_idx]という形で前々回にアクセス
        }

        //前回
        $pre_idx = $idx - 1;
        if ($prepre_idx >= 0) {
            //$numbers_array[$pre_idx]という形で前回にアクセス
        }

        //次回
        $next_idx = $idx + 1;
        if ($next_idx < $total) {
            //$numbers_array[$next_idx]という形で次回にアクセス
        }

        //次々回
        $nextnext_idx = $idx + 2;
        if ($nextnext_idx < $total) {
            //$numbers_array[$nextnext_idx]という形で次々回にアクセス
        }


    }
}

もっとスマートな方法もあるかもしれませんけど~(苦笑)

A子

うんうん、良いんじゃない?

んじゃ、そこに付け加えていくよ
$result」が最終結果で、「$record」がさっきC菜が言ってた配列ね

//ナンバーズ3の引っ張りを可視化
public function pulling3()
{
    //numbersテーブルを検索(「実施回」の昇順)
    $numbers = $this->Numbers->find()->order(['lottery_time' => 'asc']);
    $total = $numbers->count();
    $numbers_array = $numbers->toArray();
    $result = [];

    //全件数分、ループを回す
    foreach ($numbers as $idx => $val) {
        //この回の結果を初期化
        $record = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, $val->lottery_time, $val->num3_str];

        //この回の各桁の数字
        $num3_place1 = $val->num3_place1;
        $num3_place10 = $val->num3_place10;
        $num3_place100 = $val->num3_place100;
        $num3_array = [$num3_place100, $num3_place10, $num3_place1];


        //前々回
        $prepre_idx = $idx - 2;
        if ($prepre_idx >= 0) {
            $tmp_place1 = $numbers_array[$prepre_idx]->num3_place1;
            $tmp_place10 = $numbers_array[$prepre_idx]->num3_place10;
            $tmp_place100 = $numbers_array[$prepre_idx]->num3_place100;
            $tmp_array = [$tmp_place100, $tmp_place10, $tmp_place1];

            foreach ($num3_array as $val2) {
                if (in_array($val2, $tmp_array)) {
                    $record[$val2]++;
                }
            }

        }

        //前回
        $pre_idx = $idx - 1;
        if ($prepre_idx >= 0) {
            //$numbers_array[$pre_idx]という形で前回にアクセス
        }

        //次回
        $next_idx = $idx + 1;
        if ($next_idx < $total) {
            //$numbers_array[$next_idx]という形で次回にアクセス
        }

        //次々回
        $nextnext_idx = $idx + 2;
        if ($nextnext_idx < $total) {
            //$numbers_array[$nextnext_idx]という形で次々回にアクセス
        }

        //結果配列に追加
        array_push($result, $record);

    }

    $this->set(compact('result'));
}

とりあえず「前々回」の分だけ書いてみたけど、どうかな?

B美

うーん、悪くはないんだけど、「前回」「次回」「次々回」の中身が「前々回」のものとほとんど一緒になるわよ

そういう場合、どうすべきかしら?

C菜

privateメソッドとして、別ルーチンに切り出すべきですね~
あ、どうせだったら(ナンバーズ3だけじゃなく)ナンバーズ4でも流用できるようなものにしましょう~

//引っ張り判定
//$numbers_array…全レコードの配列
//$record…結果を格納する配列(参照渡し)
//$num_array…調査対象数字
//$idx…実施回を指定
//$type…「3」がナンバーズ3,「4」がナンバーズ4
private function match_judgment($numbers_array, &$record, $num_array, $idx, $type)
{
    //指定した回の各桁の数字
    $tmp_array = [];
    if ($type == 3) {
        $tmp_place1 = $numbers_array[$idx]->num3_place1;
        $tmp_place10 = $numbers_array[$idx]->num3_place10;
        $tmp_place100 = $numbers_array[$idx]->num3_place100;
        $tmp_array = [$tmp_place100, $tmp_place10, $tmp_place1];
    } elseif ($type == 4) {
        $tmp_place1 = $numbers_array[$idx]->num4_place1;
        $tmp_place10 = $numbers_array[$idx]->num4_place10;
        $tmp_place100 = $numbers_array[$idx]->num4_place100;
        $tmp_place1000 = $numbers_array[$idx]->num4_place1000;
        $tmp_array = [$tmp_place1000, $tmp_place100, $tmp_place10, $tmp_place1];
    }

    //一致するかを判定
    foreach ($num_array as $val) {
        if (in_array($val, $tmp_array)) {
            $record[$val]++;
        }
    }
}

戻り値を返さずに、結果は「参照渡し」した配列($record)に格納します~
ダメでしょうか~?

以前、「参照渡し」は使わないように!…って教えてもらいましたけど~
(【PHP言語の文法編④】を参照)

B美

このケースだったら私も「参照渡し」にするかな…(苦笑)

それじゃ、このメソッドを呼び出すにはどうする?

A子

こんな感じになるのかな?

$this->match_judgment($numbers_array, $record, $num3_array, $prepre_idx, 3);

「ナンバーズ3」の「前々回」の箇所ね

C菜

まとめてみました~

//ナンバーズ3の引っ張りを可視化
public function pulling3()
{
    //numbersテーブルを検索(「実施回」の昇順)
    $numbers = $this->Numbers->find()->order(['lottery_time' => 'asc']);
    $total = $numbers->count();
    $numbers_array = $numbers->toArray();
    $result = [];

    //全件数分、ループを回す
    foreach ($numbers as $idx => $val) {
        //この回の結果を初期化
        $record = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, $val->lottery_time, $val->num3_str];

        //この回の各桁の数字
        $num3_place1 = $val->num3_place1;
        $num3_place10 = $val->num3_place10;
        $num3_place100 = $val->num3_place100;
        $num3_array = [$num3_place100, $num3_place10, $num3_place1];

        //前々回
        $prepre_idx = $idx - 2;
        if ($prepre_idx >= 0) {
            $this->match_judgment($numbers_array, $record, $num3_array, $prepre_idx, 3);
        }

        //前回
        $pre_idx = $idx - 1;
        if ($prepre_idx >= 0) {
            $this->match_judgment($numbers_array, $record, $num3_array, $pre_idx, 3);
        }

        //次回
        $next_idx = $idx + 1;
        if ($next_idx < $total) {
            $this->match_judgment($numbers_array, $record, $num3_array, $next_idx, 3);
        }

        //次々回
        $nextnext_idx = $idx + 2;
        if ($nextnext_idx < $total) {
            $this->match_judgment($numbers_array, $record, $num3_array, $nextnext_idx, 3);
        }

        //結果配列に追加
        array_push($result, $record);
    }

    $this->set(compact('result'));
}



A子

んじゃ「ナンバーズ4」のほうも書いておこう
(ちょっと変更するだけだし…)

//ナンバーズの引っ張りを可視化
public function pulling4()
{
    //numbersテーブルを検索(「実施回」の昇順)
    $numbers = $this->Numbers->find()->order(['lottery_time' => 'asc']);
    $total = $numbers->count();
    $numbers_array = $numbers->toArray();
    $result = [];

    //全件数分、ループを回す
    foreach ($numbers as $idx => $val) {
        //この回の結果を初期化
        $record = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, $val->lottery_time, $val->num4_str];

        //この回の各桁の数字
        $num4_place1 = $val->num4_place1;
        $num4_place10 = $val->num4_place10;
        $num4_place100 = $val->num4_place100;
        $num4_place1000 = $val->num4_place1000;
        $num4_array = [$num4_place1000, $num4_place100, $num4_place10, $num4_place1];

        //前々回
        $prepre_idx = $idx - 2;
        if ($prepre_idx >= 0) {
            $this->match_judgment($numbers_array, $record, $num4_array, $prepre_idx, 4);
        }

        //前回
        $pre_idx = $idx - 1;
        if ($prepre_idx >= 0) {
            $this->match_judgment($numbers_array, $record, $num4_array, $pre_idx, 4);
        }

        //次回
        $next_idx = $idx + 1;
        if ($next_idx < $total) {
            $this->match_judgment($numbers_array, $record, $num4_array, $next_idx, 4);
        }

        //次々回
        $nextnext_idx = $idx + 2;
        if ($nextnext_idx < $total) {
            $this->match_judgment($numbers_array, $record, $num4_array, $nextnext_idx, 4);
        }

        //結果配列に追加
        array_push($result, $record);
    }

    $this->set(compact('result'));
}

どうよ


C菜

こうして見てみると、「pulling3」メソッドと「pulling4」メソッドって、一つにまとめられなくもないですね~

B美

まぁ、そこまでやらなくても良いかな

それでは、結果を表示するビューファイルのほうはどうなる?

C菜

「templates/Top」の下に「pulling3.php」と「pulling4.php」を作りましたよ~
(下記に「pulling3.php」を表示してますけど、「pulling4.php」のほうも中身は全く同じです~)



A子

あ、トップページ(templates/Top/index.php)にもリンクを張らなきゃね

<?= $this->Html->link(__('ナンバーズ3の引っ張りを確認する'), ['action' => 'pulling3'], ['class' => 'button is-small is-success']) ?>

<?= $this->Html->link(__('ナンバーズ4の引っ張りを確認する'), ['action' => 'pulling4'], ['class' => 'button is-small is-success']) ?>

この二行を追記するよ

B美

それじゃ、ブラウザから実行確認してみなさい

C菜

了解です~




A子

おぉ!
めっちゃ分かりやすいじゃん

B美

最新のデータまで含んだものを読者の皆さんのPC上で見れるから、ぜひ見てみてね
(このサイトの左側のメニューの中にある「Numbers API」をクリック)

A子

まーた「メタ発言」だよ(苦笑)

C菜

ですです~(笑)