まずはこのステップを実行してみて - エニグマ暗号機の仕組みや影響をすぐ体感できる学び方
- エニグマ暗号機の内部構造図を3つ以上探して比較する
部品や動作原理が直感的に理解しやすくなり、歴史的背景も掴める
- ローターやプラグボードの設定パターン例を5通り再現してみる
実際に手順を踏むことで膨大な暗号組み合わせ数(1京以上)への実感が得られる
- 第二次世界大戦時代の解読経緯について、年表形式で10項目まとめ直す
時系列で整理することで技術発展と戦局への影響が具体的につかめる
- 現代暗号技術(AESなど)との違いを2点以上箇条書きで調べて比較する
過去から現代への進化ポイントが明確になり、セキュリティ意識向上にもつながる
仕組みバラバラ:エニグマの影と歴史の余白
エニグマ機――ああ、この名前だけでも歴史の重みを感じる人もいるかもしれない。第二次世界大戦中に、まあ、ドイツ側の通信を守るために使われていたと伝えられている。なんか、アルトゥール・シェルビウスって技術者が設計したんだって…いや、誰それ?って思うけど、とりあえずナチス軍がこれで暗号化してたらしいよ。ちなみに一部資料によれば、その組み合わせは約150,738,274,937,250(数字見るだけで頭痛い…150兆通り!)もあるとか言われてる。複雑すぎじゃない?キーを押すたびに違う文字になるし、それどころか毎回暗号化の方法自体が変わっちゃう仕組みだったという話だよ。
ローターとかプラグボード配線、それからリフレクターまで全部合わさって、高度な安全性を実現していた、らしい。でも…本当にそんなに絶対的だったのかな?ちょっと疑問残るけど。でも事実として多くの専門家がその堅牢さについて言及しているようだし、一応信じておこうかな…。
さて、エニグマの暗号解読。この部分こそ連合国側の勝利へと繋がった要素とも言われているよね。ブレッチリー・パークで働いていたイギリス人暗号解読者たち――アラン・チューリングも含まれている――彼らはこの目的のために電気機械式コンピュータまで作っちゃったんだって。あー、途中でコーヒーでも飲みながら作業してたんだろうか、とどうでもいい想像挟んじゃったけど…。結果として、その努力が戦争期間短縮や人命救助につながったという見方も結構ある。
それでね、以下に紹介するコードなんだけど、これはPythonとFlaskを用いて作成されたエニグマ機シミュレーションになってるんだ。本物には及ばないとしても、このプログラムにはバックエンド側できちんと暗号化ロジックが組み込まれていてさ。ユーザー自身がメッセージ入力したり、ローター状態を変えてみたりすると即座に結果が分かったりするフロントエンド部分も備えているので、「ふーん」程度でも触れてみて損はないかもしれないね。
ローターとかプラグボード配線、それからリフレクターまで全部合わさって、高度な安全性を実現していた、らしい。でも…本当にそんなに絶対的だったのかな?ちょっと疑問残るけど。でも事実として多くの専門家がその堅牢さについて言及しているようだし、一応信じておこうかな…。
さて、エニグマの暗号解読。この部分こそ連合国側の勝利へと繋がった要素とも言われているよね。ブレッチリー・パークで働いていたイギリス人暗号解読者たち――アラン・チューリングも含まれている――彼らはこの目的のために電気機械式コンピュータまで作っちゃったんだって。あー、途中でコーヒーでも飲みながら作業してたんだろうか、とどうでもいい想像挟んじゃったけど…。結果として、その努力が戦争期間短縮や人命救助につながったという見方も結構ある。
それでね、以下に紹介するコードなんだけど、これはPythonとFlaskを用いて作成されたエニグマ機シミュレーションになってるんだ。本物には及ばないとしても、このプログラムにはバックエンド側できちんと暗号化ロジックが組み込まれていてさ。ユーザー自身がメッセージ入力したり、ローター状態を変えてみたりすると即座に結果が分かったりするフロントエンド部分も備えているので、「ふーん」程度でも触れてみて損はないかもしれないね。
フォルダ?仮想環境?混ざる手順で始まる道しるべ
ストーリーに沿って構築するか、あるいは…えっと、まあ気が向いたらこっちから.zipをダウンロードしてもいいよね:https://py-core.com/wp-content/uploads/2025/05/Enigma_Machine.zip ていうか今どきzipってどうなの、みたいなことをふと思ったけど…ま、いいや。
## **ファイル構成**
なんだろう、このフォルダ名の羅列を見るだけで眠くなる。静的ファイルとかtemplateとか、見慣れてる人は「ああ」って感じかな。でも、それでも一応書くよ。
## はじめに
フォルダーと仮想環境を作成します、と言われても…うーん、自分で手打ちするのか?いや、コピペでいいんだよな。Windows の場合とか macOS/Linux の場合で微妙に違うけどさ…。実際 pip install -r requirements.txt までやればOKだったりして。
macOS/Linuxの場合:
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
なんだろう、このコマンド列。やり方忘れるといつもググる羽目になる。まあ、本筋に戻ると、とりあえずこれだけ叩けば環境できるはず。たぶん。
## Flask バックエンド
このプロジェクトのエンジン――要は頭脳部分だけど――それは Python ベースのウェブフレームワーク、Flask 上で動いているわけ。でもさ、「フラスク」って名前の割には全然飲み物感ないな…。えっと、それはさておきサーバーがブラウザからリクエスト受け取って暗号化処理して返す仕組みになっている。本当に全部 `server.py` から始まるんだから笑っちゃう。
## `server.py`
このファイルでは Flask アプリケーションが定義されている。「定義されている」と言われてもピンと来ない人も多い気がするけど…ともかくメインとなるエンドポイントは三つ(いや四つだった)。説明しようとして数間違える自分がイヤになる瞬間あるよね。
正直こういうAPI見るたびに「また似たようなの作っちゃった」って思わなくもない。でも必要だからしかたない。他にも色々書いてあるけど各ルートは全部ちゃんと `enigma_machine.py` から取り込んだEnigmaクラス(補助部品もろとも)とうまく連携しながら動いている模様。……あぁそろそろ眠い。また主題から逸れそうだったのでここまで!
## **ファイル構成**
ENIGMAMACHINE/
|-- static/
|--|-- script.js
|--|-- style.css
|-- templates/
|--|-- index.html
|-- venv/
|-- enigma_machine.py
|-- requirements.txt
|-- server.py
なんだろう、このフォルダ名の羅列を見るだけで眠くなる。静的ファイルとかtemplateとか、見慣れてる人は「ああ」って感じかな。でも、それでも一応書くよ。
## はじめに
フォルダーと仮想環境を作成します、と言われても…うーん、自分で手打ちするのか?いや、コピペでいいんだよな。Windows の場合とか macOS/Linux の場合で微妙に違うけどさ…。実際 pip install -r requirements.txt までやればOKだったりして。
Windowsの場合:
python -m venv venv
venv\Scripts\activate
macOS/Linuxの場合:
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
なんだろう、このコマンド列。やり方忘れるといつもググる羽目になる。まあ、本筋に戻ると、とりあえずこれだけ叩けば環境できるはず。たぶん。
## Flask バックエンド
このプロジェクトのエンジン――要は頭脳部分だけど――それは Python ベースのウェブフレームワーク、Flask 上で動いているわけ。でもさ、「フラスク」って名前の割には全然飲み物感ないな…。えっと、それはさておきサーバーがブラウザからリクエスト受け取って暗号化処理して返す仕組みになっている。本当に全部 `server.py` から始まるんだから笑っちゃう。
## `server.py`
このファイルでは Flask アプリケーションが定義されている。「定義されている」と言われてもピンと来ない人も多い気がするけど…ともかくメインとなるエンドポイントは三つ(いや四つだった)。説明しようとして数間違える自分がイヤになる瞬間あるよね。
- `GET /` : メインインターフェイスを読み込みます。
- `POST /init` : 選択されたローター設定とプラグボードペアで Enigma を初期化します。
- `POST /encrypt` : 個々の文字の処理を行います。
- `POST /reset` : すべてをデフォルト状態に戻します。
正直こういうAPI見るたびに「また似たようなの作っちゃった」って思わなくもない。でも必要だからしかたない。他にも色々書いてあるけど各ルートは全部ちゃんと `enigma_machine.py` から取り込んだEnigmaクラス(補助部品もろとも)とうまく連携しながら動いている模様。……あぁそろそろ眠い。また主題から逸れそうだったのでここまで!

