コーディングの練習に暗号解読はいかがですか？（シーザー暗号）

# 目的
* プログラミング初心者向けに、コーディングの練習方法とモチベーションを提供しようという内容です。
* 基本文法が分かってきて、コーディング練習にちょうどいい題材を探している方などを対象にしています。
（本記事ではPythonを使っていますが、他の言語でも容易に実装可能な内容です。）

# コーディング練習で困ること
変数とかif文とかfor文とか、基本文法は分かってきたけれど、次に何をやればいいのか、どう練習をすればいいのか悩んだりしていませんか。
コーディングは基本的に、様々な書き方やパターンで数をこなして、自在に使いこなせるように慣れていくしかありません。
とはいえ、題材になるものが決まらないと「数字が〜以上の時は〇〇をprintする」みたいな、明確な目的の無い数行だけの単純なコードを延々と書いて十分な練習にならなかったりします。

# 暗号解読という題材
コーディングの練習として、暗号解読を題材にしてみるのはいかがでしょうか。
実際に私がプログラミングの勉強を始めた頃に練習に書いていたのですが、これが中々面白いです。
しかも、よく使う文字列操作や配列の取り扱いについて自分なりに考えながら学べるので、題材としても適切だと思います。
特に、最も基本的な暗号で、実装のレベル感としても簡単なシーザー暗号をオススメします。


# シーザー暗号
シーザー暗号とは、「ブルータス、お前もか」で有名なカエサルが使用したことで知られる、単一換字式暗号です。カエサル式暗号とか、シフト暗号などとも呼ばれます。
暗号の仕組みはシンプルで、平文（暗号化される前の元の文章）に対して、一つ一つの文字をあらかじめ用意された規則（暗号用に文字の一覧と順番を記載した辞書や表）に従って、文字を置き換えていく（シフトする）だけです。
規則に従って同じ文字が常に決まった文字に（一意に＝単一に）変換される（文字変換＝換字）ため、単一換字式の暗号というわけですね。
## 例
アルファベット順を規則として、「apple」をシフト数 = 1 で暗号化した場合、次のようになります。
a　 p 　p 　l 　e
↓　↓　↓　↓　↓
b　q 　q　m 　f 


# 暗号化スクリプト
下記は私が実際にPythonでコーディングしてみたシーザー暗号の暗号化スクリプトです。
まずは何も見ず、先に自分でコーディングした後に内容を比較してみたり、コードを読んでどんな処理をしているのかを知るのもいいです。（他人のコードを読むことも、かなり重要な勉強方法です。）
なんなら丸々コピーして、先に動作を確認してみてもいいと思います。

* コマンドで実行することを想定したスクリプトです。
* 『python encryption.py "{平文}" {シフト数}』の形式で、引数に平文とシフト数を指定します。
* 平文に記号が含まれる場合は、""で囲まないと処理できない場合があります。
* rule.pyに記載が無い文字は変換できません（「!」、「？」など）
* シフト数が規則の長さを超えた場合は、規則の頭に戻り、ループして変換します、
（ex. 「^」をシフト数 = 1 で変換すると「a」になります。）

```Python:rule.py
# 変換ルール（アルファベット）
ALPHABET = ["a", "b", "c", "d", "e", "f", "g", "h", "i",
            "j", "k", "l", "m", "n", "o", "p", "q", "r",
            "s", "t", "u", "v", "w", "x", "y", "z"]

# 変換ルール（記号）
MARK = [" ", ".", ",", "+", "-", "=", "/", "@", "#",
        "$", "%", "&", "(", ")", "*", ":", ";", "<",
        ">", "_", "[", "]", "{", "}", "~", "'", "^"]

# 変換ルール
RULE = ALPHABET + MARK

# 変換ルール長
RULE_LENGTH = len(RULE)
```
```Python:encryption.py
import sys

from rule import RULE, RULE_LENGTH


# 暗号化
def encrypt(target_text, shift):
    encrypt_text = ""
    char_list = [char for char in target_text]
    for c in char_list:
        char_index = RULE.index(c)
        new_index = char_index + shift
        if new_index < RULE_LENGTH:
            encrypt_text += RULE[new_index]
        else:
            re_index = new_index - RULE_LENGTH
            encrypt_text += RULE[re_index]
    return encrypt_text


def main(args):
    target_text = args[1]
    shift = int(args[2])
    encrypt_text = encrypt(target_text, shift)
    print(encrypt_text)


if __name__ == '__main__':
    args = sys.argv
    main(args)
```
## 実行結果
コマンド（入力）
```
python encryption.py "test" 5
```
出力
```
yjxy
```

# 次のステップ
練習なので、上記の暗号化スクリプトについて、特に詳細な解説などはしません。
一つ一つの処理や関数は基本的なものしか使っていないので、調べればすぐにどんな処理をしているのかは分かります。
また、上記のスクリプトは基本的な機能でしか実装されていないので、自分で機能を色々と追加して遊んでみるのもいいと思います。
例えば、規則に文字を追加したり、大文字・小文字に対応させたり、日本語に対応させるのもありです。

そして、特にオススメの次のステップとして、まずは上記スクリプトで作成された暗号を、**復号するスクリプト**を作成してみてください。
処理内容としては大きく変わらないため簡単ですし、何より復号に成功した時はちょっとした感動があります。

# 暗号解読してみよう！
というわけで、最後に暗号を残しておきます。規則は上記スクリプトと同じです。
あえて暗号化時のシフト数は伏せておきますので、ぜひ解読してみてください！
（ヒント：復号すると文章のどこかに「python」という文字列が現れます。）
```
nb]heusiou^ilusiolub]l~uqileuchu~'}cjb'lchaunb'u}i~'vusioub]p'uhiqucgjlip'~usiolujsnbihumecffmu{suih'ugil'uf'p'fvuf'n_mu}ihncho'uniu}b]ff'ha'up]lciomu}i~chau]h~uqileunia'nb'lv
```
<br>
<br>

弊社では積極的に採用活動中です。
未経験からエンジニアになった方も多いですが、バッチリ活躍しています。
かくいう私も30歳を過ぎてから転職した身ですが、幸いなことに採用いただき、日々勉強しながら取り組んでいます。
経験・未経験、新卒・中途問わず募集しておりますので、ご興味のある方は[こちら](https://www.recruit.nuco.co.jp/)をご覧ください。

***
[シーザー暗号(Wikipedia)](https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%BC%E3%82%B6%E3%83%BC%E6%9A%97%E5%8F%B7)