ジャンケンゲームのサンプル

C言語編の最後に、コンソール画面で遊べるジャンケンゲームのサンプルコードを提示しておきます。

以下のソースコードをそのままコピー&ペーストでVisual Studio内のソースコードに張り付けて、ビルドするだけで実行できます。
(Visual Studioじゃなくても大丈夫なはずです)
ただしソースファイルを分割していますので、ソースコードの分割の方法に従ってソースファイルをふたつ、ヘッダファイルをひとつ作成して、それぞれ貼り付けてください。

//main.c
/*
    ジャンケンゲーム
    main.cでは主に画面表示に関わる処理を記述する
    ゲーム本体の処理はgameEngine.cに記述する
*/

#include <stdio.h>
#include "gameEngine.h"

int main()
{
    //画面表示の定義
    char *const SHAPE[] = { "グー ", "チョキ", "パー " };
    char *const EMOJI[] = {
        "(;・ω・)     | ̄皿 ̄;|",
        "(`・ω・)ノ☆   Σ ̄皿_ミ",
        "(´・ω・)   ☆d| ̄皿 ̄|"
    };
    char *const CALL[] = {
        "じゃん、けん...", "ぽん!",
        "あーいこーで...", "しょ!"
    };
    enum { CALL_NORMAL, CALL_DRAW = 2 }; //掛け声の状態

    int win = 0, lose = 0, draw = 0;
    int state = CALL_NORMAL; //掛け声

    InitGame();

    //ゲームの設定を変更する場合
    //InitParam(10, 4, 8, 3);

    //イカサマ設定を変更する場合
    //InitIkasama(6, 6);

    printf("☆- - - - - - - - - - - -☆\n");
    printf("☆- - - C言語による - - -☆\n");
    printf("☆- - ジャンケンゲーム - -☆\n");
    printf("☆ (・ω・) ☆ | ̄皿 ̄| ☆\n");
    printf("☆- - - - スタート - - - -☆\n");
    printf("\n");

    while (1)
    {
        int you, cpu, result, prize;

        printf("- - - - - - - - - - - -\n");
        printf("残りコイン: %d, 遊戯回数: %d\n", GetCredit(), win + lose + draw);
        printf("勝ち: %d回, 負け: %d回, あいこ: %d回\n\n", win, lose, draw);
        printf("%s\n", CALL[state]);
        printf("[z,1]:グー, [x,2]:チョキ, [c,3]:パー, [q,0]:ゲーム終了\n");

        you = GetInput();
        if (you <= KEY_QUIT) //終了
            break;
        if (you <= KEY_INVALID) //入力文字が不正
        {
            printf("有効なキーを入力しなおしてください。\n\n");
            continue;
        }

        cpu = GetCpu(you);
        result = Battle(you, cpu);

        printf("\n%s\n", CALL[++state]);
        printf(" YOU:%s VS  CPU:%s\n", SHAPE[you], SHAPE[cpu]);
        printf("%s\n\n", EMOJI[result]);

        prize = GetPrize(result);
        if (prize > 0)
        {
            printf("フィーバー!");
            for (int i = 0; i < prize; i++)
                printf("☆");
            printf("\nヤッピー♪: %d枚獲得!\n", prize);
            state = CALL_NORMAL;
            ++win;
        }
        else if (prize < 0)
        {
            printf("ズコー!\n");
            state = CALL_NORMAL;
            ++lose;
        }
        else
        {
            printf("(あいこ)\n");
            state = CALL_DRAW;
            ++draw;
        }

        printf("\n");
        if (GetCredit() <= 0)
        {
            printf("コインがなくなりました。\n");
            break;
        }
    }

    printf("\n- - - - - - - - - - - -\n");
    printf("\nゲーム終了。\n");
    printf("遊戯回数: %d\n", win + lose + draw);
    printf("コイン: %d\n", GetCredit());
    printf("勝ち: %d回, 負け: %d回, あいこ: %d回\n", win, lose, draw);
    printf("Enterキーで終了...");
    getchar();
}
//gameEngine.c
/*
    ジャンケンゲーム
    gameEngine.cではゲームの具体的な挙動を実装する
*/

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

