先日は、

 

 

にて乱数を使ったミニゲームを作った見ました。スロットマシンの雛形になります。コードは、

 

 

名感じになっていますが、この部分が内部処理を用意したものになります。

 

 このサンプルコードは乱数を使っているのですが、 【 当たりにくい 】 ので、とにかくスコアが上がらない状態になっています。つまり、 【 増えない 】 仕様になっています。

 

 この乱数の仕組みですが、ランダムで範囲指定をシて、その総数を分母とした確率で二にの数値が選出されます。これが、3つ個別に行われているので、1/10の確率が3つあることになります。

 

 一つの条件での確率は、【 1/総数 】なので結果は総数を分母にした分数で示すことが出来ますが、これが組み合わさると、個別の条件に対してこの確率が発生します。

 

   ■ 2つの場合 : 1/10*1/10=1/100

   ■ 3つの場合 : 1/10*1/10*1/10=1/100

 

になります。これが、10種類で発生するので、1/10になるので、1/10と1/100に確率を抑えてあるのですが、2つの場合は、前後出揃うので1/5でくることを想定しています。これは、

 

 【 2つ揃う場合 】

 

   ■ 0〜9の中のどれかが揃う 【 x10 】

   ■ 前3つか後ろ2つが揃う  【 x2   】

 

ですから、確率は元の1/100の20倍なので、理論上は1/5で発生することになります。この場合、乱数が均一に拡散する場合だとそうなりますが、津城の乱数はそうではないので、Pythonの場合だと、systemモジュールの中の乱数を使うことになります。

 

 これを使うと、しっかりとばらつきが生じるようになるので、意図した確率を取得できますが、この事例では、

 

  ■ 抽選確率 : 乱数の確率

  ■ 当選確率 : 判定用の条件

 

が存在しています。抽選をする場合には、この2つを用意することで、 【 抽選確率 】 を調整することができるのですが、これが、【 乱数の重み付け 】 の基本的な考え方になります。

 

 

  乱数と確率

 

 先日のコードのように 【 プレイヤーにわからないような不確定な要素 】 を追加する際に乱数を使いますが、乱数も対象物があって初めて成り立つものなので、 【 総数 】 を用意することになります。それに対して、均一に分布する条件で無作為に一つの条件を抽出するのが乱数なので、乱数を使う場合 【 対象の総数 】 を用意する必要があります。

 

 少なくとも、乱数を使う場合 【 目的 】 が存在するので、その事例がどういったものなのかで条件が変わってきます。

 

  家庭用ゲーム機が存在せず、コンピューターが大学にしかなくホストコンピューターにゼロクライアントのような端末でアクセスしているような時代だと、アナログのゲームしか存在しないので、定数を用意してそこにプレイヤーの選択が可能な変数で遊ぶのもが存在していましたが、乱数を用意する場合にはアナログの乱数発生装置を実装する必要がありました。その代表例がダイスやカードの並びを変更すると言う方法になりますが、1970年代に登場したテーブルトークRPGでも行動の結果は乱数で決めるようになっているので多面体が使用されていました。その為、

 

 

のようにいろいろな多面体が存在していますが、通常のダイスが6面体でそれ以外のものは見慣れないダイスだと思います。これを用いることで、1/6や6の倍数以外の乱数を選出することができるような作りになっています。

 

 その為、1~nまでの乱数を取得する場合には、多面体を使用することになり、nのa倍のような条件だと多面体を複数回振ることになります。これが乱数の要素になりますが、ゲームに不確定要素を追加する場合にはこのように乱数を実装することになります。このダイスの使い型は 

 

  ■ 最小値

  ■ 最大値

 

を設けることで、 【 事象に対する特性 】 を実装するためのものになりますが、この乱数の要素だけでなく、得意分野は失敗しにくいと言う要素を追加するために 【 補正 】 によって成功確率の調整が行われています。

 

 このように 【 判定に対してバランス調整がされている 】 ので、 【 乱数をそのまま使わない仕様 】 になっています。

 

 テーブルトークRPGの場合、多面体を使用することで乱数を取得する仕様になっていますが、

  ■ 1〜nまでの数値
 
を取得する際に多面体を使用して、

  ■ 2以上〜nでの数値

