センター試験「情報関係基礎」2020年の問3 宝探しをプログラミングする
昨年末から,センター試験「情報関係基礎」の過去問をプログラミングする話を書いてきた。実際に授業でやっているものだ。
授業ではCindyscriptを用いているが,Pythonだとどうなるか。JavaScriptだとどうなるか。
最初は2009年の問題だった。Pythonで過去問に取り組み始めたころで,ほんとに初心者。この時点で,
(1) リスト処理
(2) 変数の型と割り算の演算子 // の問題
(3) print() の仕様
などの問題が生じていた。今となればなんでもないこと(慣れた)だが,初めは迷った。
このとき,2020年の宝探しの話も書いているが,Pythonでできる見通しはまったく立っていなかった。
2007年のブロック落としは3通りでやった。
センター試験「情報関係基礎」2007年のブロック落としをCindyScriptで書く
センター試験「情報関係基礎」2007年のブロック落としをPythonで書く
センター試験「情報関係基礎」2007年のブロック落としをJavaScriptで書く
このときの問題は,図をどうするかだったが,Pythonでは はじめて matplotlib を使った。このときは,変数のスコープの問題に直面した。
JavaScript では,結局まともな図が描けなかった。Webで探して真似して作ったが,真似しただけで,わかっているわけではない。開発環境にも苦労した。簡単なエラーなのに,気がつきにくい。
次は2017年の三角形の個数の問題。
「情報関係基礎」2017年の三角形の個数の問題をPythonで書く
「情報関係基礎」2017年の三角形の個数の問題をJavaScriptで書く
ここで,「以上,教員側には生徒の何倍もの知識が必要ということだ」と書いている。図形の表示はないが,教材を準備するために,多くの知識が必要,という話。
しかし,図がないだけ,移植は楽だった。
続いて2018年迷路。
センター試験「情報関係基礎」2018年の迷路をCindyScriptで書く
センター試験「情報関係基礎」2018年の迷路をPythonで書く
再び,図をどう描くかが問題になった。迷路の状態は2次元のリストで表しており,これを画面に表示するのに座標の順序の問題が生じる。
Cindyscriptではたいしたことはないのだが,Pythonでは難航した。
まず,リストのコピーの問題。ミュータブルとイミュータブルだ。deepcopy を発見して解決。
次に図。matplotlib ではうまくいかない。matplotlib.patches を使ってなんとか描けた。
しかし,その結果,次のことがわかった。
しかし,これで「めでたし,めでたし」とはいかないのだ。
なぜなら,でき上がった表示のためのコードは,センター試験の問題のコードとは似ても似つかぬものになっているではないか。これでは授業で「問題を見て書きなさい」とはいえない。できた状態で,袋小路を塗る部分だけを書かせるしかない。
Cindyscriptなら簡単で同じ形をしているから,表示のコードもところどころを空欄にして書かせることができる。Pythonではそうはいかないわけだ。
なお,この時点で,JavaScriptを使うことは諦めた。二兎を追うもの・・である。
この2018年の迷路について書いたのが昨年の12月9日。授業ではこのつぎが2020年の宝探しなのだが,これが書けるまで3ヶ月を要した。その間,高校教員向けのマニュアルや入門書を書きながら,いろいろ調べてきた。2020年の宝探しをやるには次のことができなければならない。
・ボタンを作ること
・画像を表示すること
片方だけではダメ。両方できなければ。
そうして,やっとTkinterにたどり着いたのだが,これまでのPythonで苦労したことがここでもあった。
まだ完成はしていないが,できたものは,Cindyscriptのコードとは似て非なるものとなりそうだ。
少しずつ説明していこう。問題の概要については,「大学入試センター試験「情報関係基礎」問3をプログラムする」を読んでおいてもらうといいだろう。
まず,ゲームの画面を再掲しておこう。

これを Tkinter で描く。マスの部分はキャンバスを作ってその上に描く。それとは別にボタンやガイド(ラベル)をおく。これらを Tkinter ではウィジェットという。
問題の順序にしたがって考えよう。

