難しくはないがレベルが高い 基本情報 Python のサンプル問題を解説


2022-11-28 更新

error

この記事は基本情報技術者試験の旧制度( 2022 年以前)の記事です。
この記事の題材となっている「 Python 」は現在の試験制度では出題されません。 ご注意くださいませ。

2019 年 10 月 28 日に、IPA から Python のサンプル問題が公開されました。

問題の全文は、別の記事で紹介 していますので、ここでは、問題のテーマと、問題を解くのに必要な知識を説明しましょう。

info_outline問題の全文に関する記事

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

さすが最近人気の Python だけあって、それほど難しくはないのですが、なかなかレベルの高い問題となっています。

また、 Python そのものを学んでいる方は、この問題で言語構文が理解できているか、チェックしてみるとよいでしょう。

問題のテーマは、描画処理のインタプリタの作成

実務の現場における Python の主な用途といえば、データ解析や機械学習でしょう。

「はたして、試験でもデータ解析や機械学習をテーマとした問題が出るのだろうか? もしもそうなら、他のプログラミング言語とレベルの差が大き過ぎてしまうので、選択者がほとんどいないだろう!」と危惧していたのですが、そうではなかったのでホッとしました。

サンプル問題のテーマは、「描画処理の命令列を解釈実行するインタプリタの作成」です。

 

ただし、データ解析や機械学習ではないとはいえ、インタプリタの作成ですから、なかなかレベルの高いテーマです。

Python には、様々な標準ライブラリがあり、ソートやサーチなどのアルゴリズムや、スタックやキューなどのデータ構造を手作りする必要がないので、それらを応用するレベルのテーマになったのでしょう。

さらに、外部ライブラリを使えば、短いコードでグラフの描画が行えるので、実際に描画を行うプログラムになっています。

実際の試験でも「ライブラリを活用してグラフを描画する問題」がよく出るのではないかと予想されます。このサンプル問題は、しっかり練習しておくべきです。

 

それでは、問題を見てみましょう。

レベルは高くても、内容は難しくないので、どうぞご安心ください。

x – y 平面の描画キャンパスがあり、そこにマーカで描画を行います。プログラムに与えられる描画処理の命令列は、

R3; R4; F100; T90; E0; F100; E0

という形式になっています。

セミコロン( ; )が命令の区切りを示し、個々の命令は 1 文字の英字で示された「命令コード」と数値で示された「数値パラメタ」から構成されています。

たとえば、「 R3 」は、「 R 」が命令コードで、「 3 」が数値パラメタです。

以下は、試験問題に示された命令とその説明です。

表 1 命令とその説明
命令コード 数値パラメタ 説明
F 長さ マーカを現在の進行方向に数値パラメタで指定した長さだけ進め,移動元から移動先までの線分を描く。数値パラメタは,1 以上の整数値である。
T 角度 マーカの進行方向を,現在の進行方向から数値パラメタが正の場合は反時計回りに,負の場合は時計回りに,数値パラメタの絶対値の角度だけ回転する。
数値パラメタが 0 の場合は回転しない。数値パラメタは,単位を度数法とする任意の整数値である。
R 繰返し回数 繰返し区間の開始を示す。この命令と対となる命令コードEの命令との間を,数値パラメタで指定した回数だけ繰り返す。
繰返し区間は,入れ子にすることができる。数値パラメタは 1 以上の整数値である。
E 0 繰返し区間の終了を示す。数値パラメタは,参照しない。

命令列のポイントは、繰返しがあることです。

R3; R4; F100; T90; E0; F100; E0 という命令は、以下の区間が繰り返されます。この図も、問題に示されています。

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

図を見ながら、命令列を解釈してみましょう。

  1. 命令 0 と命令 6 に囲まれた範囲が 3 回繰り返され、命令 1 と命令 4 で囲まれた範囲が 4 回繰り返されます。
  2. 命令 2 で進行方向に 100 だけ進み、移動元から移動先までの線分を描きます。
  3. 命令 3 でマーカの進行方向が反時計回りに 90 度だけ回転します。

つまり、「マーカを 100 だけ進めて線分を描き、反時計回りに 90 度だけ回転する」を 4 回繰り返すのです。

これによって、1 辺が 100 の正方形が描かれます。

 

次に命令 5 でマーカが 100 だけ進んで線分が描かれ、「マーカを 100 だけ進めて線分を描く」が行われます。これが 3 回繰り返されるのですから、1 辺が 100 の正方形が 3 つ描かれます。

 

