干支を出力するPythonスクリプト

# 干支を意識する時期
日本には干支という文化がありますが、正直なところ干支を意識するのは正月や翌年の年賀状の準備をする頃だけという人も多いと思います。
そこで、Pythonの辞書の取り扱いの練習を兼ねて、指定した年の干支を出力するPythonスクリプトを作成しました。
スクリプト序盤のコードは先日投稿した[西暦2025年は昭和100年みたいな計算をするPythonスクリプト](https://qiita.com/whisky_frisky/items/5fa1dda631702a4c5bcb)のコードの流用です。
ちなみに、例として2025年の干支は「巳（へび）」だと思っている人が相当数いると思われますが、それは「十二支」であって、干支は甲・乙・丙などの「十干（じっかん）」と合わせて表され、2025年の干支は「乙巳（きのと み）」だそうです。

# 魔暦と悪魔干支も出力する
このスクリプトでは十干と十二支だけでなく、魔暦と悪魔干支も出力するようにします。
魔暦と悪魔干支については下記リンク先デーモン閣下の公式サイトを参照ください。
[魔暦（Ｄ.Ｃ.）とは](https://demon-kakka.jp/aboutDC/)

# コード全体
```python
import sys


target_year_str = input("What year?: ")

try:
    target_year_int = int(target_year_str)
except:
    print("The value must be an integer.")
    sys.exit()

if target_year_int <= 0:
    print("The value must be larger than 0.")
    sys.exit()

# 十干
eto10_dict = {
    0:"庚", 1:"辛", 2:"壬", 3:"癸", 4:"甲",
    5:"乙", 6:"丙", 7:"丁", 8:"戊", 9:"己",
}

# 十二支
eto12_dict = {
    0:"申", 1:"酉", 2:"戌", 3:"亥", 4:"子", 5:"丑", 
    6:"寅", 7:"卯", 8:"辰", 9:"巳", 10:"午", 11:"未", 
}

# 悪魔干支
eto13_dict = {
    0:"妖精", 1:"河童", 2:"つちのこ", 3:"三ツ首竜", 4:"鵺（ぬえ）", 5:"一角獣", 6:"モグラザメ", 
    7:"化猫", 8:"蝦蟇（がま）", 9:"火の鳥", 10:"怪奇植物", 11:"人魚", 12:"夜叉", 
}

def find_eto_character(eto_dict, year):
    remainder = year % len(eto_dict)
    eto = eto_dict[remainder]
    return eto

eto10 = find_eto_character(eto10_dict, target_year_int)
eto12 = find_eto_character(eto12_dict, target_year_int)
eto13 = find_eto_character(eto13_dict, target_year_int)

if target_year_int >= 1999:
    dc = "魔暦"
    dc_year = target_year_int - 1998
else:
    dc = "魔暦前"
    dc_year = 1999 - target_year_int

print("西暦" + target_year_str + "年の干支は" + eto10 + eto12 + "です。")
print(dc + str(dc_year) + "年の悪魔干支は" + eto13 + "です。")
```
# 出力例
```shell
What year?: 2025
西暦2025年の干支は乙巳です。
魔暦27年の悪魔干支は怪奇植物です。

What year?: 1985
西暦1985年の干支は乙丑です。
魔暦前14年の悪魔干支は火の鳥です。
```

# コード解説
## モジュールのインポート
```python
import sys
```
`sys.exit()`でプログラムを終了させるときに使います。

## 処理対象の西暦年の処理
```python
target_year_str = input("What year?: ")

try:
    target_year_int = int(target_year_str)
except:
    print("The value must be an integer.")
    sys.exit()

if target_year_int <= 0:
    print("The value must be larger than 0.")
    sys.exit()
```
`input`で入力された値は数字であっても文字列として扱われます。
また、この後整数型 (int) に変換するのでこの段階では文字列 (str) であることがわかる名前の変数 `target_year_str` に処理対象の数字を代入します。

## 十干・十二支・悪魔干支の辞書を作成する
```python
# 十干
eto10_dict = {
    0:"庚", 1:"辛", 2:"壬", 3:"癸", 4:"甲",
    5:"乙", 6:"丙", 7:"丁", 8:"戊", 9:"己",
}

# 十二支
eto12_dict = {
    0:"申", 1:"酉", 2:"戌", 3:"亥", 4:"子", 5:"丑", 
    6:"寅", 7:"卯", 8:"辰", 9:"巳", 10:"午", 11:"未", 
}

# 悪魔干支
eto13_dict = {
    0:"妖精", 1:"河童", 2:"つちのこ", 3:"三ツ首竜", 4:"鵺（ぬえ）", 5:"一角獣", 6:"モグラザメ", 
    7:"化猫", 8:"蝦蟇（がま）", 9:"火の鳥", 10:"怪奇植物", 11:"人魚", 12:"夜叉", 
}
```
ここからは便宜上、十干・十二支・悪魔干支を「干支」と呼びます。
与えられた西暦年の干支は、西暦年を干支の数で割った余りをもとに特定できます。
例として、2025年の十二支を求める場合、下記のとおり2025を12で割ったときの余りを求めます。2025年も2013年も同じく余りは9であり、どちらも十二支は巳（へび）です。
```python
>>> 2025 % 12
9

>>> 2013 % 12
9
```
表にまとめるとこんな感じ。
十二支の辞書の `4:"子"` のように、keyに余りの値を、valueに干支名を設定します。
| 余り | 十干 | 十二支 | 悪魔干支 |
|:-:|:-:|:-:|:-:|
| 0  | 庚 | 申 | 妖精       |
| 1  | 辛 | 酉 | 河童       |
| 2  | 壬 | 戌 | つちのこ    |
| 3  | 癸 | 亥 | 三ツ首竜    |
| 4  | 甲 | 子 | 鵺（ぬえ）  |
| 5  | 乙 | 丑 | 一角獣     |
| 6  | 丙 | 寅 | モグラザメ  |
| 7  | 丁 | 卯 | 化猫       |
| 8  | 戊 | 辰 | 蝦蟇（がま）|
| 9  | 己 | 巳 | 火の鳥     |
| 10 | -  | 午 | 怪奇植物   |
| 11 | -  | 未 | 人魚      |
| 12 | -  | - | 夜叉       |

## 関数の作成
```python
def find_eto_character(eto_dict, year):
    remainder = year % len(eto_dict)
    eto = eto_dict[remainder]
    return eto
```
十干、十二支、悪魔干支について同じような処理をするのでまず関数を作成します。
使用する辞書 (eto_dict) と、与えられた西暦年 (year) を引数とします。
変数 `remainder` に、西暦年を辞書の要素数（つまり干支の数）で割った余りを代入します。
そして、辞書のkeyが余りの値と一致するvalueを変数 `eto` に代入し、その値を返します。
この関数は最終的に「丁」や「丑」や「人魚」といった干支名を返します。

## 関数の呼び出し
```python
eto10 = find_eto_character(eto10_dict, target_year_int)
eto12 = find_eto_character(eto12_dict, target_year_int)
eto13 = find_eto_character(eto13_dict, target_year_int)
```
十干、十二支、悪魔干支それぞれについて干支名を得ます。

## 魔暦の処理
```python
if target_year_int >= 1999:
    dc = "魔暦"
    dc_year = target_year_int - 1998
else:
    dc = "魔暦前"
    dc_year = 1999 - target_year_int
```
魔暦については[上述のリンク先](https://demon-kakka.jp/aboutDC/)を参照ください。
例として、1999年は「魔暦1年」、1998年は「魔暦前1年」と表示させたいので、1999年以降とそれより前とに条件を分けます。
| 西暦 | 魔暦 | 備考 |
|:-:|:-:|:-|
| 1997 | 魔暦前2年 (B.D.2) ||
| 1998 | 魔暦前1年 (B.D.1) | 西暦1998年までは西暦年と魔暦前年を足すと1999になる|
| 1999 | 魔暦1年 (D.C.1) | 西暦1999年からは魔暦年に1998を足すと西暦年になる|
| 2000 | 魔暦2年 (D.C.2) ||
| 2001 | 魔暦3年 (D.C.3) ||

## 出力
```python
print("西暦" + target_year_str + "年の干支は" + eto10 + eto12 + "です。")
print(dc + str(dc_year) + "年の悪魔干支は" + eto13 + "です。")
```
```shell
What year?: MMXXV
The value must be an integer.

What year?: -100
The value must be larger than 0.

What year?: 0
The value must be larger than 0.

What year?: 1
西暦1年の干支は辛酉です。
魔暦前1998年の悪魔干支は河童です。

What year?: 1998
西暦1998年の干支は戊寅です。
魔暦前1年の悪魔干支は火の鳥です。

What year?: 1999
西暦1999年の干支は己卯です。
魔暦1年の悪魔干支は怪奇植物です。

What year?: 2025
西暦2025年の干支は乙巳です。
魔暦27年の悪魔干支は怪奇植物です。
```

# 最後に
これで気になるあの人の干支を調べたり、流れで年齢をサバ読んだものの「へー、干支は？」と質問されたときなどに急ぎ調べる準備が整いました。
Wikipediaの「xxxx年」のページにはその年の干支も載っていて便利です。