Aizu Online Judge(AOJ)が提供している「プログラミング入門」(ITP1)の11_B問題をC++とPython で解いてみました。
ITP1 のトピック11では、構造体とクラスについて学びます。「構造体やクラスによって独自の型を定義し、プログラムで利用します。」とあります。この学習コースを通じて、Python に慣れていきたいと考えています。
問題(11_B:Dice II)
問題はリンク先をご覧ください。
前回(11-A)に作成した Dice クラスを再利用して、問題を解きます。
考察
Dice クラスを変更せずにそのまま再利用します。クラスの仕様は、前回の記事を参照してください。
今回、問題として問われている右の面を返す関数 get_right は、クラスメソッドではなく、クラスの外の関数として実装することにしました。この関数が提供する機能は、クラスにこれから必要ではなく、この問題に特化した機能だと判断したためです。
解答案
C++ プログラム例(ITP1 11_B)
今回、新設する関数 get_right は、3個の引数を持ちます。
- Dice クラスのインスタンス d(対象となるサイコロ)
- 上の面に位置させたい数 top
- 前の面に位置させたい数 front
最初に top で指定された数を上の面(number[0])に移動させます。
次に front で指定された数を前の面(number[1])に roll を使って移動させます。roll を使うのは、上の面を変えないためです。最後に右の面(number[2])を返します。
もし、上の面を移動した後、下の面(number[5])に front があれば、-1 を返します。この場合は、上の面を top に、前の面を front とすることができません。
以下は、関数 get_right のプログラムです。
int get_right(Dice d, int top, int front)
{
vector<int> number;
number = d.get_number();
if (top == number[1]) {
d.N();
} else if (top == number[2]) {
d.W();
} else if (top == number[3]) {
d.E();
} else if (top == number[4]) {
d.S();
} else if (top == number[5]) {
d.N();
d.N();
}
number = d.get_number();
if (front == number[1]) {
// do nothing
} else if (front == number[2]) {
d.roll();
} else if (front == number[3]) {
d.roll();
d.roll();
d.roll();
} else if (front == number[4]) {
d.roll();
d.roll();
} else {
return -1;
}
number = d.get_number();
return number[2];
}
サイコロの処理を Dice クラスおよび get_right 関数で処理しているため、main 自体は、以下のようにすっきりと書けています。
int main()
{
vector<int> number(6);
for (int i = 0; i < 6; ++i) {
cin >> number[i];
}
Dice d(number);
int q;
cin >> q;
for (int i = 0; i < q; ++i) {
int top, front;
cin >> top >> front;
cout << get_right(d, top, front) << endl;
}
return 0;
}
長くなったためプログラム全体は、このブログ記事の最後に掲載しました。
Python プログラム例(ITP1 11_B)
Python 版の Dice クラスも、11_A 版とまったく同一です。C++ と同じ仕様で get_right 関数を追加で実装しました。
全体の Python プログラムは、以下となります。
class Dice:
def __init__(self, number):
self.n = number.copy()
def E(self):
self.n[2], self.n[5], self.n[0], self.n[3] = \
self.n[0], self.n[2], self.n[3], self.n[5]
def N(self):
self.n[4], self.n[0], self.n[5], self.n[1] = \
self.n[0], self.n[1], self.n[4], self.n[5]
def S(self):
self.n[1], self.n[5], self.n[0], self.n[4] = \
self.n[0], self.n[1], self.n[4], self.n[5]
def W(self):
self.n[3], self.n[0], self.n[5], self.n[2] = \
self.n[0], self.n[2], self.n[3], self.n[5]
def roll(self):
self.n[3], self.n[1], self.n[4], self.n[2] = \
self.n[1], self.n[2], self.n[3], self.n[4]
def move(self, ch):
if ch == 'E':
self.E()
elif ch == 'N':
self.N()
elif ch == 'S':
self.S()
elif ch == 'W':
self.W()
def get_number(self):
return self.n
def get_right(d, top, front):
number = d.get_number()
if top == number[1]:
d.N()
elif top == number[2]:
d.W()
elif top == number[3]:
d.E()
elif top == number[4]:
d.S()
elif top == number[5]:
d.N()
d.N()
number = d.get_number()
if front == number[1]:
pass
elif front == number[2]:
d.roll()
elif front == number[3]:
d.roll()
d.roll()
d.roll()
elif front == number[4]:
d.roll()
d.roll()
else:
return -1
number = d.get_number()
return number[2]
number = list(map(int, input().split()))
d = Dice(number)
q = int(input())
for i in range(q):
top, front = map(int, input().split())
print(get_right(d, top, front))
この Python プログラムは、AOJ で「AC(Accepted=正解)」と判定されます。
最後に
C++ 版の Dice クラスは、94行です。そのプログラムを、1行も変更しないで再利用することができました。また、本来クラスは別ファイルで管理しますが、採点をするために1ファイルにしています。
また、追加する機能をクラスメソッドとして実装するのか、クラスの外の関数として実装するのか判断しました。これは、人によって判断が異なるかもしれません。
引き続き、ITP1 の問題を紹介していきます。
C++ 全体ソース(ITP1 11_B)
以下が、C++ 版の全体ソースコードとなります。
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Dice {
vector<int> number;
public:
Dice(vector<int> num)
{
number = num;
}
void E(void)
{
vector<int> temp(6);
temp[2] = number[0];
temp[1] = number[1];
temp[5] = number[2];
temp[0] = number[3];
temp[4] = number[4];
temp[3] = number[5];
number = temp;
}
void N(void)
{
vector<int> temp(6);
temp[4] = number[0];
temp[0] = number[1];
temp[2] = number[2];
temp[3] = number[3];
temp[5] = number[4];
temp[1] = number[5];
number = temp;
}
void S(void)
{
vector<int> temp(6);
temp[1] = number[0];
temp[5] = number[1];
temp[2] = number[2];
temp[3] = number[3];
temp[0] = number[4];
temp[4] = number[5];
number = temp;
}
void W(void)
{
vector<int> temp(6);
temp[3] = number[0];
temp[1] = number[1];
temp[0] = number[2];
temp[5] = number[3];
temp[4] = number[4];
temp[2] = number[5];
number = temp;
}
void roll(void)
{
vector<int> temp(6);
temp[0] = number[0];
temp[3] = number[1];
temp[1] = number[2];
temp[4] = number[3];
temp[2] = number[4];
temp[5] = number[5];
number = temp;
}
void move(char ch)
{
switch (ch) {
case 'E':
this->E();
break;
case 'N':
this->N();
break;
case 'S':
this->S();
break;
case 'W':
this->W();
break;
default:
break;
}
}
vector<int> get_number(void)
{
return number;
}
};
int get_right(Dice d, int top, int front)
{
vector<int> number;
number = d.get_number();
if (top == number[1]) {
d.N();
} else if (top == number[2]) {
d.W();
} else if (top == number[3]) {
d.E();
} else if (top == number[4]) {
d.S();
} else if (top == number[5]) {
d.N();
d.N();
}
number = d.get_number();
if (front == number[1]) {
// do nothing
} else if (front == number[2]) {
d.roll();
} else if (front == number[3]) {
d.roll();
d.roll();
d.roll();
} else if (front == number[4]) {
d.roll();
d.roll();
} else {
return -1;
}
number = d.get_number();
return number[2];
}
int main()
{
vector<int> number(6);
for (int i = 0; i < 6; ++i) {
cin >> number[i];
}
Dice d(number);
int q;
cin >> q;
for (int i = 0; i < q; ++i) {
int top, front;
cin >> top >> front;
cout << get_right(d, top, front) << endl;
}
return 0;
}
この C++ プログラムは、AOJ で「AC(Accepted=正解)」と判定されます。