を選択する場合には、最小値がダイスを振る回数で、最大値はその倍数をかけた時にその数になる多面体を使用します。こうすることで、乱数の範囲をダイスだけで構成してあるわけですが、降る回数をxとした場合、

  ■ ダイスを1回振る  : n
  ■ ダイスを複数回振る : nx

で処理をすることが出来ます。これがゲーム内での判定で使用するものになりますが、選択において成功と失敗の条件が存在しており、その条件の成功確率はダイスを使った乱数で決まるというのがテーブルトークRPGでの判定になりますが、全てが乱数任せではなく 【 得手不得手 】 の概念があり、得意なものには補正がかかるので成功しやすいなどの条件があります。これが、得意分野や不得意分野が同じ確率にならないという至極当然なバランス調整になりますが、ゲーム内ではこうした 【 ごく当たり前に存在する条件の実装 】 が行われています。つまり、均一な乱数を使うと抽選機での判定になるので、何をシても同じ確率になるとい非現実的なもの担ってしまいますから、そうならないような調整がシステム内で実装されています。

 乱数は中学校3年制の数学で 【 乱数表 】 という形で登場しますが、組み合わせや確率については、中学校2年制の数学で登場します。この時に、総数が決まっているものから特定の数を抽出する場合の確率や、全ての条件で考えた場合の確率を算出する方法を学習することになります。

 これが、乱数の使い方になりますが、乱数の基本的な考え方が

  ■ 分子 : 乱数の重み
  ■ 分母 : 確率を構成する事象の総数

なので、実質的に、この状態をどのように実装するのかを考えることになります。テーブルトークRPGでなにかの判定を行う場合、確率は1/nになりますが、この場合、通常のサイコロだと1/6の確率になります。これを1/3にする場合には、2度降って2〜4であればいいという条件を作れますが、この分母を多面体の面の数とそこに書かれた数値で判定を行うので、乱数の分母を多面体の面の数を使用することで指定して、その総数を増やす場合には、面の数を増やすことになります。そして、乱数の重みの場合、出目の範囲になりますから、分母を増やしたい場合には多面体の面の数と振る回数を増やすことになります。そして、その総数に対して、出目の最小値を1として考えた時にどの程度の範囲を倍数で指定するのかを数値で決めることになります。この際に

  ■ 面が少なく振る数が多い   : 最小値が大きい
  ■ 面が少なく振る回数が少ない : 最小値が小さい

ので、最大値が同じでも

  ■ 四面体x6 : 6〜24
  ■ 六面体x4 : 4〜24
  ■ 八面体x3 : 3〜24

のように値が変わってきます。その為、 【 乱数だけでなく、範囲を持った数値の生成 】 についてもダイスの面と係数による制御で処理が行われています。これに補正がかかるので、乱数はゲーム内での一つの要素でしかなく、その要素を使って進行時の内容が定数化しないような作りになっています。ちなみに、この組み合わせにすると、

【 一つの値が出る確率 】

  ■ 四面体x6 : 1/18
  ■ 六面体x4 : 1/20
  ■ 八面体x3 : 1/21

のようになるので、多面体だけだと作れない数値も用意することが出来ます。また、比較もできるので、 

  ■ 出目 : n
  ■ 判定 : x

とした場合に

  ■ x>n
  ■ x<n

のような条件を用意してロールを使うことも出来ます。このように判定用の定数を事前に用意して比較をすることで成功の可否を決める仕様になっているので、乱数とは別に変数発生機としてもダイスが使用されています。

 このようにシステムを用意して運用する場合には、

  ■ 定数
  ■ 変数
  ■ 乱数

の要素が存在しており、不確定要素として乱数を使うことになりますが、乱数発生器を作る場合には、対象の総数を決めた上で乱数を使用しますが、テーブルトークRPGでは、乱数の総数がダイスの面の数で、重みがその数値の使い方になります。

 この際に分母に係数を加えることで発生確率を下げ、その中で発生する最小値から最大値までの間に存在する数値に変域を設けることで乱数の重みを調整する仕組みになっています。乱数をアプリケーションの中に実装する場合には、この 【 重みを付ける作業 】 が必要になるので、抽選機で確率が全て均一な乱数発生器を1つだけ用意して運用するようなことはありません。

 こうした内容も中学校2年生の数学で登場する確率と組み合わせの知識に基づくものですから、その時の抽選をする選択を行う装置が 【 乱数発生器 】 なので、元になる知識は確率と組み合わせになります。

 

 

 

  処理と乱数


 処理を実装する際には、先程の3つのものを使うことになりますが、

  ■ 定数 : 確定したもの
  ■ 変数 : 変化するもの
  ■ 乱数 : 不確定、偏りのない分布