マーカは、初期状態で( 0, 0 )の位置にあり、進行方向は x 軸の正方向になっています。

したがって、 R3; R4; F100; T90; E0; F100; E0 を解釈実行すると、以下の図形が描画されます。

この図も、問題に示されています。この形式の命令列の解釈実行を行うプログラムを作成するのが、サンプル問題のテーマです。

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

プログラムと実行結果の例

それでは、プログラムを見てみましょう。ここでは、記事として気軽に読めるように、空欄の穴埋めに正解を記入したプログラムを示します。

穴埋めとなっていた部分は、コメント # ここが穴埋め問題 で示しておきます。

これらの穴埋めは、プログラムの説明が理解できて、Python の基本構文がしっかりわかっていれば、決して難しくありません。

 

プログラムは、parse 関数、Marker クラス、draw 関数から構成されています。

parse(s) 関数
引数として与えられた命令列 s を、タプルを要素とするリストに変換します
Markerクラス
マーカを val だけ進めて描画を行うメソッド

forward( self, val )
マーカの方向を反時計回りに val だけ回転させるメソッド

turn( self, val )
初期化を行うメソッド

__init(self)__
draw(s) 関数
引数で与えられた命令列 s を parse 関数で変換し(これが解釈)、その内容を Marker クラスのメソッドを使って描画(これが実行)

 

codeリスト プログラム(出典: 基本情報技術者試験 Python サンプル問題)

スマートフォンでは、ソースコードや実行結果は右スクロールするとご覧になれます

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

def parse(s):
    return [(x[0], int(x[1:])) for x in s.split(';')]  # int(x[1:]) が穴埋め問題

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 * math.cos(rad)  # math.cos(rad) が穴埋め問題
        dy = val * math.sin(rad)  # math.sin(rad) が穴埋め問題
        x1, y1, x2, y2 = self.x, self.y, self.x + dx, self.y + dy  # self.x, self.y, が穴埋め問題
        # (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(val)  # val が穴埋め問題
        elif code == 'T':
            marker.turn(val)  # val が穴埋め問題
        elif code == 'R':
            stack.append({'opno': opno, 'rest': val})  # val が穴埋め問題
        elif code == 'E':
            if stack[-1]['rest'] > 1:
               opno = stack[-1]['opno']  # この行が穴埋め問題
               stack[-1]['rest'] -= 1
            else:
               stack.pop()  # stackの末尾の要素を削除 (この行が穴埋め問題)
        opno += 1
    marker.show()

以下は、プログラムの実行結果の例です。

ここでは、プログラムを fesample.py というファイル名で作成し、Python の対話モードで、

>>> from fesample import draw 

を実行して draw 関数をインポートし、

>>> draw('R3;R4;F100;T90;E0;F100;E0') 

を実行して描画を行っています。

1 辺が 100 の正方形が 3 つ描かれました。サンプル問題でも、Python の対話モードでプログラムの実行を行っています。

図 プログラムの実行の例

info Python をブラウザからオンラインで実行できる「 JupyterLab 」で試すにはプログラム末尾に、

plt.show(draw('R3;R4;F100;T90;E0;F100;E0'))

を加えると実行できます

問題を解くのに必要な知識

「ライブラリの知識」
「言語構文の知識」
「プログラミング技法の知識」

に分けて、サンプル問題を解くのに必要な知識を説明しましょう。

ライブラリの知識

サンプル問題では、プログラムの中で使用されている様々な関数やオブジェクトの機能が、

plt.show() # 描画結果を表示
stack.pop() # stackの末尾の要素を削除のように、

コメントで説明されています。

したがって、標準ライブラリや外部ライブラリの機能を事前に覚えておく必要はないでしょう。

実際の試験でも、ライブラリの関数やメソッドの機能がコメントに示されるはずだからです。

ただし、print 、input 、len 、range 、int 、float 、str、list など、よく使われる標準関数の機能は、事前に覚えておくべきです。これらにコメントは示されないと思われるからです。

言語構文の知識

サンプル問題で使用されている言語構文は、2019 年 7 月 1 日に公開されたシラバス Ver.7.0 の「 Python の知識と技術」に示されたものです。

info_outline関連記事

Python の出題範囲 (シラバス) が発表されました

シラバスに沿って問題が作られるのですから、これは当然のことです。

以下は、プログラムに 「# 構文: 」 という形式のコメントを青色で追加して、どの部分で、どのような言語構文の知識が必要なのかを示したものです。