サーバーpy、三つの顔と初期化の迷路
`server.py`の最初の方では、3つのローターが事前に定められた配線とノッチ位置で生成されているんだよね。ああ、なんかこう、実際のエニグマの動きっぽさを出そうとしてる感じ。でもまあ、本物そのものってわけじゃなくて、それなりに雰囲気はあると思う。リフレクターについて言うと、Reflector Bが模倣されていて、それぞれのアルファベットが他の文字に割り当てられる仕組みになっている。…あれ?ちょっと話逸れるけど、最初この辺ややこしく感じたんだよな。ま、ともかく。
さて、`/init`ルートなんだけど、ここではユーザーから入力されたデータを基にしてローター位置とかプラグボードペアが書き換えられるようになってる。それで暗号化準備が整う仕様。でも、一瞬「これ本当に全部反映されてる?」と不安になる…いや、大丈夫だった。戻ろう。本題は、このエンドポイントでメッセージ暗号化のための状態を準備するってところ。
それから`/encrypt`ルートだけど、一度に1文字ずつ受信して、その文字をエニグマ機構へ通す形になってる。その出力として暗号化された結果と現在のローター位置も返却されるよう設計されているんだよね。ふと思ったけど、逐次的な変化を見るには都合いい仕組みなのかもしれない。UI側でも最新状態がちゃんと表示できるし…というか、それ前提で作ってあるっぽい。
最後に`/reset`ルートについて触れておくべきか。ここでは全ユーザー設定を一掃しちゃう仕様でね。ローターはA位置(つまり初期状態)で固定されて、プラグボードペアも空になる。「全部消えて大丈夫?」とか一瞬思ったけど、本来ならむしろそれが狙いなんだろう。
……そして核心部分だけど、実際に文字変換ロジック自体は `enigma_machine.py` の内部に詰め込まれている。このファイルこそがエニグマ機構そのもの―まあ、中身まではちょっと見ないことにするかな。
さて、`/init`ルートなんだけど、ここではユーザーから入力されたデータを基にしてローター位置とかプラグボードペアが書き換えられるようになってる。それで暗号化準備が整う仕様。でも、一瞬「これ本当に全部反映されてる?」と不安になる…いや、大丈夫だった。戻ろう。本題は、このエンドポイントでメッセージ暗号化のための状態を準備するってところ。
それから`/encrypt`ルートだけど、一度に1文字ずつ受信して、その文字をエニグマ機構へ通す形になってる。その出力として暗号化された結果と現在のローター位置も返却されるよう設計されているんだよね。ふと思ったけど、逐次的な変化を見るには都合いい仕組みなのかもしれない。UI側でも最新状態がちゃんと表示できるし…というか、それ前提で作ってあるっぽい。
最後に`/reset`ルートについて触れておくべきか。ここでは全ユーザー設定を一掃しちゃう仕様でね。ローターはA位置(つまり初期状態)で固定されて、プラグボードペアも空になる。「全部消えて大丈夫?」とか一瞬思ったけど、本来ならむしろそれが狙いなんだろう。
……そして核心部分だけど、実際に文字変換ロジック自体は `enigma_machine.py` の内部に詰め込まれている。このファイルこそがエニグマ機構そのもの―まあ、中身まではちょっと見ないことにするかな。
回路図じゃない内部構成、4つの小人たちが踊る
このシステム、なんだかんだで4つの主要なクラスがあるらしい。`Rotor`と、えーっと…あと`Reflector`、それから`Plugboard`と、最後に `Enigma` ってやつね。まあ、名前だけ見てるとパーツ多そうだけど、実際はわりと単純かもしれない。たぶん。
### `Rotor`
ローターってやつ、それぞれ配線があって入力された文字を変換する仕組みになってるみたい。で、自分自身のノッチ位置もちゃんと覚えてるという話。うーん…あ、このノッチに到達した瞬間に次のローターも回すようになってて、本物のエニグマ機によくある連鎖反応みたいなのが再現されてる、と聞いたことがある気がする。まあ一度混乱すると頭痛くなるけどさ。「step()」関数でローターを1ポジション進めたり、「encode_forward()」メソッドでは入力文字をどうこうして、「encode_backward()」になると今度は反射された信号をまた別ルートで変換して返す感じ?ま、とにかく複雑っぽい割には理屈自体は分かりやすい…かな、多分。
### `Reflector`
リフレクター(つまり反射器)は、そのローター群の最後尾に設置されているものらしいよ。でもこれ、不思議なくらい静かな存在なんだよね…。何と言うか、信号をもう一回ローター側へ押し戻す役目だけ担当してるっぽい。そのくせ自分自身は絶対動かないという頑固さも持ち合わせている。不動明王的な雰囲気?いや違うかも…まいいや。そして毎回同じ入力には必ず同じ出力を返すようになっていて、それがこの装置全体の不可逆性とか面白さにつながってる気がするけど、本当にそうなのかなぁ…。
### `Rotor`
ローターってやつ、それぞれ配線があって入力された文字を変換する仕組みになってるみたい。で、自分自身のノッチ位置もちゃんと覚えてるという話。うーん…あ、このノッチに到達した瞬間に次のローターも回すようになってて、本物のエニグマ機によくある連鎖反応みたいなのが再現されてる、と聞いたことがある気がする。まあ一度混乱すると頭痛くなるけどさ。「step()」関数でローターを1ポジション進めたり、「encode_forward()」メソッドでは入力文字をどうこうして、「encode_backward()」になると今度は反射された信号をまた別ルートで変換して返す感じ?ま、とにかく複雑っぽい割には理屈自体は分かりやすい…かな、多分。
### `Reflector`
リフレクター(つまり反射器)は、そのローター群の最後尾に設置されているものらしいよ。でもこれ、不思議なくらい静かな存在なんだよね…。何と言うか、信号をもう一回ローター側へ押し戻す役目だけ担当してるっぽい。そのくせ自分自身は絶対動かないという頑固さも持ち合わせている。不動明王的な雰囲気?いや違うかも…まいいや。そして毎回同じ入力には必ず同じ出力を返すようになっていて、それがこの装置全体の不可逆性とか面白さにつながってる気がするけど、本当にそうなのかなぁ…。