enum { ROCK, SIZER, PAPER };
enum { DRAW, WIN, LOSE };

//非公開関数のプロトタイプ宣言
static int ForceWin(int x);
static int Judge(int you, int cpu);

//ゲーム設定値
static struct {
    int credit;       //コイン枚数
    int wonCredit;    //勝利時にもらえるコイン最大数
    int bonusProb;    //勝利時にボーナスがもらえる確率
    int bonusRate;    //ボーナスの倍率
    int forceWinProb; //強制的にCPUが勝つ確率
    int reBattleProb; //CPUが負けた場合に再試合する確率
} param;

//初期化処理
//ゲーム開始前に一度だけ呼び出す
void InitGame()
{
    static char isInit;
    if (isInit > 0)
        return;

    isInit = 1;
    srand((unsigned)time(NULL)); //乱数初期化
    param.credit       = 10;
    param.wonCredit    = 4;
    param.bonusProb    = 8;
    param.bonusRate    = 3;
    param.forceWinProb = 6;
    param.reBattleProb = 6;
}

//設定の調整
//任意でゲーム開始前に一度だけ呼び出す
//0以下を指定したパラメーターは変更しない
//credit: コイン初期枚数
//wonCredit: 勝利時にもらえるコイン最大数
//bonusProb: 勝利時にボーナスがもらえる確率
//bonusRate: ボーナスの倍率
void InitParam(int credit, int wonCredit, int bonusProb, int bonusRate)
{
    InitGame();
    if (credit >= 1) param.credit = credit;
    if (wonCredit >= 1) param.wonCredit = wonCredit;
    if (bonusProb >= 1) param.bonusProb = bonusProb;
    if (bonusRate >= 1) param.bonusRate = bonusRate;
}

//イカサマの設定
//任意でゲーム開始前に一度だけ呼び出す
//0未満を指定したパラメーターは変更しない
//forceWinProb: 強制的にCPUが勝つ確率(0で無効)
//reBattleProb: CPUが負けた場合に再試合する確率(0で無効)
void InitIkasama(int forceWinProb, int reBattleProb)
{
    InitGame();
    if (forceWinProb >= 0) param.forceWinProb = forceWinProb;
    if (reBattleProb >= 0) param.reBattleProb = reBattleProb;
}

//現在のコイン枚数を返す
int GetCredit()
{
    return param.credit;
}

//勝負結果を返す
//イカサマ機能が有効な場合は
//CPUが負けた場合に1/nの確率で再試合
//戻り値:
//0:あいこ,1:勝ち,2:負け
int Battle(int you, int cpu)
{
    int ret = Judge(you, cpu);
    if (ret == WIN && param.reBattleProb > 0)
        if (rand() % param.reBattleProb == 0)
        {
            cpu = GetCpu(-1);
            ret = Judge(you, cpu);
        }
    return ret;
}

//勝ち負け判定
int Judge(int you, int cpu)
{
    if (you == cpu)
        return DRAW;
    if (you == ROCK && cpu == SIZER)
        return  WIN;
    if (you == SIZER && cpu == PAPER)
        return  WIN;
    if (you == PAPER && cpu == ROCK)
        return  WIN;
    return  LOSE;
}

//コインの変動
//勝利時は1~x枚のコイン獲得
//1/yの確率でz倍獲得
//戻り値は獲得したコイン枚数
int GetPrize(int result)
{
    int get;
    switch (result)
    {
    case WIN:
        param.credit--;
        get = (rand() % param.wonCredit + 1) *
            ((rand() % param.bonusProb == 0) ?
                param.bonusRate : 1);
        break;
    case LOSE:
        get =  -1;
        break;
    default:
        get = 0;
    }
    param.credit += get;
    return get;
}

