AOJ の DICE 問題の解法

# AOJ プログラミング入門 (ITP1) - #11 構造体とクラス（DICE問題）

[AIZU ONLINE JUDGE](https://onlinejudge.u-aizu.ac.jp/courses/list) > [プログラミング入門 (ITP)](https://onlinejudge.u-aizu.ac.jp/courses/lesson/2/ITP1/1) > [#11 構造体とクラス](https://onlinejudge.u-aizu.ac.jp/courses/lesson/2/ITP1/11)

## [ITP1_11_A: DICE I](https://onlinejudge.u-aizu.ac.jp/courses/lesson/2/ITP1/11/ITP1_11_A)

- `Dice` クラスを作成する
    - `__init__` メソッドでインスタンス化する
    - `move` メソッドでサイコロの面を自由に入れ替える
    - `roll` メソッドで東西南北への動きを実行する
- サイコロを作って、動かして、面を見る

```{python}
class Dice():
    def __init__(self, sequence):
        self.sequence = sequence

    def move(self, code):
        return [self.sequence[int(idx)] for idx in str(code)]

    def roll(self, root):
        for d in root:
            if d == 'N': self.sequence = self.move(152304)
            elif d == 'E': self.sequence = self.move(310542)
            elif d == 'S': self.sequence = self.move(402351)
            elif d == 'W': self.sequence = self.move(215043)
                
dice = Dice(list(map(int, input().split())))
dice.roll(input())
print(dice.sequence[0])

```

## [ITP1_11_B: DICE II](https://onlinejudge.u-aizu.ac.jp/courses/lesson/2/ITP1/11/ITP1_11_B)

- サイコロの並べ方の候補を全て提示する
    - 6 通りに上面を定める
    - それぞれに対し、鉛直方向の回転を 4 回トライする
- 上面と前面とが合致しているときの右側の面の目を答える


```{python}
class Dice():
    def __init__(self, sequence):
        self.sequence = sequence

    def move(self, code):
        return [self.sequence[int(idx)] for idx in str(code)]

    def roll(self, root):
        for d in root:
            if d == 'N': self.sequence = self.move(152304)
            elif d == 'E': self.sequence = self.move(310542)
            elif d == 'S': self.sequence = self.move(402351)
            elif d == 'W': self.sequence = self.move(215043)

seq = list(map(int, input().split()))
for _ in range(int(input())):
    a, b = map(int, input().split())
    for ops in ('', 'N', 'W', 'E', 'S', 'NN'):
        dice = Dice(seq)
        dice.roll(ops)
        for _ in range(4):
            dice.roll('NES')
            if dice.sequence[0] == a and dice.sequence[1] == b:
                print(dice.sequence[2])

```

## [ITP1_11_C: DICE III](https://onlinejudge.u-aizu.ac.jp/courses/lesson/2/ITP1/11/ITP1_11_C)

### 案 1: `NewDice` クラスを実装する

- `Dice` クラスを継承する
    - `candidates` でサイコロの並べ方の候補を全て提示する
    - `self.candidates` で並べ方の全候補を提示する
    - `__eq__` メソッドで `self.candidates` の「最小値」に基づいた `==` を定義する
- 二つの `NewDice` インスタンスの `==` を判断する

```{python}
class Dice():
    def __init__(self, sequence):
        self.sequence = sequence

    def move(self, code):
        return [self.sequence[int(idx)] for idx in str(code)]

    def roll(self, ops):
        for op in ops:
            if op == 'N': self.sequence = self.move(152304)
            elif op == 'E': self.sequence = self.move(310542)
            elif op == 'S': self.sequence = self.move(402351)
            elif op == 'W': self.sequence = self.move(215043)

class NewDice(Dice):
    def __init__(self, sequence):
        super().__init__(sequence)
        self.candidates = []
        for ops in ('', 'N', 'W', 'E', 'S', 'NN'):
            dice = Dice(self.sequence)
            dice.roll(ops)
            for _ in range(4):
                dice.roll('NES')
                self.candidates.append(dice.sequence)

    def __eq__(self, other):
        return min(self.candidates) == min(other.candidates)
        
print('Yes' if NewDice(list(map(int, input().split()))) == NewDice(list(map(int, input().split()))) else 'No')

```


### 案2: `minimize` 関数を実装する

- `minimize` 関数を定義する
    - 標準入力を整数値の list に変換する
    - サイコロの並べ方の候補を全て提示し、保存する
    - 「最小」の並べ方を示す list を提示する
- 2 つのサイコロの「最小の並べ方」が等しければ同じと考える

```{python}
class Dice():
    def __init__(self, sequence):
        self.sequence = sequence

    def move(self, code):
        return [self.sequence[int(idx)] for idx in str(code)]

    def roll(self, root):
        for d in root:
            if d == 'N': self.sequence = self.move(152304)
            elif d == 'E': self.sequence = self.move(310542)
            elif d == 'S': self.sequence = self.move(402351)
            elif d == 'W': self.sequence = self.move(215043)

def minimize(cin):
    candidates = []
    for ops in ('', 'N', 'W', 'E', 'S', 'NN'):
        dice = Dice(list(map(int, cin.split())))
        dice.roll(ops)
        for _ in range(4):
            dice.roll('NES')
            candidates.append(dice.sequence)
    return min(candidates)

print('Yes' if minimize(input()) == minimize(input()) else 'No')

```

## [ITP1_11_D: DICE IV](https://onlinejudge.u-aizu.ac.jp/courses/lesson/2/ITP1/11/ITP1_11_D)

### 案 1: `NewDice` クラスを利用する

```{python}
class Dice():
    def __init__(self, sequence):
        self.sequence = sequence

    def move(self, code):
        return [self.sequence[int(idx)] for idx in str(code)]

    def roll(self, ops):
        for op in ops:
            if op == 'N': self.sequence = self.move(152304)
            elif op == 'E': self.sequence = self.move(310542)
            elif op == 'S': self.sequence = self.move(402351)
            elif op == 'W': self.sequence = self.move(215043)

class NewDice(Dice):
    def __init__(self, sequence):
        super().__init__(sequence)
        self.candidates = []
        for ops in ('', 'N', 'W', 'E', 'S', 'NN'):
            dice = Dice(self.sequence)
            dice.roll(ops)
            for _ in range(4):
                dice.roll('NES')
                self.candidates.append(dice.sequence)

    def __eq__(self, other):
        return min(self.candidates) == min(other.candidates)

prv = []
for _ in range(int(input())):
    tmp = min(NewDice(list(map(int, input().split()))).candidates)
    if tmp in prv:
        print('No')
        break
    prv.append(tmp)
else:
    print('Yes')

```

### 案 2: `minimize` 関数を利用する

```{python}
class Dice():
    def __init__(self, sequence):
        self.sequence = sequence

    def move(self, code):
        return [self.sequence[int(idx)] for idx in str(code)]

    def roll(self, ops):
        for op in ops:
            if op == 'N': self.sequence = self.move(152304)
            elif op == 'E': self.sequence = self.move(310542)
            elif op == 'S': self.sequence = self.move(402351)
            elif op == 'W': self.sequence = self.move(215043)

def minimize(cin):
    candidates = []
    for ops in ('', 'N', 'W', 'E', 'S', 'NN'):
        dice = Dice(list(map(int, cin.split())))
        dice.roll(ops)
        for _ in range(4):
            dice.roll('NES')
            candidates.append(dice.sequence)
    return min(candidates)

prv = []
for _ in range(int(input())):
    tmp = minimize(input())
    if tmp in prv:
        print('No')
        break
    prv.append(tmp)
else:
    print('Yes')

```

## まとめ

クラスを実装することで、使い回ししやすいコードを記述することができる。
（関数を定義すると記述量は減らしやすいけど、使い回しには不向きかも）