ポケモンのタイプ相性プログラムをC言語で作ってみた

#はじめに
　全国のポケモントレーナーの皆さん、ポケモンのタイプ相性って覚えるのって大変ですよね？なんたってタイプに関しては18種類もあるし挙句の果てに複合タイプなんていうのもいます。私もポケモン好きですがすべては覚えていません。なので作っちゃいました！

#タイプ相性プログラムについて
　このプログラムはタイプを入力することで自動で相性の良さ悪さをタイプごとに表示してくれるプログラムです。複合タイプにも対応できるように作りました。自分なりに構造が単純で分かりやすいように作りました。インターネットに頼らずに作ったので完成度にあまり突っ込むのはやめていただきたいです...早速ソースコードをどうぞ！

```c
#include <stdio.h>

int main(void) {
    //タイプの呼称
    //無->ノーマル,炎->ほのお,水->みず,草->くさ,電->でんき,氷->こおり,闘->かくとう,毒->どく,地->じめん,
    //飛->ひこう,超->エスパー,虫->むし,岩->いわ,霊->ゴースト,竜->ドラゴン,悪->あく,鋼->はがね,妖->フェアリー
    char type[18][5] = {"無", "炎", "水", "草", "電", "氷", "闘", "毒", "地",
                        "飛", "超", "虫", "岩", "霊", "竜", "悪", "鋼", "妖"};
    int typen[18];  //タイプナンバー
    int n = 0;  //タイプ名のナンバー
    int r = 0;  //タイプ数

    for (int i = 0; i < 18; i++) {
        typen[i] = 0;   //初期値0
    }

    do {
        printf("タイプの数を教えてください(最高2つまで):");
        scanf("%d", &r);
        if (r != 1 && r != 2) {
            printf("タイプは1つもしくは2つまでしか入力できません!\n");
        }
    } while (r != 1 && r != 2);

    //単体タイプ
    if (r == 1) {
        do {
            printf(
                "タイプを入力してください。\n無:0 炎:1 水:2 \n草:3 電:4 氷:5 "
                "\n闘:6 毒:7 地:8\n飛:9 超:10 虫:11\n岩:12 霊:13 竜:14\n悪:15 "
                "鋼:16 妖:17\nnumber:");
            scanf("%d", &n);
            /*
            タイプ相性（防御側）
            --  2倍弱点
            ++  1/2耐性
            10  効果なし
            */
            switch(n){
                //無
                case 0 : {typen[6]--; typen[13] = 10;} break;
                //炎
                case 1 : {typen[1]++; typen[2]--; typen[3]++; typen[5]++; typen[8]--; typen[11]++; typen[12]--; typen[16]++; typen[17]++;} break;
                //水
                case 2 : {typen[1]++; typen[2]++; typen[3]--; typen[4]--; typen[5]++; typen[16]++;} break;
                //草
                case 3 : {typen[1]--; typen[2]++; typen[3]++; typen[4]++; typen[5]--; typen[7]--; typen[8]++; typen[9]--; typen[11]--;} break;
                //電
                case 4 : {typen[4]++; typen[8]--; typen[9]++; typen[16]++;} break;
                //氷
                case 5 : {typen[1]--; typen[5]++; typen[7]--; typen[12]--; typen[16]--;} break;
                //闘
                case 6 : {typen[9]--; typen[10]--; typen[11]++; typen[12]++; typen[15]++; typen[17]--;} break;
                //毒
                case 7 : {typen[3]++; typen[6]++; typen[7]++; typen[8]--; typen[10]--; typen[11]++; typen[17]++;} break;
                //地
                case 8 : {typen[2]--; typen[3]--; typen[4] = 10; typen[5]--; typen[7]++; typen[12]++;} break;
                //飛
                case 9 : {typen[3]++; typen[4]--; typen[5]--; typen[6]++; typen[8] = 10; typen[11]++; typen[12]--;} break;
                //超
                case 10 : {typen[6]++; typen[10]++; typen[11]--; typen[13]--; typen[15]--;} break;
                //虫
                case 11 : {typen[1]--; typen[3]++; typen[6]++; typen[8]++; typen[9]--; typen[12]--; typen[17]++;} break;
                //岩
                case 12 : {typen[0]++; typen[1]++; typen[2]--; typen[3]--; typen[6]--; typen[7]++; typen[8]--; typen[9]++; typen[16]--;} break;
                //霊
                case 13 : {typen[0] = 10; typen[6] = 10; typen[7]++; typen[11]++; typen[13]--; typen[15]--;} break;
                //竜
                case 14 : {typen[1]++; typen[2]++; typen[3]++; typen[4]++; typen[5]--; typen[14]--; typen[17]--;} break;
                //悪
                case 15 : {typen[6]--; typen[10] = 10; typen[11]--; typen[13]++; typen[15]++; typen[17]--;} break;
                //鋼
                case 16 : {typen[0]++; typen[1]--; typen[3]++; typen[5]++; typen[6]--; typen[7] = 10; typen[8]--; typen[9]++; typen[10]++; typen[11]++; typen[12]++; typen[14]++; typen[16]++; typen[17]++;} break;
                //妖
                case 17 : {typen[6]++; typen[7]--; typen[11]++; typen[14] = 10; typen[15]++; typen[16]--;} break;
                //該当タイプなし
                default : {printf("正確なタイプを入力してください!\n");}
            }   
        } while (n > 17 || n < 0);
    }

    //複合タイプ
    if (r == 2) {
        for (int m = 0; m < 2; m++) {
            do {
                printf(
                    "タイプを入力してください。\n無:0 炎:1 水:2 \n草:3 電:4 "
                    "氷:5 \n闘:6 毒:7 地:8\n飛:9 超:10 虫:11\n岩:12 霊:13 "
                    "竜:14\n悪:15 鋼:16 妖:17\nnumber:");
                scanf("%d", &n);
                /*
                タイプ相性（防御側）
                --  2倍弱点
                ++  1/2耐性
                10  効果なし
                */
                switch(n){
                    //無
                    case 0 : {typen[6]--; typen[13] = 10;} break;
                    //炎
                    case 1 : {typen[1]++; typen[2]--; typen[3]++; typen[5]++; typen[8]--; typen[11]++; typen[12]--; typen[16]++; typen[17]++;} break;
                    //水
                    case 2 : {typen[1]++; typen[2]++; typen[3]--; typen[4]--; typen[5]++; typen[16]++;} break;
                    //草
                    case 3 : {typen[1]--; typen[2]++; typen[3]++; typen[4]++; typen[5]--; typen[7]--; typen[8]++; typen[9]--; typen[11]--;} break;
                    //電
                    case 4 : {typen[4]++; typen[8]--; typen[9]++; typen[16]++;} break;
                    //氷
                    case 5 : {typen[1]--; typen[5]++; typen[7]--; typen[12]--; typen[16]--;} break;
                    //闘
                    case 6 : {typen[9]--; typen[10]--; typen[11]++; typen[12]++; typen[15]++; typen[17]--;} break;
                    //毒
                    case 7 : {typen[3]++; typen[6]++; typen[7]++; typen[8]--; typen[10]--; typen[11]++; typen[17]++;} break;
                    //地
                    case 8 : {typen[2]--; typen[3]--; typen[4] = 10; typen[5]--; typen[7]++; typen[12]++;} break;
                    //飛
                    case 9 : {typen[3]++; typen[4]--; typen[5]--; typen[6]++; typen[8] = 10; typen[11]++; typen[12]--;} break;
                    //超
                    case 10 : {typen[6]++; typen[10]++; typen[11]--; typen[13]--; typen[15]--;} break;
                    //虫
                    case 11 : {typen[1]--; typen[3]++; typen[6]++; typen[8]++; typen[9]--; typen[12]--; typen[17]++;} break;
                    //岩
                    case 12 : {typen[0]++; typen[1]++; typen[2]--; typen[3]--; typen[6]--; typen[7]++; typen[8]--; typen[9]++; typen[16]--;} break;
                    //霊
                    case 13 : {typen[0] = 10; typen[6] = 10; typen[7]++; typen[11]++; typen[13]--; typen[15]--;} break;
                    //竜
                    case 14 : {typen[1]++; typen[2]++; typen[3]++; typen[4]++; typen[5]--; typen[14]--; typen[17]--;} break;
                    //悪
                    case 15 : {typen[6]--; typen[10] = 10; typen[11]--; typen[13]++; typen[15]++; typen[17]--;} break;
                    //鋼
                    case 16 : {typen[0]++; typen[1]--; typen[3]++; typen[5]++; typen[6]--; typen[7] = 10; typen[8]--; typen[9]++; typen[10]++; typen[11]++; typen[12]++; typen[14]++; typen[16]++; typen[17]++;} break;
                    //妖
                    case 17 : {typen[6]++; typen[7]--; typen[11]++; typen[14] = 10; typen[15]++; typen[16]--;} break;
                    //該当タイプなし
                    default : {printf("正確なタイプを入力してください!\n");}
                }
            } while (n > 17 || n < 0);
        }
    }

    //タイプ相性
    for (int p = 0; p < 18; p++) {
        if (typen[p] >= 9) {
            printf("%sは効果なしです。\n", type[p]);
        }
        if (typen[p] == 2) {
            printf("%sは1/4倍耐性です。\n", type[p]);
        }
        if (typen[p] == 1) {
            printf("%sは1/2倍耐性です。\n", type[p]);
        }
        if (typen[p] == -1) {
            printf("%sは2倍弱点です。\n", type[p]);
        }
        if (typen[p] == -2) {
            printf("%sは4倍弱点です。\n", type[p]);
        }
    }
    return 0;
}
```