を求める際に使用します。

 中学校1年生の数学の 【 項 】 のカリキュラムで登場する定数と変数については、電気すら使用していない歯車の時代から存在していますから、システムを作る際には確実に使用するものになります。

 デジタルではなく、アナログなゲームで考えてみると

  ■ 定数 : ゲームシステム
  ■ 変数 : プレイ中の状態

になります。例えば、カードゲームを使った場合、手札によってプレイヤーの選択が変わりますが、これは定数化したものではありませんし、思いつきで任意のものを切ると負けてしまうので、少なくとも条件を用意してその中から最適解と思えるものを選出しているはずです。ということは、カードが配らられた時の状態は常に異なるので、同じ状態が続くことはありませんから、このカードの抽選は乱数と考えることが出来ます。つまり、

  ■ 抽選
  ■ カードの並び

は乱数によって得た結果ということになります。この順番通りにしかカードを出せない場合、配置は乱数ですが、配り終わった時の状態は確定しているので定数ということになります。

 このカードを組み合わせて戦術を建てる場合、この乱数によって生じたカードの並びから対策を練る必要が出てきます。この場合、戦術は常に変化するので変数ということになります。また、ゲームシステムで考えた場合、手札の枚数が決まっている場合には定数ですが、カードの枚数を決めた後にその場所に格納されるカードの種類は決まっていません。つまり、この条件では、【 区画の数 】 が定数であり、【 そこに入るデータ 】 については 【 変数 】 ということになります。

 ゲームシステムを考える場合、

  ■ 確定したデータ
  ■ 確定していないデータ

を最初に決めておく必要があります。というのも

  ■ 乱数 ⊂ 確定していないデータ
  ■ 変数 ⊂ 確定していないデータ

ですから、最初に確定の有無でデータの仕分けをシておくと作業がしやすくなります。つまり、

  ■ 1 : 確定したデータ
  ■ 0 : 確定していないデータ

のように分けておいて、確定していないデータについては、

  ■ 1 : 乱数
  ■ 0 : 変数

のように分けることが出来ます。こうして考えると、この区分けは2ビットのデータがあれば行えることが解りますが、このよう二項目をカテゴライズして考えると、システムの中のデータをどのように扱えばいいのかを明確にすることが出来ます。

 テーブルトークRPGでもシステムは確定したものになっていますから、例外措置はないのでルールブックの内容は 【 定数 】 と考えることが出来ます。また、キャラクターシートもデータ部分についてはフォーマットが決まっているので定数ですし、その策定方法やプレイヤーの選択できる内容についても定数で選択できる項目を策定してあります。当然、冒険の中で登場するモンスターについてもルールブック内で登場するものなので定数になっています。これが、 【 ゲームを作れるフレームワークのように仕様が策定されたもの 】 として販売されているルールブックになります。

 つまり、この商品は 【 ゲームを作るためのフレームワーク 】 なので、用意されたシステムに準拠したゲームを作ることができる仕様なので、そこに登場する世界や物語を作って、プレイヤーの体験できるゲーム自体を作る必要があります。これを行うのがマスターですが、基本的に進行するためのシナリオを作ることになるので、ここが乱数や変数では行きあたりばったりでひどい状態になるので、こうした部分も定数として確定させたものを用意する必要があります。

 つまり、変数で登場する部分はプレイヤーの行動やその時のイレギュラーな行動による分岐などになります。

 基本的に、テーブルトークRPGもゲーム制作ができるソフトを使ってゲームを作るようなイメージなので、

  ■ スマイルビルダー
  ■ RPGツクール

などのようにある程度決まったものがあって、その中でゲームを作っていくようなものと同じ考え方になりますが、ゲームのような容量の成約はないので自由な選択ができるようになっています。

 この時のプレイヤーの選択肢が変数で、ゲーム内で登場する会話の内容も何を話すのかは不明ですからここも変数になります。

 ロールや戦闘時の命中やダメージの判定も仕様は定数ですが、何が出るのかは不明ですからデータそのものは変数で、ロールを行った際の抽選がダイスを使った乱数の結果ということになります。

 このように、システム内で

  ■ 定数
  ■ 変数
  ■ 乱数

