サイコロを10回振る

目次
  • 解説
  • 1. importと定数設定
  • 2. サイコロを振る処理を関数にする
  • 3. サイコロを10回振って配列に入れる
問題に挑戦!
進捗を変更する




解説

1. importと定数設定


次はサイコロを10回振ってみます。まずは前回と同様にimport定数などの準備をしましょう。

(1)Colab上で「step02.ipynb」を新規作成してください。
(2)下記のコードを最初のセルに入力して、
ランタイム」 > 「すべてのセルを実行」してください。
# インポート
import random

# 定数
DICE_A = 'サイコロA'
DICE_B = 'サイコロB'
DICE_A_MAX = 6
DICE_B_MAX = 6
ROLLS = 10

# 各サイコロの最大値を表示
print('{}の最大値は{}です'.format(DICE_A, DICE_A_MAX))
print('{}の最大値は{}です'.format(DICE_B, DICE_B_MAX))

実行して次の結果が出力されればOKです。

サイコロAの最大値は6です
サイコロBの最大値は6です

2. サイコロを振る処理を関数にする


step01のセル3を10回書けばサイコロを10回振ることはできますが、関数配列for文によるループを使って効率化しましょう。まずは関数の定義です。

(1)乱数を発生させるためのモジュールrandom」を使うための
import文は既に設定済みですね。
(2)次のコードを新しいセルに追加してください。
# 「サイコロを振る」のと同じ状態を再現する関数
# 引数1つ目はint型、dice_max=サイコロの最大値
# 引数2つ目はint型、dice_min=サイコロの最小値、省略時は1
# 戻り値はint型、サイコロを振った結果の目の値
def roll_dice(dice_max: int, dice_min: int = 1) -> int:
    return random.randint(dice_min, dice_max)

ここでは関数を定義しただけで、呼び出していませんので、実行しても結果は変わりません。

step01のセル3で行っていた処理と見比べてみましょう。

ポイント

def roll_dice():

関数の先頭から見てみると、まず「def」と「roll_dice」があります。

defは「ここから関数ですよ」ということを明示するためだけのキーワードです。

roll_dice関数の名前で、作成者が自由につけることが可能です。変数名と同様にすべて小文字で単語の区切りをアンダーバーにするスネークケースを用いることが一般的です。

引数も戻り値もない最も単純な形式では、「def roll_dice():」のようにdefで始まり、関数名と丸括弧、そして最後に「:(コロン)」を書きます。

関数とインデント

defから始まった関数の中身は、defの先頭と比べて右に4文字ほどずれいます。このずれのことをインデントと言い、Colabではこのインデント半角スペース4文字が使用されます。

関数の中身はインデントが終わるまでとなります。

引数

関数を呼び出す際に丸括弧の中に置く値関数の入力のことを引数(ひきすう)と言うんでしたね。関数を定義する側では関数の名前に続く丸括弧に、「dice_max: int」のように受け取った引数を入れる変数名(仮引数)とそのを並べます。

dice_min: int = 1」のように仮引数へ代入まで行ってしまうことで、呼び出す際にその引数を省略することが可能になります。引数が省略された場合には、仮引数へ代入された値が関数内で使用されます。

とは、変数の中身がどんな形であるかを示す仕組みです。例えば数値の引数を入れる変数ならば、引数名の後ろに「: int」を付けます。これによって、呼び出す際に誤って文字列などを渡してしまう事を防ぐことが可能です。

実はPythonでは(の明示)は必須ではなく、変数には何を入れても構いません。あくまで「この変数は数値用ですよ〜」と言うヒントでしかなく、正式にもタイプヒントと呼びます。VSCodeなどのIDEがこれを理解して、「文字列入れちゃってるけど大丈夫?」と教えてくれるだけなのです。最初は自分のために明示して、型の違いに慣れることをおすすめします。

戻り値

関数が返す値関数の出力のことを戻り値(もどりち)と言うんでしたね。関数を定義する側では、関数の最後に「return XXXXX」とすることで、戻り値を返すことが可能です。また、そのを明示する場合には、defの行の最後に書く「:(コロン)」の手前に、「 -> int」のように矢印と型名を書きます。