ローターが回る時、前も後ろもわからなくなる瞬間
### 「プラグボード」
プラグボードってね、ローターを通る前と後で文字のペアを入れ替える役目があるんだよ。なんというか、これのおかげで暗号化の層がもう一つ重なる感じになる。えっと、実際に作る場合には文字ごとのペア関係を辞書型で定義するんだけど……あ、今ちょっと辞書って言葉で昔の英単語帳思い出した。いや関係ないな、ごめん戻る。だから設定されたペアが無い文字は何も変わらず、そのまま流れていく。それだけシンプルだけど意外と大事な仕組み、だと思う。
### 「エニグマ」
このクラス…つまり全部まとめてコントロールするやつなんだけど、3つのローター、それからリフレクター1個とプラグボード1枚で構成されている。ふう、説明疲れるな。でもちゃんと伝えたい。ローターのステップ処理とか、一段一段文字を通していく流れまで、このクラスが担当してるってわけだ。`encrypt_char()` メソッドは1文字ずつ動く仕様になっていて——ああ、途中でどうでもいいこと考えたけど話戻す——手順としてはまず入力を受け取って、それぞれの要素を順に通過させて最終的な結果が返る仕掛けになっているらしい。気付いたら結構複雑なんだよね、この辺り。ま、いいか。
プラグボードってね、ローターを通る前と後で文字のペアを入れ替える役目があるんだよ。なんというか、これのおかげで暗号化の層がもう一つ重なる感じになる。えっと、実際に作る場合には文字ごとのペア関係を辞書型で定義するんだけど……あ、今ちょっと辞書って言葉で昔の英単語帳思い出した。いや関係ないな、ごめん戻る。だから設定されたペアが無い文字は何も変わらず、そのまま流れていく。それだけシンプルだけど意外と大事な仕組み、だと思う。
### 「エニグマ」
このクラス…つまり全部まとめてコントロールするやつなんだけど、3つのローター、それからリフレクター1個とプラグボード1枚で構成されている。ふう、説明疲れるな。でもちゃんと伝えたい。ローターのステップ処理とか、一段一段文字を通していく流れまで、このクラスが担当してるってわけだ。`encrypt_char()` メソッドは1文字ずつ動く仕様になっていて——ああ、途中でどうでもいいこと考えたけど話戻す——手順としてはまず入力を受け取って、それぞれの要素を順に通過させて最終的な結果が返る仕掛けになっているらしい。気付いたら結構複雑なんだよね、この辺り。ま、いいか。
反射板って固定席…いやただの鏡じゃないはずだが
プラグボードでの交換、ああ、そういえばね。まずはそれから始まる。2. ローターを順方向に通過──この手順、何度もやってると指が勝手に覚えるんだけど、たまに混乱することもある。3. リフレクターで反射。この時点で「あれ?もう半分終わった?」みたいな気持ちになるけど油断できない。4. ローターを逆方向に通過する工程があって……なんだか面倒くさいと思う瞬間も正直ある。でも仕方ないよね、この複雑さこそエニグマらしいし。5. 最後のプラグボード交換で一巡り完了。ただ、ここまで説明しておいてふと「こんな手順、本当に全部頭入れて使ってたのかな」と自問したくなる。
`encrypt_message()`メソッドはメッセージ内の各文字を1つずつ暗号化するためにループ処理を行うんだけど、単調作業っぽい印象とは裏腹になぜか集中力が切れる時がある。不思議だよなぁ。それでもミスできない緊張感は常について回るという…。`get_rotor_positions()`メソッドでは現在各ローターウィンドウ(左から右)に表示されている文字を返す仕様になっている。細かい部分なんだけど「今どうなってる?」と確認したい時には便利だったりする。
self.step_rotors()
return self.plugboard.swap(c)
## JavaScript: PythonとのUI接続
このプロジェクトのフロントエンドは `static/script.js` に依存している。一応書いておくと、このファイルはHTMLインターフェースとFlaskバックエンドをつなぐ役割を果たす。ユーザーがキー押下するとJavaScriptが入力内容取得、そのキーを視覚的にハイライトし、暗号化用としてその文字データをバックエンドへ送信する流れになる。「まあ普通だろ」と思いつつも自分なら絶対スペルミスしそうなので要注意ポイント多し。画面上表示されたローターもクリックによる操作可能——これ意外と地味に助かったりするんだよね、不器用だからマウス対応ありがたい感じだった…。
`encrypt_message()`メソッドはメッセージ内の各文字を1つずつ暗号化するためにループ処理を行うんだけど、単調作業っぽい印象とは裏腹になぜか集中力が切れる時がある。不思議だよなぁ。それでもミスできない緊張感は常について回るという…。`get_rotor_positions()`メソッドでは現在各ローターウィンドウ(左から右)に表示されている文字を返す仕様になっている。細かい部分なんだけど「今どうなってる?」と確認したい時には便利だったりする。
## `enigma_machine.py`
from string import ascii_uppercase
class Rotor:
def __init__(self, wiring, notch, position='A'):
self.wiring = wiring
self.notch = notch
self.position = ascii_uppercase.index(position)
def encode_forward(self, c):
index = (ascii_uppercase.index(c) + self.position) % 26
return self.wiring[index]
def encode_backward(self, c):
index = (self.wiring.index(c) - self.position) % 26
return ascii_uppercase[index]
def step(self):
self.position = (self.position + 1) % 26
return ascii_uppercase[self.position] == self.notch
def current_letter(self):
return ascii_uppercase[self.position]
class Reflector:
def __init__(self, wiring):
self.wiring = wiring
def reflect(self, c):
return self.wiring[ascii_uppercase.index(c)]
class Plugboard:
def __init__(self, pairs=None):
self.mapping = {c: c for c in ascii_uppercase}
if pairs:
for a, b in pairs.items():
self.mapping[a] = b
self.mapping[b] = a
def swap(self, c):
return self.mapping.get(c, c)
class Enigma:
def __init__(self, rotors, reflector, plugboard):
# 右から左へ配置というのが地味に紛らわしい…いや慣れればどうってことないか。
self.rotors = rotors
self.reflector = reflector
self.plugboard = plugboard
def step_rotors(self):
if self.rotors[0].step(): # 一番右のローター
if self.rotors[1].step(): # 中央のローター
# あっ、中断して別件考えてた…続き戻す。
self.rotors[2].step() # 一番左のローター
def encrypt_char(self, c):
if c not in ascii_uppercase:
return c
self.step_rotors()
c = self.plugboard.swap(c)
for rotor in self.rotors:
c = rotor.encode_forward(c)
c = self.reflector.reflect(c)
for rotor in reversed(self.rotors):
c = rotor.encode_backward(c)
return self.plugboard.swap(c)
def encrypt_message(self, message):
# 実際こういうループ見ると無限に続く気もしてくるけど、それは錯覚だから大丈夫。
return ''.join(self.encrypt_char(c) for c in message if c in ascii_uppercase)
def get_rotor_positions(self):
# 現在位置取得用。この出力を見る度「動いてるな…」と思わずぼーっと見てしまう。
return ''.join(r.current_letter() for r in reversed(self.rotors))
## JavaScript: PythonとのUI接続
このプロジェクトのフロントエンドは `static/script.js` に依存している。一応書いておくと、このファイルはHTMLインターフェースとFlaskバックエンドをつなぐ役割を果たす。ユーザーがキー押下するとJavaScriptが入力内容取得、そのキーを視覚的にハイライトし、暗号化用としてその文字データをバックエンドへ送信する流れになる。「まあ普通だろ」と思いつつも自分なら絶対スペルミスしそうなので要注意ポイント多し。画面上表示されたローターもクリックによる操作可能——これ意外と地味に助かったりするんだよね、不器用だからマウス対応ありがたい感じだった…。

