Cpp to Python

この章ではPythonで書かれた2種類のプログラムを用いて、実際にrehearsalの使い方を解説します。

Getting Startedでは、C++とPythonの四則演算について考えることにします。 Pythonが

<整数> <演算子> <整数>

と出力するので、その結果をC++のプログラムに

<計算結果>

という形で答えてもらいます。 このソースコードはgithub.com/rehearsal-open/template-sample/getting-startedに公開しています。

コーディング

それでは、実際にコードを書いていきましょう。下図のようなファイル構成です。

1
2
3
 ┣ answer.cpp
 ┣ quiz.py
 ┗ rehearsal.yml

ひとつずつファイル構成を見てみましょう

./answer.cpp

C++側のコードです。単純に入力を受け取り、計算結果を出力しています。わざと間違えるようにint型でのみ計算を行います。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// ./answer.cpp

#include <iostream>
#include <string>
using namespace std;

int main() {

    for (auto i = 0; i < 1000; i++) {
        int a, b;
        string ope;

        // input line to get question
        cin >> a >> ope >> b;

        // output answer
        switch (ope[0]) {
        case '+': cout << a + b << flush << endl; break;
        case '-': cout << a - b << flush << endl; break;
        case '*': cout << a * b << flush << endl; break;
        case '/': cout << a / b << flush << endl; break;
        case '%': cout << a % b << flush << endl; break;
        }
    }
}

このコードを実行した場合、1000問出題する必要があるため、とても手動では行うことができません。

./quiz.py

Python側のコードです。問題を作成し、出力、Pythonとしての答えを計算してからC++の回答を取得し、それらを最後に一覧として表示します。確認のためにPythonのファイル出力でも最後の一覧を出力しておきます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

# ./quiz.py

import random

nQuiz = 1000
data = []

f = open(file="out.txt", mode='w')

for i in range(nQuiz):
    
    # make quiz
    first = random.choice(range(1, 100000))
    second = random.choice(range(1, 100000))
    operator = random.choice(["+", "-", "*", "/", "%"])

    # please flush property true
    print(first, operator, second, sep=" ", flush=True)

    # get python's answer
    pyAns = 0
    if operator == "+":
        pyAns = first + second
    if operator == "-":
        pyAns = first - second
    if operator == "*":
        pyAns = first * second
    if operator == "/":
        pyAns = first / second
    if operator == "%":
        pyAns = first % second

    # get c++'s answer
    cppAns = input()

    # compare with table
    data.append([first, operator, second, pyAns, cppAns])

for i in range(nQuiz):
    first, operator, second, pyAns, cppAns = data[i][0], data[i][1], data[i][2], data[i][3], data[i][4]
    # please flush property true
    print(str(first)+" "+operator+" "+str(second)+" = (python: "+str(pyAns)+", cpp: "+cppAns+")", flush=True)
    print(str(first)+" "+operator+" "+str(second)+" = (python: "+str(pyAns)+", cpp: "+cppAns+")", file=f)

./rehearsal.yml

最後にrehearsal.ymlです。それぞれのタスクのリレーションを組みます。buildフェイズでC++のビルドを行ってから実行を行います。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# ./rehearsal.yml, uses version 1.202109

version: 1.202109
phase:
- name: build # build and set environments
  task:
  - name: gcc_build
    kind: cui
    cmd: g++
    args: [answer.cpp, -o, answer]
    stdout:
      write-log: true
    stderr:
      write-log: true
- name: run_task  # cpp executable file
  task:
  - name: cpp
    kind: cui
    cmd: ./answer.exe
    stdout:
      write-log: true
      sendto:
        - python
  - name: python # run python script
    kind: cui
    cmd: python
    args: [quiz.py]
    stdout:
      write-log: true
      sendto:
        - cpp

実行

善は急げです。すべて書き終えたらさっそく実行してみましょう。シェルを開いてrehearsal-cli run -p ./rehearsal.ymlを実行します。問題生成はランダムであるため問題の内容はおそらく異なります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$ rehearsal-cli run -p ./rehearsal.yml

[INFO]:  start phase (1 / 5)
[INFO]:  __init::__frontend_logger was started.
[INFO]:  start phase (2 / 5)
[INFO]:  build::gcc_build was started.
[INFO]:  build::gcc_build has been already stopped.
[INFO]:  start phase (3 / 5)
[INFO]:  run_task::cpp was started.
[INFO]:  run_task::python was started.
run_task::python(standard output)       : 71191 * 98267
run_task::cpp(standard output)          : -1594208595
run_task::python(standard output)       : 97901 - 46723
run_task::cpp(standard output)          : 51178
...
<中略>
...
run_task::python(standard output)       : 50414 / 28825 = (python: 1.7489679098005204, cpp: 1)
run_task::python(standard output)       : 78334 * 78476 = (python: 6147338984, cpp: 1852371688)
run_task::python(standard output)       : 99560 - 33870 = (python: 65690, cpp: 65690)
run_task::python(standard output)       : 82352 / 43550 = (python: 1.89097588978186, cpp: 1)
run_task::python(standard output)       : 38297 % 12706 = (python: 179, cpp: 179)
run_task::python(standard output)       : 35321 - 34331 = (python: 990, cpp: 990)
run_task::python(standard output)       : 62255 % 37346 = (python: 24909, cpp: 24909)
run_task::python(standard output)       : 56890 / 71068 = (python: 0.8005009286880171, cpp: 0)
[INFO]:  run_task::cpp has been already stopped.
[INFO]:  run_task::python has been already stopped.
[INFO]:  start phase (4 / 5)
[INFO]:  start phase (5 / 5)
[INFO]:  __init::__frontend_logger was stopped.

このように表示されたら完了です。

これが終わったら?

ドキュメントであなたがしたいことを見つけましょう。rehearsalはあなたがやりたいこと、確かめたいことを必ずや実現してくれるはずです。