3. サイコロを10回振って配列に入れる


定義した関数roll_dicefor文で10回呼び出して、その結果を配列に入れてみます。

(1)次のコードを新しいセルに追加して
ランタイム」 > 「すべてのセルを実行」してください。
# サイコロを10回振った結果を入れる配列
diceA_faces = []
diceB_faces = []

# for文で10回サイコロを振って配列に追加
# rangeで0〜9の数値を生成して、ループ毎に変数countに代入
for count in range(ROLLS):
    diceA_face = roll_dice(DICE_A_MAX)
    diceB_face = roll_dice(DICE_B_MAX)
    diceA_faces.append(diceA_face)
    diceB_faces.append(diceB_face)
    print('count:{} => {} = {} / {} = {}'.format(count, DICE_A, diceA_face, DICE_B, diceB_face))

print('{}を{}回振った結果は{}でした'.format(DICE_A, ROLLS, diceA_faces))
print('{}を{}回振った結果は{}でした'.format(DICE_B, ROLLS, diceB_faces))

実行して次のような結果が出力されればOKです。

count:0 => サイコロA = 5 / サイコロB = 4
count:1 => サイコロA = 4 / サイコロB = 2
count:2 => サイコロA = 3 / サイコロB = 3
count:3 => サイコロA = 3 / サイコロB = 4
count:4 => サイコロA = 3 / サイコロB = 2
count:5 => サイコロA = 5 / サイコロB = 2
count:6 => サイコロA = 5 / サイコロB = 1
count:7 => サイコロA = 4 / サイコロB = 5
count:8 => サイコロA = 2 / サイコロB = 4
count:9 => サイコロA = 6 / サイコロB = 5
サイコロAを10回振った結果は[5, 4, 3, 3, 3, 5, 5, 4, 2, 6]でした
サイコロBを10回振った結果は[4, 2, 3, 4, 2, 2, 1, 5, 4, 5]でした

ポイント

配列と初期化

配列とは、同じ変数を複数まとめたものです。変数を定義する際、最初はデータが無い場合には、空っぽの配列を示す「[]」を代入しておきます。これを初期化と言います。

配列の要素と要素数

配列の中身ひとつひとつのことを配列の要素と言います。配列の中身が10個あるならば、要素数10の配列と呼びます。また、一般的に要素数のことを配列の長さとも表現するため、長さ10の配列とも呼ばれます。

配列への追加

配列にデータを追加する場合には、append関数を使います。この関数は配列として定義した変数で自動的に使えるようになります。コードの8行目と10行目から、roll_dice関数でサイコロを振った結果を、配列として初期化した変数diceA_facesに追加している様子がわかります。

for文によるループ処理

7行目をみると、「for」「count」「in」「range(ROLLS)」「:」の5つが見えます。

for〜in〜:」が基本セットで、関数と同じでインデントが終わるまでがこのfor文の中身です。

rangeという関数は、0から、引数として渡した整数のひとつ手前までの整数を配列として返してくれます。countという変数は名前を自由に付けています。

変数 in 配列」の形にすることで、変数に配列の中身をひとつずつ代入して、その度にインデントされた範囲の行を実行する、というのがfor文の役割です。

実行結果の「count:」をみると、0から9までが代入されていることがわかります。

問題

確認問題


確認問題1

この中で次の関数「sub」を使用したコードに対応する出力結果が正しくない組み合わせはどれか?

def sub(a: int, b: int = 1) -> int:
    return a - b
確認問題2

この中でfor文を使用したコードに対応する出力結果が正しくない組み合わせはどれか?

実践問題


問題

step02.ipynbの各セルに必要なコードを入力して、最大値が12であるサイコロCを追加して、サイコロを20回振った結果を出力させてください

