ITP1_11_C サイコロ IIIをC++で解いてみた[AIZU ONLINE JUDGE]

AIZU ONLINE JUDGE

こんにちは! mnbd(@mnbbbbbd)です。

AIZU ONLINE JUDGEの「ITP1_11_C サイコロ III」を解いてみましたので、その回答と解説をご紹介いたします。

プログラミング初心者なので、もっといい回答があるに違いありません。

あくまでも「動作はする」サンプルとしてご覧ください。

問題文

Dice I と同様の方法で、入力された整数から2つのサイコロをつくります。これらが同一のものか判定するプログラムを作成してください。Dice I の方法でサイコロを回転させ、2つのサイコロのそれぞれの6方向から見た整数が全て一致するとき、同一のサイコロとみなします。

Input

1行目に1つ目のサイコロの各面の整数が、ラベルの順番に空白区切りで与えられます。
2行目に2つ目のサイコロの各面の整数が、ラベルの順番に空白区切りで与えられます。

Output

2つのサイコロが同一ならば “Yes” と、異なるならば “No” と1行に出力してください。

Constraints

0≤0≤ 入力されるサイコロの面の整数 ≤100

https://onlinejudge.u-aizu.ac.jp/courses/lesson/2/ITP1/11/ITP1_11_C

サイコロIIIの問題は、サイコロIとサイコロIIに関連していますので、そちらも参考にしてください。

ただし、私の場合は、各問題が連動したソースコードになっておりません。

本来であれば、サイコロIからちゃんとクラスを実装していれば、各問題でのコーディング量を減らせるはずです。

解答

#include <bits/stdc++.h>
using namespace std;

class Dice {
  public:
    Dice(int number[]);
    void print_status();
    int get_status(int number);
    void toss(char direction);
    bool is_same(Dice d);
    bool is_same_dice(Dice d);
    void right_rotation();

  private:
    int dice[6];
};

Dice::Dice(int n[]) {
    for(int i = 0; i < 6; i++) {
        dice[i] = n[i];
    }
}

void Dice::print_status() {
    for(int i = 0; i < 6; i++) {
        cout << dice[i] << " ";
    }
    cout << endl;
}

int Dice::get_status(int number) { return dice[number]; }

void Dice::toss(char direction) {
    int tmp;
    switch(direction) {
    case 'N':
        tmp = dice[0];
        dice[0] = dice[1];
        dice[1] = dice[5];
        dice[5] = dice[4];
        dice[4] = tmp;
        break;
    case 'S':
        tmp = dice[0];
        dice[0] = dice[4];
        dice[4] = dice[5];
        dice[5] = dice[1];
        dice[1] = tmp;
        break;
    case 'E':
        tmp = dice[0];
        dice[0] = dice[3];
        dice[3] = dice[5];
        dice[5] = dice[2];
        dice[2] = tmp;
        break;
    case 'W':
        tmp = dice[0];
        dice[0] = dice[2];
        dice[2] = dice[5];
        dice[5] = dice[3];
        dice[3] = tmp;
        break;
    }
}

bool Dice::is_same(Dice d) {
    for(int i = 0; i < 6; i++) {
        if(dice[i] != d.get_status(i)) {
            return false;
        }
    }
    return true;
}

bool Dice::is_same_dice(Dice d) {
    for(int i = 0; i < 6; i++) {
        if(i < 4) {
            toss('S');
        } else if(i == 4) {
            toss('E');
        } else {
            toss('W');
            toss('W');
        }

        for(int j = 0; j < 4; j++) {
            right_rotation();
            if(is_same(d)) {
                return true;
            }
        }
    }
    return false;
}

void Dice::right_rotation() {
    int tmp = dice[1];
    dice[1] = dice[2];
    dice[2] = dice[4];
    dice[4] = dice[3];
    dice[3] = tmp;
}

int main() {
    int dice_table[2][6];

    for(int i = 0; i < 2; i++) {
        for(int j = 0; j < 6; j++) {
            cin >> dice_table[i][j];
        }
    }

    Dice d1(dice_table[0]), d2(dice_table[1]);

    if(d1.is_same_dice(d2)) {
        cout << "Yes" << endl;
    } else {
        cout << "No" << endl;
    }
    return 0;
}

ハマったポイント

2つのサイコロが同一のものであるかどうかの判定する処理がわかりませんでした。

サイコロの上部を起点としての6面、その各面に対してサイコロの前面を起点として横回転に4面の向きを変えて、6面が同一の値になってるかを判定しています。

感想

サイコロIやIIの全体の各正答率が50%台ですが、サイコロIIIは正答率が30%台と難易度があがってる印象はありました。

また、過去の問題のコードを利用して、プログラム自体が長くなっているため、そこにバグがあるとハマりやすいと思います。

まとめ

AIZU ONLINE JUDGEの「ITP1_11_C サイコロ III」を解いてみましたので、その回答と解説をご紹介いたします。

少しずつですが、プログラミングの勉強をしています。
まだ初心者ですが、よかったらつながっていただけると嬉しいです。
Twitterアカウント(@mnbbbbbd

以上です。
読んでいただきありがとうございました!