プラグボード配線地獄、辞書なのか?実体不明な交換劇場
各クリックによってローターの開始位置が変わるんだけど、これはね、実際のオペレーターが暗号化する前にやってた手動のセットアップ手順を模しているらしい。なんか昔のことを思い出す…いや、実はそんなに昔を知ってるわけじゃないけど。ただ、それよりプラグボードについて話したほうがいいか。ユーザーは文字ボタンをクリックしてペアリングを作成できて、その時ペアリングラインも表示されるし、設定内容の要約テキストだってちゃんと更新されるんだよね。ああ、説明くどいかな?でも仕様だからしょうがない。
でさ、`initializeEnigmaBeforeTyping()` という関数があるけど、これのおかげで現状ローターとプラグボード設定でバックエンドが正しく初期化されていることになる。その処理自体は入力開始前に一度しか行われないみたいだ。うーん、一回きりってちょっとドキドキするよな。でもまぁ次へ進もう。
ユーザーが文字押すと、その時点でコードは現在のローター位置とかプラグボード構成、それから選ばれた文字も含めて `http://127.0.0.1:5000/encrypt` へリクエスト送信する流れになっている。それと同時にサーバー側から暗号化された文字と新しいローター状態も返却される感じ。この辺、ごちゃごちゃ考えすぎても仕方ないし…まあ、とりあえず画面には入力内容や暗号化結果、新しくなったローター配列まで全部表示されるという話。
そういえばリセットボタンも用意されていて、それを押すことで `http://127.0.0.1:5000/reset` へのコールが発生するんだったっけ?その瞬間ディスプレイはクリアされるし、全てのローター設定やプラグボードペアリングまでもリセットされちゃう。何度やり直しても大丈夫なのだけど、本当に必要な時以外むやみに押さない方がいいかもしれない……ま、大事なのは一応伝えたと思うのでこのくらいで切り上げようかな。
でさ、`initializeEnigmaBeforeTyping()` という関数があるけど、これのおかげで現状ローターとプラグボード設定でバックエンドが正しく初期化されていることになる。その処理自体は入力開始前に一度しか行われないみたいだ。うーん、一回きりってちょっとドキドキするよな。でもまぁ次へ進もう。
ユーザーが文字押すと、その時点でコードは現在のローター位置とかプラグボード構成、それから選ばれた文字も含めて `http://127.0.0.1:5000/encrypt` へリクエスト送信する流れになっている。それと同時にサーバー側から暗号化された文字と新しいローター状態も返却される感じ。この辺、ごちゃごちゃ考えすぎても仕方ないし…まあ、とりあえず画面には入力内容や暗号化結果、新しくなったローター配列まで全部表示されるという話。
そういえばリセットボタンも用意されていて、それを押すことで `http://127.0.0.1:5000/reset` へのコールが発生するんだったっけ?その瞬間ディスプレイはクリアされるし、全てのローター設定やプラグボードペアリングまでもリセットされちゃう。何度やり直しても大丈夫なのだけど、本当に必要な時以外むやみに押さない方がいいかもしれない……ま、大事なのは一応伝えたと思うのでこのくらいで切り上げようかな。
暗号プロセス分解不能──1文字ずつ進む迷宮へようこそ
script.js……って名前、なんかもうベタすぎて逆に落ち着く。まあいいや、本題。えっと、このファイルの冒頭には var _keys = window._keys || {}; がぽつんとあって、初期化フラグの enigmaInitialized も false で用意されてる。あー、今朝もコーヒーがうまく淹れられなかったな……いや関係ないか。</code></pre>
////キーボード入力の処理部分なんだけどさ、document.onkeydown の中ではまず String.fromCharCode(e.keyCode).toUpperCase() で押されたキーを大文字にして受け取ってるんだよね。でもアルファベットじゃない場合はスルーする仕組みになってて、_keys に存在しなかったら return されちゃう。ま、それはしょうがない。
e.preventDefault(); と _keys[letter].classList.add('pressed'); を挟んでから、「エニグマ」本体を初期化していない時だけ initializeEnigmaBeforeTyping() を await してフラグを true にする流れがある。その後 sendToEnigma(letter) が呼ばれて暗号化へ進む感じ。ああ~途中でふと思ったけど、「await」書き忘れると地味にハマるんだよね、自分だけかな……? 戻ろう。
onkeyup のほうは document.onkeyup = function(e) { ... } で始まり、中身は押されたキーが離された瞬間に .classList.remove('pressed') を呼び出してハイライトを解除する。_keys[letter] の有無チェックあり。でもこれ二回定義されてるような気配あるけど、まあ実害は…たぶん無い?
次の async function initializeAndSend(letter) はエニグマ未初期化なら await initializeEnigmaBeforeTyping() を噛ませて、そのあと送信という流儀。ただしこの関数自体本文内では使われている形跡薄いっぽい(少なくともここまで読む限り)。
(function(k){...}) の即時実行関数では DOM 上にある全部の .key クラス要素をループして _keys に textContent をキーとして格納している。一見地味だけど必要不可欠なんだよねこういうやつ。
またロータークリック系——rotors 配列(‘rotor-1’, ‘rotor-2’, ‘rotor-3’) と alphabet(‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’) 用意した上で rotors.forEach(id => {...}) という具合にイベントリスナー付与。それぞれクリックごとテキスト内容を書き換えて次のアルファベットへ回す仕掛けになってる。「A→B→C...」みたいな循環式。この辺手癖で書いた気持ち分かるわ…。
プラグボード関連もまぁ色々手間かかっていて、let selectedPlugs = []; plugPairs = {}; usedPairClasses = 0; と管理変数ずらり並ぶところからスタート。「resetPlugSelections」は選択中プラグを全解除、「getPlugByLabel」は渡された label の plug 要素探し出す役目になっている(querySelectorAll('.plug')周りとか特に)。
updatePlugSummary 関数では Object.entries(plugPairs) をフィルタリングしながら「A↔B」の形式文字列作成、それを #plug-summary 要素へ突っ込む流儀。他愛ないけど情報整理力問われたりする一幕。
実際ユーザーがプラグクリックすると、その plug 要素取得・選択状態追加・selectedPlugs.push…。もし既存ペアならアラート表示『◯◯は既に△△と接続されています』になるし。同じ文字同士だった場合も弾く仕様。「pairClass」で最大10色サイクル的背景色付与とか細部妙につめこまれている感触。
sendToEnigma(letter) は現在ローター位置取得(document.getElementById("rotor-x").textContent)、plugPairs 状態含め payload 化。そして fetch("http://127.0.0.1:5000/encrypt", ...) POST 投げて結果(await response.json())受領後 UI 更新(updateDisplay)。
updateDisplay 自体は入力履歴欄/暗号文欄/現ローター表示欄それぞれ textContent 書き足すのみだからシンプルと言えばシンプル。でもさぁ…console.log(`Encrypted ${letter} → ${result.encrypted}`)、こういうデバッグログ残しっぱなしなの見るたび「あー前夜眠かったのかな」と思ったりする…関係ない話だった、ごめんなさい!
ビジュアルキーボード上でも .key 全件 forEach→addEventListener('click', ...) 設定済み。その場でもエニグマ初期化&sendToEnigma 呼び出せる設計だね。あと reset-button 押下時にはバックエンドリセット用 fetch("http://127.0.0.1:5000/reset",{method:"POST"}) 挟みつつフロント側UI/状態全部クリア(typed, encrypted, rotor-state, rotor-x)され plugPairs や usedPairClasses 初期値へ戻す、と。ま、一息入れる余裕くらい欲しいものです…。
最後は initializeEnigmaBeforeTyping()—これ現在ローター&plugboard状態まとめた payload 作成→fetch("http://127.0.0.1:5000/init",...) POST 投げとなるので、本当に最小限しかやってない印象。「何度目かわからぬ再起動」に似た虚脱感覚えることもあるけど重要工程には違いない。
UI 部分について言及すると、本体ビジュアル/プラグボード/クリック対応キーボード等ごちゃっと詰まったインターフェース構造。それぞれ static/style.css に依存強い感じあり。この CSS ファイルではダークグレー基調背景・金色&茶色系統アクセント・影効果など駆使して機械的質感表現狙われていて、各クラス(.key, .rotor, .plug 等)毎レイアウトや配色細密設定済み。「押下キー沈みこむ」「選択中プラグ黄色点滅」「異なるペア毎独立背景」と物理模倣性高め。当然ながらコンピュータ画面越しじゃ温度とか伝わらなくても、それっぽさへの執念というか…いや妙な方向行きそうなのでこの辺で止めよう。また明日続きを考えようかな…。

