2025年の共通テストから「情報I」が入る。以下はまだ「入るはずである(まだ決まったわけではないが)」という時期に書いたものに一部加筆したものである。そのころ、大学入試センターが作って限られたところに配付していた試作問題を,情報処理学会が大学入試センターと調整して大学入学共通テストへの「情報」の出題についての追記で公開した。この試作問題は「検討用イメージ」で,実際にこの形で出題されることが決まったわけではなかった。
この第5問がプログラミングの問題で,シーザー暗号がとりあげられている。言語は今までもセンター試験で出題されていた「情報関係基礎」という科目で使われている擬似言語「DNCL」(DNCは大学入試センターの略)をPython風にアレンジしたものである。この擬似言語は今はDNCLではなく「共通テスト用プログラム表記」と呼ばれている(ドント法のページも参照)。
この問題を実際にPythonを使いながら眺めてみよう。
この問題で解く暗号文は,問題の最後で,リンカーンの有名なゲティスバーグ演説を小文字にしたものであることがわかる:
gettysburg = """Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal. Now we are engaged in a great civil war, testing whether that nation, or any nation so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this. But, in a larger sense, we can not dedicate -- we can not consecrate -- we can not hallow -- this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us -- that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion -- that we here highly resolve that these dead shall not have died in vain -- that this nation, under God, shall have a new birth of freedom -- and that government of the people, by the people, for the people, shall not perish from the earth.""" Hirabun = gettysburg.lower()
暗号文はこれを10文字ずらしたシーザー暗号である。ただし,アルファベット以外の部分はそのままである。
alphabet = "abcdefghijklmnopqrstuvwxyz" codebook = alphabet[10:] + alphabet[:10] tbl = str.maketrans(alphabet, codebook) Angoubun = Hirabun.translate(tbl) print(Angoubun)
pyeb cmybo kxn cofox iokbc kqy yeb pkdrobc lbyeqrd pybdr yx drsc myxdsxoxd, k xog xkdsyx, myxmosfon sx vslobdi, kxn nonsmkdon dy dro zbyzycsdsyx drkd kvv wox kbo mbokdon oaekv. xyg go kbo oxqkqon sx k qbokd msfsv gkb, docdsxq grodrob drkd xkdsyx, yb kxi xkdsyx cy myxmosfon kxn cy nonsmkdon, mkx vyxq oxnebo. go kbo wod yx k qbokd lkddvo-psovn yp drkd gkb. go rkfo mywo dy nonsmkdo k zybdsyx yp drkd psovn, kc k psxkv bocdsxq zvkmo pyb dryco gry robo qkfo drosb vsfoc drkd drkd xkdsyx wsqrd vsfo. sd sc kvdyqodrob psddsxq kxn zbyzob drkd go cryevn ny drsc. led, sx k vkbqob coxco, go mkx xyd nonsmkdo -- go mkx xyd myxcombkdo -- go mkx xyd rkvvyg -- drsc qbyexn. dro lbkfo wox, vsfsxq kxn nokn, gry cdbeqqvon robo, rkfo myxcombkdon sd, pkb klyfo yeb zyyb zygob dy knn yb nodbkmd. dro gybvn gsvv vsddvo xydo, xyb vyxq bowowlob grkd go cki robo, led sd mkx xofob pybqod grkd droi nsn robo. sd sc pyb ec dro vsfsxq, bkdrob, dy lo nonsmkdon robo dy dro expsxscron gybu grsmr droi gry pyeqrd robo rkfo drec pkb cy xylvi knfkxmon. sd sc bkdrob pyb ec dy lo robo nonsmkdon dy dro qbokd dkcu bowksxsxq lopybo ec -- drkd pbyw droco ryxybon nokn go dkuo sxmbokcon nofydsyx dy drkd mkeco pyb grsmr droi qkfo dro vkcd pevv wokcebo yp nofydsyx -- drkd go robo rsqrvi bocyvfo drkd droco nokn crkvv xyd rkfo nson sx fksx -- drkd drsc xkdsyx, exnob qyn, crkvv rkfo k xog lsbdr yp pboonyw -- kxn drkd qyfobxwoxd yp dro zoyzvo, li dro zoyzvo, pyb dro zoyzvo, crkvv xyd zobscr pbyw dro okbdr.
問題ではまず出現するアルファベットの度数分布を調べる:
ここで 差分()
は a〜z を 0〜25 に置き換える関数とのことである(ちょっと名前がそぐわない?)。ただし,アルファベット以外は -1 に置き換える。Pythonで書けば次のようになる:
def 差分(c): d = ord(c) - ord("a") if d < 0 or d > 25: d = -1 return d
この関数を使えば,上の問題のプログラムはPythonでは次のようになる:
Hindo = [0] * 26 for i in range(len(Angoubun)): bangou = 差分(Angoubun[i]) if bangou != -1: Hindo[bangou] = Hindo[bangou] + 1 print(Hindo)
なお,Pythonとしては
for c in Angoubun: bangou = 差分(c) if bangou != -1: Hindo[bangou] += 1
と書くほうがきれいである。なお,Pythonのスタイルガイド PEP 8 では変数名や関数名は小文字が推奨されているが,ここでは問題に従った(大学入試センター試験「情報関係基礎」で使われていたDNCLという擬似言語や「情報I」で使われる「共通テスト用プログラム表記」では配列名は大文字で始める)。Pythonは大文字で始めるとクラス名みたいに見えるので,本当にPython風にするなら小文字で始めるほうがいいように思う。
この度数分布を棒グラフで表す:
import matplotlib.pyplot as plt plt.bar(list(alphabet), Hindo)
このパターンから推理して,10文字ずらしたことを突き止め,解読に成功する,というストーリーである。
これをPythonにするのは練習問題として残しておく。