が存在するわけですが、あくまでも乱数は、【 確定した確率が存在しており、その抽選時に使用するもの 】 でしかないので、制御をする際には定数化した確率を用意することになります。
 

 

 

  ソフトウェアと値


 システムを考える場合だと、決まった動きをする場合には定数と変数で制御をすることになりますが、この場合、

  ■ 定数 : 動かないもの
  ■ 変数 : 変化するもの

を使用することになります。先日のコードだと、

  ■ 定数 : 文字列
  ■ 変数 : 変化する数値

で使用していますが、システムを作る場合には、この2つを明確にしておく必要があります。先日は、この変化する数値を

  ■ 乱数 : 値の抽選
  ■ 変数 : スコアの変化

で行っていますが、ifを使用した判定では変数を比較演算子を使うことで等号で結べる場合にスコアの変化が出るような条件にしています。

 これが、先程の

  ■ 定数
  ■ 変数
  ■ 乱数

を目的に応じて使用した事例になりますが、先日のコードでは、

  ■ スコアの変化
  ■ 数値の変化
  ■ 数値の並び
  ■ 文字列の表示

を扱っています。この時に

  ■ スコアと文字列の並びの関係性

でスコアの変化が生じているわけですが、定数でスコアが変わる仕様なので、スコアの変化は小学校1年生で学習する加減算で行っています。
 
 変化の基本は加減算ですから、それをどのように扱うのかで使用する処理の方法が変わってきますが、その知識を数学で身につけていくことになります。

 

 

 

  マイクラと乱数


 マインクラフトでも乱数は用意されており、ドロッパーやディスペンサーがそうした機能を持ったブロックになっています。

 これは個数と位置で乱数の確率が変わる仕様になっていますが、その抽選をランダムで行う仕様になっています。なので、異なるアイテムを個別のスロットに配置すると出てくるものが常に変化します。


統合版だと、ピストンの動きで乱数をコントロールできるので、


のような挙動を実装できるので、これを並列化するトトで


のような0〜9の値を取得したり、


のように2つの異なる1〜3の状態を作れるので乱数同士でジャンケンをすることも出来ます。また、確率は、乱数の分子を増やせば変更できるので、それを行うことで乱数の重みの調整をすることも出来ます。


このように 【 サバイバルモードでもレッドストーンを使うと乱数を使える 】 ようになっていますが、配布ワールドを作る場合には、コマンドブロックが使用できるので、変数と乱数を数値の形で利用することが出来ます。その為、乱数を使って動作する仕組みをコマンドを使って実装することも出来ます。
 

 

 

  ゲームとシステム


 ゲームを作る場合、コード内に

  ■ 確定した要素
  ■ 不確定な要素
  ■ 変化する要素

を用意することになりますが、先日のコードでは、

  ■ 乱数による抽選
  ■ プレイヤーは結果待ち

という条件になっていました。この場合、プレイヤーは出る結果を待つだけですが、種類で考えると、これは受動的なコンテンツになります。つまり、プレイヤーに選択権がなく、あくまでも乱数の結果を待つだけのものになっています。これが、ルーレットやスロットに見られる 【 結果待ち 】 だけが存在するものになります。

 ルーレットやスロットを実際にコードで作る場合は作り方が全く異なるのですが、ルーレットの場合だと、

  ■ 3種のパターン
  ■ 数値の確定方法

を決めて、そこに付加要素を追加します。つまり、配列にパターンを用意しておいて、その数値を入れ替えていくような考え方になります。実際のスロットは回転していますから、ラジアンで回転しているものを制御するほうが考えやすいのですが、義務教育の度数法で考えると

  ■ 何回転したのか?
  ■ 何度回ったのか?

という状態を考える必要があります。これを同じにした場合、3つのリールは同時に止まりますが、絵柄が違うので並びもかとぁってきます。これだと、同じ絵柄の並びが変わるだけなので、これが揃う条件をつけようと思うと、 【 2つ目と3つ目のリールの回転を変える 】 ことでズレが生じるので絵柄が徐々にずれていくことになります。それにより用意された絵柄が揃うようになるわけですが、この時に仮に6つの絵柄を用意したものが変化する用意した場合、表示の角度は360/6ですから、60度になるので、これを1として考えた時に、係数がいくつになるのか?を指定することになります。これを増やすと回転数が増えますが、

【 絵柄が揃う要素はズレの部分だけ 】