次はこのプログラムの実行結果です。

![code_sankou.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301733/1ed094c1-e7a0-01b2-e07f-0711f6865116.png)



言いたいことはわかります。一部とんでもないやつがいることは。これは置いといて解説行きます。

##解説
　このプログラムでは単タイプ、複合タイプどちらにも対応させています。とはいってもどちらもほとんど同じような構造になっています。特にタイプ相性の処理をつかさどるswitch文が非常にでかいものになってしまいました。しかも2か所もこれがあります。
　switch文の中身はインクリメントやデクリメントを駆使して複合タイプで弱点を打ち消しあうようなポケモンたちにも対応できるようにしています。（例：ホウオウ、ハッサム、ミカルゲetc）また、効果なしの場合は大きな値を代入することでインクリメント、デクリメントの影響を受けにくくしました。

![code_sankou.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301733/1d123274-8dc4-b2a7-cbb7-26247eb4ec48.png)

画像はホウオウの例です。（※ホウオウは4倍弱点・2倍弱点・1\2耐性・1\4耐性・効果なし全てあります。）

#おわりに
　自分の目標であった複合タイプ含めたタイプ相性プログラムを作れたので大方満足できました。しかし、反省としてはswitch文を含めた部分のプログラムは関数化してもっとすっきりしたプログラムにしたかったです。もう少し改善してより分かりやすく複雑でないプログラムを作りたいと思いました。もしこの記事を見てくださった方がいるのであれば、タイプ相性の処理を関数にするためのヒントがあれば教えていただけたら幸いです。
　最後まで読んでいただきありがとうございました。