どれも、 Python の入門書で説明されている基本的なものなので、わからない言語構文があれば意味を調べておきましょう。

「変数への代入」
「関数の呼び出し」
「メソッドの呼び出し」

など、多用されている構文は、最初の 1 回だけコメントを入れてあります。

 

codeリスト プログラムを読むのに必要とされる言語構文の知識(出典: 基本情報技術者試験 Python サンプル問題)

# 構文: モジュールのインポート
import math  # 数学関数の標準ライブラリ
# 構文: モジュールをインポートし別名を付ける
import matplotlib.pyplot as plt  # グラフ描画の外部ライブラリ

# 構文: 関数の定義
def parse(s):
    # 構文: リスト内包表記
    # 構文: スライス
    # 構文: メソッドの呼び出し
    return [(x[0], int(x[1:])) for x in s.split(';')]

# 構文: クラスの定義
class Marker:
    # 構文: 初期化メソッドの定義
    # 構文: selfの意味
    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 * math.cos(rad)
        dy = val * math.sin(rad)
        # 構文: タプルのアンパック(展開)
        # 構文: インスタンス変数の値を読み出す
        x1, y1, x2, y2 = self.x, self.y, 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文による繰り返し
    while opno < len(insts):
        print(stack)
        # 構文: リストのアンパック(展開)
        code, val = insts[opno]
        # 構文: if文による分岐
        # 構文: 比較演算子
        if code == 'F':
            marker.forward(val)
        elif code == 'T':
            marker.turn(val)
        elif code == 'R':
            # 構文: 辞書の要素の設定
            stack.append({'opno': opno, 'rest': val})
        elif code == 'E':
            if stack[-1]['rest'] > 1:
                # 構文: リストの添字
                opno = stack[-1]['opno']
                # 構文: 複合代入演算子
                stack[-1]['rest'] -= 1
            else:
                stack.pop()  # stackの末尾の要素を削除
        # 構文: 複合代入演算子
        opno += 1
    marker.show()

プログラミング技法の知識

サンプルプログラムの処理内容を理解するには、

  • リスト、タプル、辞書を使い分ける知識
  • リストをスタックとして使う知識

が必要です。

「リスト」「タプル」「辞書」およびサンプル問題では取り上げられていない「集合」は、Python ならではの便利な機能ですので、しっかり学習しておきましょう。

実際の試験問題でも、これらが多用されると予想されるからです。

info_outline関連記事

「基本情報 の Python ってどんな感じ?」こんな感じです!|午後問題の歩き方

令和 2 年度の春期試験で Python を選択する受験者へのアドバイス

過去の試験では、新たなプログラミング言語が採用されたときの最初の問題は、ボリュームが少なく、とてもやさしい内容になっていました。

たとえば、新たに表計算が採用されたときの最初の問題(平成 21 年度 春期 午後問 13 )は、わずか 4 ページであり、使われている関数は、切り上げ、IF 、照合、合計の 3 つだけでした。

これは、試験の運営側に、多くの選択者を得たいという思いと、選択者の多くに合格点を取ってほしいという思いがあってのことでしょう。

おそらく Python も同様のはずです。最初の Python の問題は、ねらい目です。

 

ただし、Python は、言語構文を覚えるのに時間がかかる言語です。

4 月の本試験まで約 5 か月ありますが、これから Python の学習を始めるという受験者は、今回発表されたサンプル問題で使われている言語構文を隅々まで理解できるようになるまで、気合を入れて丁寧な学習をしてください。

もしも、Python の言語構文の教材をお持ちなら、最初から丁寧に復習してください。何度も繰り返して復習してください。

そして、自信を持って試験に臨んでください。

令和2年度の春期試験で Python を選択する受験者は、どれくらいいるのでしょう。講師をしている筆者は、大いに興味があります。

なぜなら、基本情報技術者試験で Python の選択者が多くいるなら、それはプログラミング自体を学習する言語として Python が普及している証であり、今後 Python を学ぶ研修が多くなるからです。

はたして、どうなるでしょう。ワクワクします。

それでは、またお会いしましょう!

label 関連タグ
科目A試験は、
免除できます。
独習ゼミで科目A試験を1年間免除して、科目B試験だけに集中しましょう。
免除試験を受けた 74.9% の方が、
科目A免除資格を得ています。
科目A免除試験 最大 2 回の
受験チャンス !
info_outline
科目A免除試験 最大 2 回の
受験チャンス !
詳しく見てみるplay_circle_filled
label これまでの『資格ガイド』の連載一覧 label 著者