乱数を使ったガチャを作成してみましょう。
1 もくじ
2 乱数
randomモジュールを用いると、ランダムな数を生成したり、リストからランダムに抽出することができます。
2.1 random.randint()
random.randint(a,b)を使ってa~bまでの整数を生成します。
以下のコードを実行してみてください。さいころと同じふるまいをします。
1行目のimport randomで、randomモジュールを読み込み、使用できるようにしています。
実行結果
3
- Challenge6-1 上のプログラムを改造して、1~50までの乱数を表示するプログラムを作成しましょう。
- Challenge6-2 さらに改造して、2~100までのランダムな偶数を表示するプログラムを作成しましょう。
ヒント: 2から100までの偶数を数学的に書くと2n
(1 <= n <= 50)となります。
解答
Challenge6-1: print(random.randint(1,50))
Challenge6-2: print(random.randint(1,50) * 2)
2.2 random.choice()
random.choice(list)を使ってlistからランダムに要素を選択します。
以下のコードを実行してみてください。魚の名前が入ったリストからランダムに選択して表示します。
実行結果
アジ
2.3 random.choices()
random.choices(list,k,weights)を使ってlistからランダムに複数の要素を選択します。
random.choices()で選択された要素は重複することがあります。重複させたくない場合はrandom.sample()が用意されています。
以下のコードを実行してみてください。魚の名前が入ったリストからランダムに3つ選択して表示します。
実行結果
['タイ', 'イワシ', 'イワシ']
さらには重みをつけることもできます。引数weightsで確率を指定します。
import random
fishes = ["アジ","サバ","イワシ","タイ","サメ"]
fish_weights =[30,30,30,8,2] #アジ,サバ,イワシ30%、タイ8%、サメ2%
print(random.choices(fishes,k=10,weights = fish_weights))実行結果
['サバ', 'イワシ', 'アジ', 'サメ', 'アジ', 'サバ', 'イワシ', 'アジ', 'イワシ', 'イワシ']
配列からランダムな要素を重み付きで取り出す
random.choices()を使えば、random.choice()ではできなかった、重みをつけて要素を取り出す操作ができました。
では、魚の名前のリストではなく魚の名前そのものが欲しいとき、どうすれば良いでしょうか。
まずは、先ほどのコードをk=1と書き換えて実行してみましょう。
import random
fishes = ["アジ","サバ","イワシ","タイ","サメ"]
fish_weights =[30,30,30,8,2] #アジ,サバ,イワシ30%、タイ8%、サメ2%
print(random.choices(fishes,k=1,weights = fish_weights))実行結果
['イワシ']
ここで注意したいのは、k=1と指定しても、要素数1の配列が返ってくることです。配列の要素を取り出すには、list[0]のようにインデックスで指定します。
random.choices(・・・)[0]と指定することで、配列からランダムな要素を重み付きで取り出せます。
import random
fishes = ["アジ","サバ","イワシ","タイ","サメ"]
fish_weights =[30,30,30,8,2] #アジ,サバ,イワシ30%、タイ8%、サメ2%
print(random.choices(fishes,k=1,weights = fish_weights)[0])実行結果
イワシ
2.4 応用
以下の要件を満たすプログラムを作成していきましょう。
レア度は★1~★3まであり、排出率は以下の通りです。
★1: 75% ★2: 20% ★3: 5%
それぞれのレア度には3種類の魚があり、以下のリストの通りです。同じレア度の中で何が選ばれるかはランダムです。
先ほどの例をそのまま使えば以下のようになりますが、これではあまりよくありません。
import random
FISH_LIST = ["アジ","サバ","イワシ","カワハギ","タチウオ","メバル","タイ","スズキ","カサゴ"]
FISH_WEIGHT = [25,25,25,20/3,20/3,20/3,5/3,5/3,5/3] #それぞれの排出率
print(random.choices(FISH_LIST,k=1,weights=FISH_WEIGHT)[0])要件通りには動くのですが、他人や未来の自分にとって読みにくく、何か改良しようとすると大変なコードです。具体的には以下の欠点が挙げられます。
- どの魚がどのランクなのかわかりにくい
- それぞれのランクの排出率がわかりにくい
- 魚の種類を追加したとき、
FISH_WEIGHTを何か所も変更する必要がある。
これらを解決するためにはどうすれば良いでしょうか。
今回は初めにレア度を排出率に従って決定し、次にその中からランダムに魚を選ぶ方法を取りましょう。まずは排出率に従って「★n」と表示するプログラムを作成します。
import random
FISH_LIST = ["★1","★2","★3"]
FISH_WEIGHT = [75,20,5] #★1~3の排出率
print(random.choices(FISH_LIST,k=1,weights=FISH_WEIGHT)[0])実行結果
★1
次に、「★n」の部分をそれぞれの魚のリストに置き換えます。
import random
STAR_1 = ["アジ","サバ","イワシ"]
STAR_2 = ["カワハギ","タチウオ","メバル"]
STAR_3 = ["タイ","スズキ","カサゴ"]
FISH_LIST = [STAR_1,STAR_2,STAR_3] #2次元配列であることに注意!
FISH_WEIGHT = [75,20,5] #★1~3の排出率
print(random.choices(FISH_LIST,k=1,weights=FISH_WEIGHT)[0])実行結果
['アジ', 'サバ', 'イワシ']
リストが出力されているので、さらにこれをrandom.choice()で選択すれば良いですね。
import random
STAR_1 = ["アジ","サバ","イワシ"]
STAR_2 = ["カワハギ","タチウオ","メバル"]
STAR_3 = ["タイ","スズキ","カサゴ"]
FISH_LIST = [STAR_1,STAR_2,STAR_3] #2次元配列であることに注意!
FISH_WEIGHT = [75,20,5] #★1~3の排出率
print(random.choice(random.choices(FISH_LIST,k=1,weights=FISH_WEIGHT)[0]))実行結果
サバ
うまくいきました!これは釣りゲームの部品になるので、後で再利用できるように適当な名前を付けて保存しておきましょう。 これはよくない例と比較して格段に修正、改造しやすくなっています。次のChallengeで確認してください。
- Challenge6-3 上のプログラムを改造して、★2に「コイ」を追加しましょう。
- Challenge6-4 ★4の魚を追加してみましょう。排出率も適当に調節してください。