1. はじめに
私はパチスロが好きですがメダルを増やすことが好きというより、内部でどのような抽選が行われ、どう制御されているのかという仕組みを理解して打つのが好きです。
型式検定の厳しい制約の中で、開発者がいかに天才的なロジックを組んでいるのか。その裏側を再現してみたくなり、まずは構造がシンプルな某Aタイプの告知機をモデルに、TypeScriptでシミュレーターを構築してみました。
また、開発にあたっては今回はGitHub Copilot Proを導入しました。
有料版のパワーを借りて、期待値計算のデバッグや複雑なフラグ配分の実装など、AIとのペアプログラミングでどこまで実機の挙動に迫れるかという技術検証も兼ねています。
2. 設計思想:16bit乱数空間による「個数管理」
パチスロの抽選は、一般的に16bit($0$ 〜 $65535$)の整数空間で行われます。
メーカー公表の「1/7.3」といった確率は、この65536個の「イス」を各役にいくつ割り振るか(個数)で決まります。
今回の実装では、浮動小数点による判定を避け、実機基板の思想に近いレンジ判定を採用しました。
某台の巷流の解析値や実戦値をベースを参考にざっくりとフラグの個数を決めて埋め込みました。
export const FLAG_COLUMNS: FlagColumns = {
SOLO_BIG: { 1: 155, 2: 157, 3: 160, 4: 164, 5: 176, 6: 190 },
SOLO_REG: { 1: 105, 2: 115, 3: 125, 4: 135, 5: 146, 6: 157 },
CHERRY_BIG: { 1: 45, 2: 44, 3: 43, 4: 52, 5: 52, 6: 56 },
CHERRY_REG: { 1: 60, 2: 68, 3: 77, 4: 81, 5: 90, 6: 105},
ICHIMAI_A_BIG: { 1: 15, 2: 16, 3: 15, 4: 15, 5: 15, 6: 17 },
ICHIMAI_B_BIG: { 1: 9, 2: 11, 3: 10, 4: 10, 5: 10, 6: 11 },
ICHIMAI_A_CHERRY_BIG: { 1: 9, 2: 10, 3: 9, 4: 10, 5: 10, 6: 10 },
ICHIMAI_B_CHERRY_BIG: { 1: 10, 2: 10, 3: 10, 4: 11, 5: 9, 6: 10 },
CHERRY_ONLY: { 1: 1059, 2: 1059, 3: 1059, 4: 1059, 5: 1059, 6: 993 },
GRAPE: { 1: 10815, 2: 10832, 3: 10978, 4: 11222, 5: 11280, 6: 11300 },
PIERROT: { 1: 99, 2: 99, 3: 99, 4: 99, 5: 99, 6: 99 },
BELL: { 1: 98, 2: 98, 3: 98, 4: 98, 5: 98, 6: 98 },
REPLAY: { 1: 8980, 2: 8980, 3: 8980, 4: 8980, 5: 8980, 6: 8980 },
};
状態(ステート)は以下の3つを定義し、それぞれ参照するフラグテーブルを切り替えています。
RBを第一種特別役物(レギュラーボーナス)とし、BBを第一種特別役物に係る連続役物作動装置(ビッグボーナス)として考えています。
通常時: 全フラグを抽選いる。ボーナスフラグを引くとボーナス系の状態に遷移。
RB: 規定消化or上限到達で通常時へ移行する状態。
BB: JACカウントを減らしながらRBを連続で回している状態。
3. 検証①:100万ゲームにおける「理論値への収束」
まずは、独自に設定したフラグ配分モデルが、長期的に見て公表されている機械割(設定6で110%超など)と一致するのかを確認しました。
試行回数: 1,000,000G
結果: 設定6 理論値 111.2%に対し、おおよそ期待通りくらいのものが確認できました。
サンプル
====================================
🎰 Aタイプ シミュレーション結果
====================================
総試行回数: 1,000,000 G
通常時G : 891,380 G
ボーナスG: 108,620 G
------------------------------------
BB回数 : 3,967 回
RB回数 : 3,660 回
BB当選確率: 1/224.7 (0.45%)
RB当選確率: 1/243.5 (0.41%)
合算確率: 1/116.9
------------------------------------
チェリー: 15,876 回 (1/56.1)
└ 重複: 2,541 回 (重複率: 16.01%)
1枚役A : 411 回 (1/2168.8)
└ チェリー重複: 169 回 (重複率: 41.12%)
1枚役B : 312 回 (1/2857.0)
└ チェリー重複: 144 回 (重複率: 46.15%)
ぶどう : 152,242 回 (1/5.9)
ピエロ : 1,329 回 (1/670.7)
ベル : 1,338 回 (1/666.2)
リプレイ: 122,386 回 (1/7.3)
停止制御 成功: 282,710 回
└ 成功内訳 CHERRY : 7,674 回
└ 成功内訳 GRAPE : 152,242 回
└ 成功内訳 PIERROT: 120 回
└ 成功内訳 BELL : 288 回
└ 成功内訳 REPLAY : 122,386 回
停止制御 失敗: 10,461 回
└ 失敗内訳 CHERRY : 8,202 回
└ 失敗内訳 GRAPE : 0 回
└ 失敗内訳 PIERROT: 1,209 回
└ 失敗内訳 BELL : 1,050 回
└ 失敗内訳 REPLAY : 0 回
停止制御ロス: -59,264 枚
------------------------------------
最終差枚(実績): +267,302 枚
機械割(実績) : 109.31 %
最終差枚(チェリー完全): +299,776 枚
機械割(チェリー完全) : 110.44 %
最終差枚(全成功): +326,566 枚
機械割(全成功) : 111.37 %
====================================
リール配列と引き込み範囲(4コマ)に基づき、成立役を蹴る位置で停止させた場合の欠損を停止制御失敗としています。いわゆる目押しミスですね。小役をフォローできていないパターンです。
停止制御失敗の適当押しやチェリーのみ完全フォローなど複数パターンの機械割も出すようにしてみました。
4. 検証②:300G / 3000G における「期待値」と「現実」の乖離
100万ゲームではある程度収束しても、短いスパンでは確率は牙を剥きます。
打ち手のリアリティに合わせて、2つの時間軸で挙動を観測しました。
① 300G試行(短期決戦:約30分〜45分)
仕事帰りのちょい打ちを想定した回数です。100回分です。
設定1

