回転するサイコロの状態をコード化してみよう

プログラミングの勉強をしている時に、以下のような問題に出会いました。


**問題の内容**
===
>六面体のサイコロの初期状態として、以下の情報が与えられる。
　　・サイコロを上から見た面の数字
　　・サイコロを正面から見た面の数字
　　・サイコロを右から見た面の数字
このサイコロを上下左右に複数回転がした後、
サイコロを上から見た面の数字を出力せよ

　

**すべてのパターンをコードにべた書きできる？**
===
まず、すべてのパターンをコードにべた書きすると、
何パターン書く必要があるのかを考えてみます。
　　・サイコロを上から見た面（1つ目の面）の数字が**6パターン**
　　・サイコロを正面から見た面（2つ目の面）の数字が残りの**5パターン**
　　・サイコロを右から見た面（3つ目の面）の数字がさらに残りの**4パターン**
　　・その初期状態から、上下左右に回転するので**4パターン**
これらを掛け合わせると、
　　6 * 5 * 4 * 4 = **480パターン**
と非常に多く、全てコードにべた書きするのは現実的ではありません。

```python
# 転がる前のサイコロの状態
if (dise_top == 1) & (dise_front == 2) & (dise_right == 3):

    # サイコロが転がる方向
    if (direction == "up"):
        
        # 転がった後のサイコロの状態
        dise_top = 2
        dise_front = 6
        dise_right = 3
```
こんな内容を480パターンも書きたくない。

:::note info
「六面体のサイコロの向かい合った面の和は7になる」という法則があるので、
実際のパターンはもっと少なくなりますが、話の本筋とは外れるためここでは議論しません。
:::

　

**回転前のサイコロの状態と回転した方向から
　回転後のサイコロの状態を求められるのか？**
===
続いて
　　・回転前のサイコロの状態（上、正面、右から見た面の数字）
　　・回転した方向（上下左右）
の情報から、
　　・回転後のサイコロの状態（上、正面、右から見た面の数字）
が求められるかを調べてみます。

具体例を挙げて考えてみます。
　　・回転前のサイコロの状態が以下の状態の時に、
　　　　・上から見た面の数字：1
　　　　・正面から見た面の数字：2
　　　　・右から見た面の数字：3
　　・「上」方向に回転すると、
　　・回転後のサイコロの状態は以下の状態となる。
　　　　・上から見た面の数字：2
　　　　・正面から見た面の数字：6
　　　　・右から見た面の数字：3

ここで回転後のサイコロの状態は、
回転前のサイコロの状態を使って以下のように表すことができます。
　　・上から見た面の数字：**回転前の正面から見た面の数字「2」と同じ**
　　・正面から見た面の数字：**回転前の底面の数字（7 - 回転前の上から見た面の数字「1」）**
　　・右から見た面の数字：**回転前の右から見た数字「3」と同じ**
これは今回の回転前のサイコロの状態に限らず、
「上」方向への回転であれば同じ結果になります。

:::note info
底面の数字を求めるのに「7 - 【上から見た数字】」としているのは、
「六面体のサイコロの向かい合った面の和は7になる」という法則があるためです。
:::

　

**上方向「以外」に回転した場合も
　回転後のサイコロの状態を求められるのか？**
===
前段落で「上」方向に回転した場合に、
回転後のサイコロの状態を、開店前のサイコロの状態で表せることを示しました。

他の「下・左・右」方向に回転した場合も同様に、
回転後のサイコロの状態を、開店前のサイコロの状態で表すことができます。

　・「下」方向に回転
　　　・上から見た面の数字：**回転前の背面の数字（7 - 回転前の正面から見た面の数字）と同じ**
　　　・正面から見た面の数字：**回転前の上から見た面の数字と同じ**
　　　・右から見た面の数字：**回転前の右から見た数字と同じ**

　・「右」方向に回転
　　　・上から見た面の数字：**回転前の左面の数字（7 - 回転前の右から見た面の数字）と同じ**
　　　・正面から見た面の数字：**回転前の正面から見た数字と同じ**
　　　・右から見た面の数字：**回転前の上から見た数字と同じ**

　・「左」方向に回転
　　　・上から見た面の数字：**回転前の右から見た数字と同じ**
　　　・正面から見た面の数字：**回転前の正面から見た数字と同じ**
　　　・右から見た面の数字：**回転前の底面の数字（7 - 回転前の上から見た面の数字）と同じ**

これで全てのパターンにおいて、
　　・回転前のサイコロの状態
　　・回転する方向
の情報があれば、
　　・回転後のサイコロの状態
が表せることがわかりました。

　

**コード化してみよう**
===
ここまでの内容を Python の関数としてコード化すると、
以下のようになります。

```python
# 回転後のサイコロの状態を調べる関数
def roll_dice(before_top, before_front, before_right, direction):

    # サイコロが回転する方向が「上」だった場合に、回転した後の状態を設定する
    if (direction == "up"):
        after_top = before_front
        after_front = (7 - before_top)
        after_right = before_right

    # サイコロが回転する方向が「下」だった場合に、回転した後の状態を設定する
    elif (direction == "down"):
        after_top = (7 - before_front)
        after_front = before_top
        after_right = before_right

    # サイコロが回転する方向が「左」だった場合に、回転した後の状態を設定する
    elif (direction == "left"):
        after_top = before_right
        after_front = before_front
        after_right = (7 - before_top)

    # サイコロが回転する方向が「左」だった場合に、回転した後の状態を設定する
    elif (direction == "right"):
        after_top = (7 - before_right)
        after_front = before_front
        after_right = before_top


    # サイコロが回転した後の状態を戻り値として返す
    return(after_top, after_front, after_right)
```

そしてこの関数を呼び出して、
結果出力をするコードは以下のようになります。

``` Python
# サイコロが回転する前の状態（上、正面、右から見た面の数字）
before_top = 1
before_front = 2
before_right = 3

# サイコロが回転する方向
direction = "up"

# 回転後のサイコロの状態を調べる関数を呼び出す
after_top, after_front, after_right = roll_dice(before_top, before_front, before_right, direction)

# 結果出力
print("回転後のサイコロを上から見た面の数字 ->", after_top)
print("回転後のサイコロを前から見た面の数字 ->", after_front)
print("回転後のサイコロを右から見た面の数字 ->", after_right)
```

結果は以下のようになります。

``` Python
回転後のサイコロを上から見た面の数字 -> 2
回転後のサイコロを前から見た面の数字 -> 6
回転後のサイコロを右から見た面の数字 -> 3
```

もちろん「サイコロが回転する前の状態」や「サイコロが回転する方向」の変数を変えれば、
別の結果が出力されますし、
`for`文を組み合わせれば、複数回回転した後のサイコロの状態も求めることができます。
ぜひ活用してみてください。