JavaScript側で暴走するUI操作、誰も止められぬ連携失敗例集
最大で10色まで、ユニークな色が順番に使われる。いや、正確には「明瞭さを保つため」っていう理由もあるんだけど、色数が多すぎても目が疲れるしね……。CSSレイアウトは全体的に中央寄せされてて、そのうえ各セクションもなんだか本物のエニグママシンっぽい雰囲気を出そうとしているんだよ。ま、私自身は本物を見たことないけど。ああ、それとプラグボードジャック間のスペースもちゃんと含めて調整してあるみたい。
## `templates/index.html`
このHTMLファイルではシミュレーターの構造が定義されてる。最上部にはローター領域が配置されていて――まあ、この部分、ユーザーはクリックすることで各ローターを回転できるようになってるんだよね。あれ?今何の話してたっけ? あ、そうそう。その下にキーボードグリッドが並ぶ形で置かれていて、それぞれの文字はQWERTZ配列で行ごとにまとめられている(ドイツ製エニグマモデル準拠)。余談だけどQWERTYじゃなくQWERTZなの、本当にややこしいと思わない?でもまあ仕方ない。そのさらに下にはプラグボードが設置されていて、2つの文字をクリックすると接続される仕様なんだ。それによってペアリングが決まり、その結果として暗号化処理にも影響が出るというわけなんだけど…うーん、不思議な仕組みだよなぁ。でも結局全部合わせて一つの流れになるから、とりあえず触ってみたほうが早いかもしれないね。
## `templates/index.html`
このHTMLファイルではシミュレーターの構造が定義されてる。最上部にはローター領域が配置されていて――まあ、この部分、ユーザーはクリックすることで各ローターを回転できるようになってるんだよね。あれ?今何の話してたっけ? あ、そうそう。その下にキーボードグリッドが並ぶ形で置かれていて、それぞれの文字はQWERTZ配列で行ごとにまとめられている(ドイツ製エニグマモデル準拠)。余談だけどQWERTYじゃなくQWERTZなの、本当にややこしいと思わない?でもまあ仕方ない。そのさらに下にはプラグボードが設置されていて、2つの文字をクリックすると接続される仕様なんだ。それによってペアリングが決まり、その結果として暗号化処理にも影響が出るというわけなんだけど…うーん、不思議な仕組みだよなぁ。でも結局全部合わせて一つの流れになるから、とりあえず触ってみたほうが早いかもしれないね。
最後に残ったもの―黄金色キーボードと沈黙するリセット
ステータスパネルには、入力した文字や暗号化の結果、ローターの状態、それからプラグボードの接続状況なんかも表示されるんだよね。あ、そういえば昔似たようなインターフェイスを見た気もするけど…いや違ったかな。ま、とにかく色んな情報が一目で分かる感じになってる。うーん、でもこの手のパネルって時々何を表示しているのか分からなくなる瞬間あるよね?私だけかな、多分そんなことないと思うけど。不意に他の事考え出してしまうんだけど、戻ろう、本題へ——つまり全部がちゃんと確認できて便利なんだ。}
{ここまで読んでくれて本当にありがとう、と言いたいところだけど、ちょっと変な気持ちになる日もあるよね。もしこの記事が少しでも役立ったと思ったら、それはそれで嬉しいし……ああ、ごめん突然脱線した。でも質問とか、「こんなPythonコード例を書いてほしい」みたいなのがあれば遠慮せず教えてほしいなって思います(実際メールとか来ると妙に緊張するけど)。皆さんからのお便りやリクエストはいつでも歓迎してますので!さて……プログラミング楽しむこと忘れずに。またPy-Core.com Python Programmingで会える日を心待ちにしています。
## `style.css`css
body{background-color:#2e2e2e}
...
## index.htmlxml
<head>
<meta charset="UTF-8">
<title>Enigma Keyboard</title>
<link rel="stylesheet" href="%7B%7B%20url_for('static',%20filename='style.css')%20%7D%7D">
</head><body>
<div class="layout-container">
...
</div>
</body>
{ここまで読んでくれて本当にありがとう、と言いたいところだけど、ちょっと変な気持ちになる日もあるよね。もしこの記事が少しでも役立ったと思ったら、それはそれで嬉しいし……ああ、ごめん突然脱線した。でも質問とか、「こんなPythonコード例を書いてほしい」みたいなのがあれば遠慮せず教えてほしいなって思います(実際メールとか来ると妙に緊張するけど)。皆さんからのお便りやリクエストはいつでも歓迎してますので!さて……プログラミング楽しむこと忘れずに。またPy-Core.com Python Programmingで会える日を心待ちにしています。