実行結果例を表示
サイコロAの最大値は6です
サイコロBの最大値は6です
サイコロCの最大値は12です
count:0 => サイコロA = 5 / サイコロB = 2 / サイコロC = 2
count:1 => サイコロA = 5 / サイコロB = 3 / サイコロC = 11
count:2 => サイコロA = 3 / サイコロB = 1 / サイコロC = 6
count:3 => サイコロA = 6 / サイコロB = 3 / サイコロC = 4
count:4 => サイコロA = 6 / サイコロB = 1 / サイコロC = 8
count:5 => サイコロA = 3 / サイコロB = 2 / サイコロC = 8
count:6 => サイコロA = 3 / サイコロB = 3 / サイコロC = 9
count:7 => サイコロA = 6 / サイコロB = 5 / サイコロC = 5
count:8 => サイコロA = 5 / サイコロB = 5 / サイコロC = 9
count:9 => サイコロA = 3 / サイコロB = 3 / サイコロC = 5
count:10 => サイコロA = 3 / サイコロB = 4 / サイコロC = 2
count:11 => サイコロA = 3 / サイコロB = 1 / サイコロC = 11
count:12 => サイコロA = 6 / サイコロB = 1 / サイコロC = 3
count:13 => サイコロA = 1 / サイコロB = 6 / サイコロC = 4
count:14 => サイコロA = 6 / サイコロB = 6 / サイコロC = 3
count:15 => サイコロA = 5 / サイコロB = 4 / サイコロC = 5
count:16 => サイコロA = 4 / サイコロB = 3 / サイコロC = 2
count:17 => サイコロA = 4 / サイコロB = 2 / サイコロC = 3
count:18 => サイコロA = 2 / サイコロB = 2 / サイコロC = 11
count:19 => サイコロA = 6 / サイコロB = 4 / サイコロC = 6
サイコロAを20回振った結果は[5, 5, 3, 6, 6, 3, 3, 6, 5, 3, 3, 3, 6, 1, 6, 5, 4, 4, 2, 6]でした
サイコロBを20回振った結果は[2, 3, 1, 3, 1, 2, 3, 5, 5, 3, 4, 1, 1, 6, 6, 4, 3, 2, 2, 4]でした
サイコロCを20回振った結果は[2, 11, 6, 4, 8, 8, 9, 5, 9, 5, 2, 11, 3, 4, 3, 5, 2, 3, 11, 6]でした

正解


正解プログラムコード全文を表示
# インポート
import random

# 定数
DICE_A = 'サイコロA'
DICE_B = 'サイコロB'
DICE_C = 'サイコロC'
DICE_A_MAX = 6
DICE_B_MAX = 6
DICE_C_MAX = 12
ROLLS = 20

# 各サイコロの最大値を表示
print('{}の最大値は{}です'.format(DICE_A, DICE_A_MAX))
print('{}の最大値は{}です'.format(DICE_B, DICE_B_MAX))
print('{}の最大値は{}です'.format(DICE_C, DICE_C_MAX))
# 「サイコロを振る」のと同じ状態を再現する関数
# 引数1つ目はint型、dice_max=サイコロの最大値
# 引数2つ目はint型、dice_min=サイコロの最小値、省略時は1
# 戻り値はint型、サイコロを振った結果の目の値
def roll_dice(dice_max: int, dice_min: int = 1) -> int:
    return random.randint(dice_min, dice_max)
# サイコロをROLLS回振った結果を入れる配列
diceA_faces = []
diceB_faces = []
diceC_faces = []

# for文でROLLS回サイコロを振って配列に追加
# rangeで0〜ROLLS-1の数値を生成して、ループ毎に変数countに代入
for count in range(ROLLS):
    diceA_face = roll_dice(DICE_A_MAX)
    diceB_face = roll_dice(DICE_B_MAX)
    diceC_face = roll_dice(DICE_C_MAX)
    diceA_faces.append(diceA_face)
    diceB_faces.append(diceB_face)
    diceC_faces.append(diceC_face)
    print('count:{} => {} = {} / {} = {} / {} = {}'.format(count, DICE_A, diceA_face, DICE_B, diceB_face, DICE_C, diceC_face))

print('{}を{}回振った結果は{}でした'.format(DICE_A, ROLLS, diceA_faces))
print('{}を{}回振った結果は{}でした'.format(DICE_B, ROLLS, diceB_faces))
print('{}を{}回振った結果は{}でした'.format(DICE_C, ROLLS, diceC_faces))