質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.02%

  • C

    3069questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C言語で上手く実行してくれないのですが…

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 162

Cat_N_Memory

score 3

前提・実現したいこと

C言語で自分の腕試しに簡易的なカードゲームを作ろうとしています。

発生している問題・エラーメッセージ

コンパイルは問題なく出来ましたが、肝心の起動が上手くいきません。
タスクマネージャー上では「起動中」なのですが、1~2分待っても何も反応がありません。

該当のソースコード

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define Cardtype 2
#define Intype 4
#define CardMax 3

typedef struct status{
    int hp;
    int cards[2][4];
    int have[5];
} Sta;

/* カードの名前を判定する */
void Namejudge(const int id){
    switch(id){
        case 10 : printf("無の剣"); break;
        case 11 : printf("緑の剣"); break;
        case 12 : printf("赤の剣"); break;
        case 13 : printf("青の剣"); break;
        case 20 : printf("無の盾"); break;
        case 21 : printf("緑の盾"); break;
        case 22 : printf("赤の盾"); break;
        case 23 : printf("青の盾"); break;
    }
}

/* カードの説明文を判定する */
void Descjudge(const int id){
    char desc[256];

    switch(id){
        case 10 : printf("相手に無属性威力4の攻撃。"); break;
        case 11 : printf("相手に木属性威力4の攻撃。"); break;
        case 12 : printf("相手に火属性威力4の攻撃。"); break;
        case 13 : printf("相手に水属性威力4の攻撃。"); break;
        case 20 : printf("全属性の攻撃を半減させる。"); break;
        case 21 : printf("水属性の攻撃を無効化、木属性の攻撃を半減させる。"); break;
        case 22 : printf("木属性の攻撃を無効化、火属性の攻撃を半減させる。"); break;
        case 23 : printf("火属性の攻撃を無効化、水属性の攻撃を半減させる。"); break;
    }
}

/* 初期化処理 */
void Initia(Sta *std){
    int r, n, m;
    int f;

    srand(time(NULL));

    std->hp = 100;

    for(f = 0; f < 5; f++){
        do{
            n = rand() % Cardtype + 1;
            m = rand() % Intype;

            if(std->cards[n - 1][m] == CardMax){
                std->have[f] = n * 10 + m;
                std->cards[n - 1][m] += 1;
            }
        } while(std->have[f] < 10);
    }

}

/* 選択処理 */
int choosecard(Sta std, Sta ene){
    int f, choice;

    printf("自分残りHP:%d", std.hp);
    printf("相手残りHP:%d", ene.hp);

    printf("手持ちカード\n");

    for(f = 0; f < 5; f++){
        printf("%d番:", f + 1);
        Namejudge(std.have[f]);
        printf(" - ");
        Descjudge(std.have[f]);
    }

    printf("カードを選択してください(1~5):");

    do{
    scanf("%d", &choice);
    if(choice < 1 || choice > 5){
        printf("\a1~5で選択してください。:");
    }
    } while(choice < 1 || choice > 5);

    return choice - 1;
}

/* ダメージ計算、演算処理、文章表示 */
void Fight(int p, int e, Sta *pla, Sta *ene){
    int pd, ed;
    int obju;

    if(pla->have[p] / 10 == 1 && ene->have[e] / 10 == 1){
        /* どちらも攻撃札の場合、単純にダメージを付与 */
        pd = 4;
        ed = 4;
        printf("互いの攻撃がぶつかり合った!\n");
    }else if(pla->have[p] / 10 == 1 && ene->have[e] / 10 == 2){
        /* こちらが攻撃札の場合、ダメージ変動するかの判定 */
        /* 無属性盾なら半減 */
        if(ene->have[e] % 10 == 0) pd = 2;
        else{
            obju = ((pla->have[p] % 10) - (ene->have[e] % 10) + 3) % 3;
            /* 1なら貫通、2なら無効、0なら半減 */
            switch(obju){
                case 0 : pd = 2; printf("こちらの攻撃は相手の盾で弱められてしまった!\n"); break;
                case 1 : pd = 4; printf("こちらの攻撃は相手の盾を貫通した!\n"); break;
                case 2 : pd = 0; printf("こちらの攻撃は相手の盾に阻まれてしまった!\n"); break;
            }
        }
        ed = 0;
    }else if(pla->have[p] / 10 == 2 && ene->have[e] / 10 == 1){
        /* 今度は逆、やることもほぼ変わらない */
        /* 無属性盾なら半減 */
        if(pla->have[p] % 10 == 0) ed = 2;
        else{
            obju = ((pla->have[p] % 10) - (ene->have[e] % 10) + 3) % 3;
            /* 1なら無効、2なら貫通、0なら半減 */
            switch(obju){
                case 0 : ed = 2; printf("こちらの盾で相手の攻撃を弱めた!\n"); break;
                case 1 : ed = 0; printf("こちらの盾は相手の攻撃を阻んだ!\n"); break;
                case 2 : ed = 4; printf("こちらの盾は相手の攻撃で破れてしまった!\n"); break;
            }
        }
        pd = 0;
    }else{
        /* どちらも防御札なので互いにダメージなし */
        pd = 0;
        ed = 0;
        printf("互いに守りあっている。\n");
    }

    pla->hp -= ed;
    ene->hp -= pd;
}

