Python のサンプル問題が公開されました

かねてより、アナウンスがあった、基本情報技術者試験 午後のプログラミング選択問題で新しく追加される Python について、2019 年 10 月 28 日、IPA よりサンプル問題が発表されました。

プレスリリース

IPA 独立行政法人 情報処理推進機構:情報処理技術者試験センター:
基本情報技術者試験(FE)におけるPythonのサンプル問題の公開について

今回は上記のニュースリリースより、問題文全文をページに起こしました。

Python サンプル問題

error
出典:基本情報技術者試験 Pythonサンプル問題
本記事ではわかりやすいよう、問題文にシンタックスハイライトなどを入れています

問 Python のプログラムに関する次の記述を読んで,設問 1,2 に答えよ。

命令列を解釈実行することによって様々な図形を描くプログラムである。

(1)
描画キャンバスの座標は,x 軸の範囲が -320 ~ 320,y 軸の範囲が -240 ~ 240 である。描画キャンバスの座標系を,図1に示す。描画キャンバス上にはマーカがあり,マーカを移動させることによって描画する。マーカは,現在の位置座標と進行方向の角度を情報としてもつ。マーカの初期状態の位置座標は (0, 0) であり,進行方向は x 軸の正方向である。



図 1 描画キャンバスの座標系

(2)
命令列は,命令を “;” で区切った文字列である。命令は,1 文字の命令コードと数値パラメタの対で構成される。命令には,マーカに対して移動を指示する命令,マーカに対して回転を指示する命令,及び命令列中のある範囲の繰返しを指示する命令がある。繰り返す範囲を,繰返し区間という。命令は,命令列の先頭から順に実行する。命令とその説明を,表 1 に示す
図 命令コードと数値パラメタの説明
命令コード 数値パラメタ 説明
F 長さ マーカを現在の進行方向に数値パラメタで指定した長さだけ進め、移動元から移動先までの線分を描く。
T 角度 マーカの進行方向を、数値パラメータが正の場合は反時計回りに、負の場合は時計回りに、数値パラメタの角度(度数法)だけ回転する。
R 繰返し回数 繰返し区間の開始を示す。この命令と対になる命令コード E との間を、命令コード R の数値パラメタの回数だけ繰り返す。
E 0 繰返し区間の終了を示す。数値パラメタは、常に 0 である。
(3)
命令列 R3; R4; F100; T90; E0; F100; E0(以下,命令列 α という)の繰返し区間を,図 2 に示す。マーカが初期状態にあるときに,命令列 α を実行した場合の描画結果を,図 3 に示す。なお,図3中の描画キャンバスの枠,目盛りとその値,① ,② 及び矢印は,説明のために加えたものである。



図 2 命令列 α の繰返し区間



図 3 命令列 α を実行した場合の描画結果

設問 1

次の記述中の       に入れる正しい答えを,解答群の中から選べ。ここで,a1 と a2 に入れる答えは,a に関する解答群の中から組合せとして正しいものを選ぶものとする。

(1)
命令列 α の実行が終了した時点でのマーカの位置は,図 3 中の   a1   が指す位置にあり,進行方向は   a2   である。
(2)
マーカが初期状態にあるときに,図 4 に示す 1 辺の長さが 100 の正五角形を描くことができる命令列は,   b   である。ここで,図 4 中の描画キャンバスの枠,目盛りとその値は,説明のために加えたものである。

a に関する解答群

a1 a2
x 軸の正方向
y 軸の正方向
x 軸の正方向
y 軸の正方向

b に関する解答群

ア R5; F100; T-108; E0  
イ R5; F100; T-75; E0
ウ R5; F100; T-72; E0  
エ R5; F100; T-60; E0
オ R5; F100; T60; E0  
カ R5; F100; T72; E0
キ R5; F100; T75; E0  
ク R5; F100; T108; E0

 

〔プログラムの説明〕

(1)
関数 parse は,引数として与えられた命令列を,タプルを要素とするリストに変換する。ここで,命令列は,少なくとも一つの命令をもち,誤りはないものとする。1 タプルは,1 命令に相当し,命令コード及び数値パラメタから構成される。関数 parse が定義された状態での,対話モードによる実行例を,実行結果 1 に示す。

実行結果 1

>>> parse('R4;F100;T90;E0')
[('R', 4), ('F', 100), ('T', 90), ('E', 0)]
(2)
クラス Marker は,マーカの現在の位置座標を属性 x, y に,進行方向を x 軸正方向から反時計回りに測った角度で属性 angle に保持する。オブジェクトの生成時に,描画キャンバスの表示範囲を設定し,属性 x, y を 0, 0 に,属性 angle を 0 に設定する。クラス Marker に,マーカの操作をする次のメソッドを定義する。
forward( val )
マーカの位置座標を,現在の進行方向に val で指定された長さだけ進め,線分を描く。
引数: val 長さ
turn( val )
マーカの進行方向を,反時計回りに val で指定された角度だけ回転させる。
引数: val 度数法で表した角度
(3)
関数 draw は,引数として与えられた命令列の各命令を解釈実行し,描画結果を表示する。ここで,命令列は,少なくとも一つの命令をもち,誤りはないものとする。関数 draw の概要を,次に示す。
  1. 命令列を,関数 parse を利用してタプルを要素とするリストに変換する。
  2. マーカの操作は,クラス Marker を利用する。
  3. 繰返し区間の入れ子を扱うために,スタックを用いる。
  4. スタックはリストで表現され,各要素は繰返しの開始位置 opno と残り回数 rest をもつ辞書である。
  5. プログラムの位置 β にある print 関数を使って,スタックの状態変化を出力する。

2 重の繰返し区間をもつ命令列について,関数 draw が定義された状態での,対話モードによる実行例を,実行結果 2 に示す。