設定6

考察: ちょい打ちくらいだと思ったより設定差は感じずらいんだなと結果からも見て取れますね。
② 3000G試行(中期戦:約4時間〜5時間)
腰を据えて判別を試みる「半日実戦」のスパンです。
これくらいで小役の合算から打ち続けたりやめる人がいるかなという感じですね。
これもとりあえず100回分の分布です。
考察: 3000Gまで回すとようやく設定差が感じられるようになってきますね。でも設定6でも回してそこそこへこむこともあるのでやはり3000Gくらいだとボラがあります。
5. おわりに
仕組みをコードで書き、シミュレーションを繰り返すことで、普段何気なく叩いているレバーの裏側に広がる論理回路の解像度が上がりました。
また夜にちょっぴりたまに打つくらいなら設定を意識しても大差がないしふらっと遊んでもよさそうですね。
シミュレーションに使用したソースコードはGitHubで公開しています。16bit乱数による抽選ロジックや、フラグ配分(config)の詳細はリポジトリを参照してください。
(※リール配列等は独自に構成・改変した研究用のデータセットを使用しています)
今回はシンプルなAタイプの再現でしたが、次回はより変則的な状態管理が求められる、私が好きだった5号機の不人気Cタイプ某台の再現に挑戦してみたいと思います。
6. レポジトリ
使い方についてはREADME.mdに記載しています。