なので、

  ■ 回転した回数
  ■ ズレの量

が生じるものの、実際に使用しているのはズレの量になります。つまり、操作が出来ない状態で多く回っているのは、法則性をすぐにわからないようにしてあるのと、抽選しているように見せる為のただの演出のようなものなので、構造で見るとずれた量によって生じた結果が必要なものになります。そう考えると、乱数で数値を抽出する条件では異なり、

  ■ 配列内のデータの並び
  ■ 抽選時のズレの量の指定

で変化することになりますから、実際には、この構造物は 【 定数で管理できる構造物 】 になっています。なので、運の要素は存在せず、乱数を使わなくても実際にはこうした構造物は作れます。では、これを回転数によって生じる 【 並び 】 以外の条件で揃える要素を加える場合にはどうすればいいのか?というと 【 ループによる値の変化を止める 】 ことで、数を確定させることになりますから、ここで初めて 【 UI 】 の概念が登場します。つまり、 【 操作 】 を入れることでそれが可能になります。つまり、これを行うことで、

  ■ 定数による諸理
  ■ 変数による制御

が成立することになります。この状態だと、確定した状態で値を止めることができるので、チートが入っている場合には 【 ズレる 】 わけですが、当選確率の変化を加える場合だと、回転数自体を変えたり、回転速度を変えるなどして揃いやすくする方法があります。

 つまり、

  ■ 構造物自体は定数
  ■ 処理のシステムが条件分岐
  ■ 操作部分がイベントハンドラ

という構造になっているので、コードでその仕様のものを実装しようと思うと、意外と簡素な構造になっています。

 ルーレットは、回転数が決まっているので、一次関数のように回転数で0からの変化が生じるようになっており、そこにスタート段階の値が決まっているので、初期値を追加した構造になっています。その為、ルーレットの場合、

  ■ 出 目 : y
  ■ 回転数 : x
  ■ ズレ  : b

とした場合、 y=x+b の状態で変化していることになります。この場合、0を基準いまわした場合、最終的に+bだけズレるので、この初期値が変化していくことで次に同じ場所に来る区画は+bをシたものということになります。流石に、これだとゲーム性がないので、 【 ディーラーが玉を投げ込む 】 わけですが、これで、止まった位置と関係ない場所に玉が入る可能性が出てくるので、実質的にルーレット自体の数値の位置関係とアタリの関係性が皆無な構造になっています。こうした物を作る場合、回転数に乱数の要素を加えてみたり、ダイナミクスで玉とルーレットの挙動を調整すると位置なっ径のコントロールが出来ますが、昭和のコインゲームコーナーの発光体で判定をするようなゲームのように回転していったあとに位置が決まるようなルーレットの場合だと、乱数で抽選をする前に前に回転の演出を加えたようなものと考えることが出来ます。

 乱数を使ったゲームをだと、数の範囲を少なくした 【 数ゲーム 】 のようなものだと

  ■ 乱数の発生
  ■ 数値の入力
  ■ 等号での判定

程度で行えるので可否という二値の判定だけで作ることが出来ます。

 【 1〜3の中の数値野中のどれかを選ぶのでその数を当てる 】

というものがあった場合、この数値を入力して結果を待ち、合否の確認をするようなものがそれになりますが、これにルールを追加したものがジャンケンになります。

 ジャンケンの場合、

  ■ 勝利条件
  ■ 引き分け

というルールがあり、その条件に基づいて判定をするので、


のような判定が存在します。これが、二人の場合だと、それぞれが異なるものを用意しますから、個別の判定を実装する必要があります。つまり、この判定を横宝庫に見た時の条件をそのまま条件分岐で実装することになりますから、1〜3の条件の場合、

  ■ プレイヤーが1の場合
  ■ プレイヤーが2の場合
  ■ プレイヤーが3の場合
 
の個別の処理に対して、相手が1〜3のいずれかを出した判定を用意することになります。その為、表と同じように9つの判定を実装することになりますから数当てよりも複雑な処理を実装することになります。ただし、数値でこれを管理した場合、変数とコンピューターの乱数の組み合わせで判定をすればいいので、実際には数当てゲームと同じで比較演算子で等号で判定を行い、

  ■ かち
  ■ まけ
  ■ ひきわけ

の判定を行うことが出来ます。これが、コイントスよりも複雑な判定を入れたものになります。