実行結果 2

>>> draw('R2;R3;E0;E0') 
[] 
[{'opno': 0, 'rest': 2}] 
[{'opno': 0, 'rest': 2}, {'opno': 1, 'rest': 3}] 
[{'opno': 0, 'rest': 2}, {'opno': 1, 'rest': 2}] 
[{'opno': 0, 'rest': 2}, {'opno': 1, 'rest': 1}] 
[{'opno': 0, 'rest': 2}] 
[{'opno': 0, 'rest': 1}] 
[{'opno': 0, 'rest': 1}, {'opno': 1, 'rest': 3}] 
[{'opno': 0, 'rest': 1}, {'opno': 1, 'rest': 2}] 
[{'opno': 0, 'rest': 1}, {'opno': 1, 'rest': 1}] 
[{'opno': 0, 'rest': 1}]

〔プログラム〕

import math  # 数学関数の標準ライブラリ 
import matplotlib.pyplot as plt  # グラフ描画の外部ライブラリ 

def parse(s): 
    return [(x[0], "[  c  ]") for x in s.split(';')] 

class Marker: 
    def __init__(self): 
        self.x, self.y, self.angle = 0, 0, 0 
        plt.xlim(-320, 320)  # x軸の表示範囲を設定 
        plt.ylim(-240, 240)  # y軸の表示範囲を設定 

    def forward(self, val): 
        # 度数法で表した角度を,ラジアンで表した角度に変換 
        rad = math.radians(self.angle) 
        dx = val * "[  d1  ]"
        dx = val * "[  d2  ]"
        x1, y1, x2, y2 = "[  e  ]", self.x + dx, self.y + dy
        # (x1,y1)と(x2,y2)を結ぶ線分を描画
        plt.plot([x1, x2], [y1, y2], color='black', linewidth=2)  
        self.x, self.y = x2, y2

    def turn(self, val): 
        self.angle = (self.angle + val) % 360     def show(self): 
        plt.show()  # 描画結果を表示 

def draw(s): 
    insts = parse(s) 
    marker = Marker() 
    stack = [] 
    opno = 0
    while opno < len(insts): 
        print(stack)  # <----- β
        code, val = insts[opno] 
        if code == 'F': 
            marker.forward("[  f  ]") 
        elif code == 'T': 
            marker.turn("[  f  ]")
        elif code == 'R': 
            stack.append({'opno': opno, 'rest':"[  f  ]"}) 
        elif code == 'E': 
            if stack[-1]['rest']"[  g  ]": 
                "[  h  ]"
                stack[-1]['rest'] -= 1
            else: 
                "[  i  ]"
        opno += 1 
    marker.show()

設問 2

プログラム中の      に入れる正しい答えを,解答群の中から選べ。ここで,d1 と d2 に入れる答えは,d に関する解答群の中から組合せとして正しいものを選ぶものとする。d に関する解答群の中で使用される標準ライブラリの仕様は,次のとおりである。

math.sin( x )
指定された角度の正弦( sin )を返す。
引数: x ラジアンで表した角度
戻り値:引数の正弦( sin )
math.cos( x )
指定された角度の余弦( cos )を返す。
引数: x ラジアンで表した角度
戻り値:引数の余弦( cos )

c に関する解答群

int(x[1])  イ int(x[1:])int(x[:1])  エ int(x[2])int(x[2:])  カ int(x[:2])

d に関する解答群

d1 d2
math.cos(rad) -math.sin(rad)
math.cos(rad) math.sin(rad)
math.sin(rad) -math.cos(rad)
math.sin(rad) math.cos(rad)

e に関する解答群

0, 0  イ dx, dyselg.x, self.y  エ self.x - dx, self.y - dy

f に関する解答群

0  イ codelen(insts)  エ val

g に関する解答群

< 0  イ < 1  ウ == 0> 0  オ > 1

h,i に関する解答群

opno = stack[-1]['opno'] stack.clear()  # stackをクリアstack.pop()  # stackの末尾の要素を削除stack.pop(0)  # stackの先頭の要素を削除stack[-1]['opno'] = opno

解答と出題趣旨

解答
設問番号 正解
設問1 a
b
設問2 c
d
e
f
g
h
i
出題趣旨

命令列の解釈実行を行うインタプリタを作成することは,プログラミング技法の習得の点でも,プログラムの動作原理を理解する点でも,意義深い取組である。
 
 本問は,簡易な描画処理の命令列を解釈実行することを主題としている。
 
 本問では,繰返しの入れ子構造をもつ命令列の解釈実行について問うことによって,スタックを用いて実装する能力を評価する。また,マーカの移動及び回転を指示する命令の実行について問うことによって,プログラム言語 Python の外部ライブラリや,三角関数などの数値計算を行う標準ライブラリを活用する能力を評価する。

Python に関する記事と連載、追加中!!

基本情報技術者試験 受験ナビでは、おなじみの 矢沢 久雄 さんにサンプル問題の解説いただいたほか、午後問題の歩き方 にて Python の連載が始まりました!

label 関連タグ
実は、午前試験を『免除』できます 独習ゼミで午前免除試験を受けた 85% の方が、
午前分野を免除しています。
2020年 6月 12日 12時
締め切り間近!!
alarm2020年 6月 12日 12時締切!

詳しく見てみるplay_circle_filled
label これまでの『資格ガイド』の連載一覧 label 著者
  • 基本情報技術者試験 の受験勉強をレポート頂ける方を募集中です!
  • ツイッター で過去問を配信しています

姉妹サイト 「IT資格の歩き方」 では応用情報技術者以上の情報処理技術者試験の対策記事があります!

基本情報技術者試験を合格されたら、「IT資格の歩き方」で末永く、スキルアップにお役立てください!