int main(void){
    Sta Pla, Ene;
    int turn, plac, enec;

    srand(time(NULL));

    Initia(&Pla);
    Initia(&Ene);

    turn = 0;

    puts("========================");
    puts("      Cards Battle      ");
    puts("========================");

    do{
        printf("---%dターン目---\n", ++turn);
        plac = choosecard(Pla, Ene);
        enec = rand() % 5;
        printf("カードオープン!\n");

        printf("あなたは「");
        Namejudge(Pla.have[plac]);
        printf("」を召喚!\n");

        printf("あいては「");
        Namejudge(Ene.have[enec]);
        printf("」を召喚!\n");

        Fight(plac, enec, &Pla, &Ene);

        if(Pla.hp <= 0 || Ene.hp <= 0) break;
    } while(1);

    return 0;
}

試したこと

どこかエラーにひっからないレベルで間違えているのかと思いましたが、まだ初めて間もないためよくわからず戸惑っています。

補足情報(言語/FW/ツール等のバージョンなど)

コンパイラはMinGWを使っています。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

Initia関数内のこの部分が非常に怪しいです。

do{
    n = rand() % Cardtype + 1;
    m = rand() % Intype;

    if(std->cards[n - 1][m] == CardMax){
        std->have[f] = n * 10 + m;
        std->cards[n - 1][m] += 1;
    }
} while(std->have[f] < 10);

std->cardsの値が初期化される前に参照されています。

ですので、if文内部が実行される保証はありません。
また、ループ内が実行されなければ、終了条件を満たす保証もありません。

ループに突入する前に適切に構造体変数を初期化する必要があるでしょう。


私ならカード周りをこういう風に実装するかな、とちょっと書いてみました。

card.h

#ifndef INCLUDED_CARD
#define INCLUDED_CARD

typedef struct {
    int id_;
    char name_[10];
    char caption_[128];
} Card;

int get_type_num_of_cards(void);
Card *get_random_card(Card *);

int get_card_id(const Card *);
const char *get_card_name(const Card *);
const char *get_card_caption(const Card *);

int print_card_info(const Card *);

#endif

card.c

#include "card.h"
#include <stdio.h>
#include <stdlib.h>

static Card cards[] = {
    {10, "無の剣", "相手に無属性威力4の攻撃。"},
    {11, "緑の剣", "相手に木属性威力4の攻撃。"},
    {12, "赤の剣", "相手に火属性威力4の攻撃。"},
    {13, "青の剣", "相手に水属性威力4の攻撃。"},
    {20, "無の盾", "全属性の攻撃を半減させる。"},
    {21, "緑の盾", "水属性の攻撃を無効化、木属性の攻撃を半減させる。"},
    {22, "赤の盾", "木属性の攻撃を無効化、火属性の攻撃を半減させる。"},
    {23, "青の盾", "火属性の攻撃を無効化、水属性の攻撃を半減させる。"}
};

int get_type_num_of_cards(void) {
    return sizeof(cards) / sizeof(cards[0]);
}
Card *get_random_card(Card *card) {
    *card = cards[
        rand() % get_type_num_of_cards()
    ];
    return card;
}

int get_card_id(const Card *card) {
    return card->id_;
}
const char *get_card_name(const Card *card) {
    return card->name_;
}
const char *get_card_caption(const Card *card) {
    return card->caption_;
}

int print_card_info(const Card *card) {
    return printf(
        "id: %d, %s\n%s\n",
        get_card_id(card),
        get_card_name(card),
        get_card_caption(card)
    );
}

割と手抜きです。実際には外部ファイルにカードの情報を置いた方がよいでしょう。
あんまり参考にならないかもしれませんが、こういう書き方もあるよ、と言うことで。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/22 15:19

    回答ありがとうございます!

    僕は本来そこのループで「選択されたカードが既に使用回数の上限に達しているか」という判断をしたかったのですが、確かにこれを見る限り「上限に達しないと処理しない」という風になっていました…
    気付いていただきありがとうございました!

    キャンセル

  • 2017/10/22 15:26 編集

    解決されたようで、お疲れ様です。

    こちらも素人なのですが、気になったので、いくつか。
    その部分は初期化処理ですので、
    for (f = 0; f < 5; f++) {
    n = rand() % Cardtype + 1;
    m = rand() % Intype;
    std->have[f] = n * 10 + m;
    }
    だけでも十分な気がします。
    また、カードの種類毎に使用回数を決めているならば、cards[2][4]で間違いないと思いますが、自身が持っている5種類のカードに対して使用回数制限があるならば、used[5]でも十分な気がします。
    (追記)同じカードを2つ持ってても意味ない場合は、既にそのカードが取得されていないか確かめる必要がありそうですね。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 91.02%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C

    3069questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。