//強制的に勝つ手を返す
static int ForceWin(int x)
{
    switch (x)
    {
    case ROCK:
        return PAPER;
    case SIZER:
        return ROCK;
    default:
        return SIZER;
    }
}

//CPUの手をランダムで返す
//イカサマ機能が有効な場合は1/nの確率でCPUが勝つ
//youがマイナス値の場合はイカサマ機能を強制的に無効
int GetCpu(int you)
{
    if (you >= 0 && param.forceWinProb > 0)
        if (rand() % param.forceWinProb == 0)
            return ForceWin(you);
    return rand() % 3;
}

//キー入力を受け取る
//戻り値:
//-1:無効な文字(KEY_INVALID)
//-2:終了(KEY_QUIT)
int GetInput()
{
    int c = getchar();

    if (c == '\n')
        return KEY_INVALID;
    while (getchar() != '\n');
    if (c == 'q' || c == '0')
        return KEY_QUIT;

    switch (c)
    {
    case 'z':
    case '1':
        return ROCK;
    case 'x':
    case '2':
        return SIZER;
    case 'c':
    case '3':
        return PAPER;
    default:
        return KEY_INVALID;
    }
}
//gameEngine.h

#pragma once

//キーの定義
enum { KEY_QUIT = -2, KEY_INVALID };

//プロトタイプ宣言

//初期化処理
//ゲーム開始前に一度だけ呼び出す
void InitGame();

//設定の調整
//任意でゲーム開始前に一度だけ呼び出す
//0以下を指定したパラメーターは変更しない
//credit: コイン初期枚数
//wonCredit: 勝利時にもらえるコイン最大数
//bonusProb: 勝利時にボーナスがもらえる確率
//bonusRate: ボーナスの倍率
void InitParam(int credit, int wonCredit, int bonusProb, int bonusRate);

//イカサマの設定
//任意でゲーム開始前に一度だけ呼び出す
//0未満を指定したパラメーターは変更しない
//forceWinProb: 強制的にCPUが勝つ確率(0で無効)
//reBattleProb: CPUが負けた場合に再試合する確率(0で無効)
void InitIkasama(int forceWinProb, int reBattleProb);

//現在のコイン枚数を返す
int GetCredit();

//勝負結果を返す
//イカサマ機能が有効な場合は
//CPUが負けた場合に1/nの確率で再試合
int Battle(int you, int cpu);

//コインの変動
//勝利時は1~x枚のコイン獲得
//1/yの確率でz倍獲得
//戻り値は獲得したコイン枚数
int GetPrize(int result);

//CPUの手をランダムで返す
//イカサマ機能が有効な場合は1/nの確率でCPUが勝つ
//youがマイナス値の場合はイカサマ機能を強制的に無効
int GetCpu(int you);

//キー入力を受け取る
//戻り値:
//-1:無効な文字(KEY_INVALID)
//-2:終了(KEY_QUIT)
int GetInput();

「main.c」は画面の表示に関わる処理だけを記述します。
「gameEngine.c」は実際のゲーム処理や必要な関数群を定義したゲームエンジンです。

ファイルを分割することで、main関数側は必然的にゲームの内部動作にはタッチしない処理になります。
ファイルごとにできるだけ処理を独立させることで、バグが入り込む可能性が少なくなります。

ただジャンケンをするだけではゲーム性に乏しいので「勝利時に獲得できるコイン枚数のランダム性」と「コンピューター側のイカサマ機能」を搭載しています。

勝利時にもらえるコイン数が多いので、そのままだとコインは増える一方です。
そこで、コンピューター側が勝つ確率を上げることでバランスを取っています。

コンソールアプリケーションなので、画面はどうしても寂しくなります。
一般的なゲームのように音楽や画像などを用いてゲームらしく作るにはウィンドウアプリケーションの作り方を学ぶ必要があります。
その場合であってもゲームエンジン部分(裏で動作する部分)は、サンプルコードからほとんど変更せずに流用ができると思います。
(キー入力の受け取り処理あたりは変更が必要だと思います)