ア・イのところをプログラムする。方向指定ボタンを作って,d_x,d_y に値を代入する関数を呼び出すようにする。その関数は,Cindyscriptではこうだ。
// 方向指定ボタンで呼ばれる 上・下・左・右
up():=(
dx=0;
dy=-1;
);
down():=(
);
left():=(
);
right():=(
);up() だけを作って,あとを問題にした。問題の本文を読めば下方向は書いてあるし,右方向が ア・イ である。なお,Cindyscript ではアンダースコアは別の意味を持つので,アンダースコアはつけない。このあとPythonでもつけない形で書く。
これにならって,Pythonでも作る。
def up():
dx = 0
dy = -1ボタンは次のように作る。
まず,ボタンを定義
btn1 = tk.Button(text="上", command = up) command = up で,このボタンをクリックすると,関数 up を呼び出すことができる。引数は書かない。つまり,渡せない。
できたボタンを配置する。
btn1.place(x=550, y=200)同じようにして他のボタンも作る。
さあ,他も書けた。実行。
ボタンを押して・・・ 動かない・・・・ エラーメッセージは出ない。
なぜ? 答えは後で。Pythonに詳しい人ならすぐわかるだろう。
いや,詳しくなくても,昨日の記事を読めばわかるか。
とりあえず,次の説明。先程の問題文にある図2。

これは問題ない。これ全体を関数 move としておこう。ウ,エは YOKO , TATE
Cindyscriptでは
// 移動ボタンが押されたときの手続き (図2)
move():=(
message="";
if(robox+dx>0 & robox+dx<=YOKO &
roboy+dy>0 & roboy+dy<=TATE,
robox=robox+dx;
roboy=roboy+dy;
);
nokori=nokori-1;
if(takarax==robox & takaray==roboy,
message="宝を見つけた! 宝探し成功!";
);
);問題の通りに書ける。はじめの massage = "" は問題にはないが,罠に落ちた時のメッセージが表示されたままになるのを修正するために付けたものである。
Pythonでは
# 移動ボタンが押されたときの手続き (図2)
def move():
message = ""
if (robox+dx > 0 and robox+dx <= YOKO and
roboy+dy > 0 and roboy+dy <= TATE):
robox = robox + dx
roboy = roboy + dy
nokori = nokori - 1
if takarax == robox and takaray == roboy:
message = "宝を見つけた! 宝探し成功!"構造は全く同じだ。でもPythonでは動かない。
理由はさっきと同じ。

構造としては問題なく書ける。Cindyscriptは略そう。
# 最小歩数の計算 (図3)
def calc():
sax = takarax - robox
say = takaray - roboy
if sax < 0:
sax = sax * (-1)
if say < 0:
say = say * (-1)
hosuu = sax + sayその次。

# 罠のマス判定 (図4)
def hantei():
for i in range(WANASUU):
if Wanax[i] == robox and Wanay[i] == roboy:
message = "罠にかかった! ダメージを受けた!"
miss = miss + 1
if miss == 3:
message = "3回目だ! ついに壊れた・・宝探し失敗"これも構造上は全く同じように書ける。

ここは同じようにはいかない。02 行目,ボタンが押されたならば だからまずボタンを用意する。そのボタンで図2の関数を実行する。
btn5 = tk.Button(text="移 動",command = move)したがって,書くのは後半。罠探知ボタンも作っておいてこれを呼び出す。
# 罠探知 (図5後半)
def detection():
for i in range(WANASUU):
if Wanax[i] == robox+dx and Wanay[i] == roboy+dy:
message = "罠を発見した"
Wanahyoji[i] = 1
nokori=nokori-1;ひとまずここまで。このあと,全体を動かすための手続きがある。

一見すると,01,02 行目は初期設定で,07行目からはwhile を使って,これまでに作った関数を呼び出せばよさそうだ。しかし,この通りにはできない。
なぜなのか,どうすればいいかも読者諸氏には考えていただこう。
ここまで,「構造としては同じ」と書いた部分は,そのまま教材として穴埋め形式で出せる。一度問題は解いて,答え合わせもしているので,そこを埋めながら打ち込んでいけばよい。
では,また明日。
