じゃんけんゲーム【C言語】

じゃんけんゲーム【C言語】

C言語講座だけだと味気ないですよね。せっかく勉強したもので何ができるのかを見てもらうのも面白いかなと思ったのでいくつか簡単なものを作ってみたいと思い書き始めました。

最後に完成品のソースコードを置いておくのでコンパイルして遊んでみてください。また製作過程を載せているので、プログラミングを勉強した後にぜひ読んでみてください!

製作物の概要

じゃんけんゲームなので3種類の手がありますね。グー・チョキ・パーの3種で勝ち・負け・引き分けが決まる単純なゲームです。相手はコンピュータでランダムに手を繰り出してくる設定にしましょうか。

引き分けがずっと続くと勝負がつかない状態がずっと続くなんてことも考えられるので、今回は引き分けは引き分けという結果であいこをなくします。

勝ち・負け・引き分けの数をカウントして表示してあげると楽しそうですね(勝ちで連勝数+1、引き分けで変動なし、負けで連勝数0にするのもいいですね)。

製作過程

アイデアを出したところで早速実装していきます。まずはベースとなるファイルを作成します。

#include <stdio.h>

int main() {
  return 0;
}

お決まりの部分ですね。

まずはここにコンピュータが出す手を実装していきます。コンピュータが出す手はグー・チョキ・パーの3種類なので、乱数をとってきてmod3してあげれば良さそうです。

乱数についてはsrandとrandにtime関数を組み合わせてあげれば十分でしょう。

ここまでを実装すると以下のようになります。

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

int main() {
  srand(time(NULL));
  int cp_hand = rand() % 3;
  char hand_display[3][10] = {"グー", "チョキ", "パー"};
  printf("コンピュータの出した手は%sです\n", hand_display[cp_hand]);
  return 0;
}

これでコンピュータの方は実装できましたね。

今度はプレイヤーの方を実装していきます。簡単に実装できるscanfで作ることにします。より操作性を意識する方はkbhit関数とgetch関数を使うと面白いかもしれません。

実装してみたコードがこちらになります。

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

int main() {
  /*player input*/
  int player_hand;
  printf("じゃんけん……[0:グー、1:チョキ、2:パー]\n");
  scanf("%d", &player_hand);

  /*computer lottery*/
  srand(time(NULL));
  int cp_hand = rand() % 3;

  /*output*/
  char hand_display[3][10] = {"グー", "チョキ", "パー"};
  printf("コンピュータの出した手は%sです\n", hand_display[cp_hand]);
  printf("あなたが出した手は%sです\n",hand_display[player_hand]);
  if(player_hand == cp_hand) {
    printf("結果はあいこです!!\n");
  } else if((player_hand == 0 && cp_hand == 1) || (player_hand == 1 && cp_hand == 2) || (player_hand == 2 && cp_hand == 0)) {
    printf("結果は勝利です!!\n");
  } else if((player_hand == 0 && cp_hand == 2) || (player_hand == 1 && cp_hand == 0) || (player_hand == 2 && cp_hand == 1)) {
    printf("結果は敗北です……\n");
  } else {
    printf("不正!!試合無効!!\n");
  }
  return 0;
}

プレイヤーの部分とコンピュータの部分と表示部分をそれぞれ見やすいように整頓しつつ実装しました。ユーザーが0~2の整数値を入力してくれる前提で作っているので、あまりよくないコードを書いています。例えばプレイヤーが10と入力した場合、配列の要素数を超えたところを参照してしまうので予期しない動作が発生してしまいます。

この部分をdo-whileを使って解決したのが以下のコードになります。

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

int main() {
  /*player input*/
  int player_hand;
  do {
    printf("じゃんけん……[0:グー、1:チョキ、2:パー]\n");
    scanf("%d", &player_hand);
  } while(player_hand < 0 || 2 < player_hand);

  /*computer lottery*/
  srand(time(NULL));
  int cp_hand = rand() % 3;

  /*output*/
  char hand_display[3][10] = {"グー", "チョキ", "パー"};
  printf("コンピュータの出した手は%sです\n", hand_display[cp_hand]);
  printf("あなたが出した手は%sです\n",hand_display[player_hand]);
  if(player_hand == cp_hand) {
    printf("結果はあいこです!!\n");
  } else if((player_hand == 0 && cp_hand == 1) || (player_hand == 1 && cp_hand == 2) || (player_hand == 2 && cp_hand == 0)) {
    printf("結果は勝利です!!\n");
  } else if((player_hand == 0 && cp_hand == 2) || (player_hand == 1 && cp_hand == 0) || (player_hand == 2 && cp_hand == 1)) {
    printf("結果は敗北です……\n");
  } else {
    printf("不正!!試合無効!!\n");
  }
  return 0;
}

これでplayer_handという変数に0,1,2以外の変数が入らなくなりました。

ここまででじゃんけんの基礎ができました。ここまでのじゃんけんを関数化しておきます。ついでに勝ち・負け・引き分けの記録をする配列を作成して引数に入れておくことにしましょうか。

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

void play_game(int *);

int main() {
  /*result counter*/
  int result[3] = {0, 0, 0};
  play_game(result);
  printf("勝ち:%d 負け:%d 引き分け:%d\n", result[0], result[1], result[2]);
  return 0;
}

void play_game(int *cnt) {
  /*player input*/
  int player_hand;
  do {
    printf("じゃんけん……[0:グー、1:チョキ、2:パー]\n");
    scanf("%d", &player_hand);
  } while(player_hand < 0 || 2 < player_hand);

  /*computer lottery*/
  srand(time(NULL));
  int cp_hand = rand() % 3;

  /*output*/
  char hand_display[3][10] = {"グー", "チョキ", "パー"};
  printf("コンピュータの出した手は%sです\n", hand_display[cp_hand]);
  printf("あなたが出した手は%sです\n",hand_display[player_hand]);
  if(player_hand == cp_hand) {
    cnt[2]++;
    printf("結果はあいこです!!\n");
  } else if((player_hand == 0 && cp_hand == 1) || (player_hand == 1 && cp_hand == 2) || (player_hand == 2 && cp_hand == 0)) {
    cnt[0]++;
    printf("結果は勝利です!!\n");
  } else if((player_hand == 0 && cp_hand == 2) || (player_hand == 1 && cp_hand == 0) || (player_hand == 2 && cp_hand == 1)) {
    cnt[1]++;
    printf("結果は敗北です……\n");
  } else {
    printf("不正!!試合無効!!\n");
  }
  return;
}

勝ち・負け・引き分けの記録が作れたのでゲームを何回か連続して遊べると良い気がしますね。ゲームを続けるかをプレイヤーに選択してもらう形に変更します。1回は実行したいのでdo-whileで実装すると良さそうですね。

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

void play_game(int *);

int main() {
  /*result counter*/
  int result[3] = {0, 0, 0};

  /*play*/
  int flag_continue;
  do {
    play_game(result);
    do {
      printf("じゃんけんゲームを続けますか?[0:いいえ、1:はい]\n");
      scanf("%d", &flag_continue);
    } while(flag_continue < 0 || 1 < flag_continue);
  } while(flag_continue);

  /*result output*/
  printf("総勝ち数:%d 総負け数:%d 総引き分け数:%d\n", result[0], result[1], result[2]);
  return 0;
}

void play_game(int *cnt) {
  /*player input*/
  int player_hand;
  do {
    printf("じゃんけん……[0:グー、1:チョキ、2:パー]\n");
    scanf("%d", &player_hand);
  } while(player_hand < 0 || 2 < player_hand);

  /*computer lottery*/
  srand(time(NULL));
  int cp_hand = rand() % 3;

  /*output*/
  char hand_display[3][10] = {"グー", "チョキ", "パー"};
  printf("コンピュータの出した手は%sです\n", hand_display[cp_hand]);
  printf("あなたが出した手は%sです\n",hand_display[player_hand]);
  if(player_hand == cp_hand) {
    cnt[2]++;
    printf("結果はあいこです!!\n");
  } else if((player_hand == 0 && cp_hand == 1) || (player_hand == 1 && cp_hand == 2) || (player_hand == 2 && cp_hand == 0)) {
    cnt[0]++;
    printf("結果は勝利です!!\n");
  } else if((player_hand == 0 && cp_hand == 2) || (player_hand == 1 && cp_hand == 0) || (player_hand == 2 && cp_hand == 1)) {
    cnt[1]++;
    printf("結果は敗北です……\n");
  } else {
    printf("不正!!試合無効!!\n");
  }
  printf("勝ち:%d 負け:%d 引き分け:%d\n", cnt[0], cnt[1], cnt[2]);
  return;
}

勝ち・負け・引き分けの数は毎回表示して欲しいのでplay_game関数の中にお引っ越ししました。それとは別にゲーム終了時ににも最終結果があった方がそれらしいと思ったのでmain関数の最後にも表示する部分を置きました。

実際にプレイしてみました!何か物足りない感じがするのでゲームらしさを足してあげることにします。例えば勝ち負けあいこにスコアをつけてみるのはどうでしょうか。それに連勝のカウントがあると自己ベスト更新の喜びが生まれるかもしれませんね。

result配列の要素を増やして記録を保持すれば簡単に実装できるので追加してみます。

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

void play_game(int *);

int main() {
  /*result counter*/
  int result[6] = {0, 0, 0, 0, 0, 0}; //勝ち数, 負け数, あいこ数, 連勝数, スコア, 最大連勝数

  /*play*/
  int flag_continue;
  do {
    play_game(result);
    do {
      printf("じゃんけんゲームを続けますか?[0:いいえ、1:はい]\n");
      scanf("%d", &flag_continue);
    } while(flag_continue < 0 || 1 < flag_continue);
  } while(flag_continue);

  /*result output*/
  printf("総勝ち数:%d 総負け数:%d 総引き分け数:%d スコア:%d点 最大連勝数:%d\n", result[0], result[1], result[2], result[4], result[5]);
  return 0;
}

void play_game(int *cnt) {
  /*player input*/
  int player_hand;
  do {
    printf("じゃんけん……[0:グー、1:チョキ、2:パー]\n");
    scanf("%d", &player_hand);
  } while(player_hand < 0 || 2 < player_hand);

  /*computer lottery*/
  srand(time(NULL));
  int cp_hand = rand() % 3;

  /*output*/
  char hand_display[3][10] = {"グー", "チョキ", "パー"};
  printf("コンピュータの出した手は%sです\n", hand_display[cp_hand]);
  printf("あなたが出した手は%sです\n",hand_display[player_hand]);
  if(player_hand == cp_hand) {
    cnt[2]++;
    printf("結果はあいこです!!\n");
  } else if((player_hand == 0 && cp_hand == 1) || (player_hand == 1 && cp_hand == 2) || (player_hand == 2 && cp_hand == 0)) {
    cnt[0]++;
    cnt[3]++;
    cnt[4] += cnt[3];
    cnt[5] = (cnt[5] > cnt[3])? cnt[5] : cnt[3];
    printf("結果は勝利です!!\n");
  } else if((player_hand == 0 && cp_hand == 2) || (player_hand == 1 && cp_hand == 0) || (player_hand == 2 && cp_hand == 1)) {
    cnt[1]++;
    cnt[3] = 0;
    printf("結果は敗北です……\n");
  } else {
    printf("不正!!試合無効!!\n");
  }
  printf("勝ち:%d 負け:%d 引き分け:%d 連勝:%d スコア:%d点\n", cnt[0], cnt[1], cnt[2], cnt[3], cnt[4]);
  return;
}

これで申し訳程度のスコア制と連勝数の仕組みができました。

改良点は色々あるとは思いますが一通り作るだけならこんな感じでしょう。ゲームのレベルを調整したり、インターフェースをもう少し豪華にしたり、system(“cls”)でclsコマンドを実行して画面をクリアして最新のプレイ画面のみを表示するようにするのも良さそうですね。そもそもの操作性をよくするためにkbhit()とgetch()を使うのもいいと思います。勝負の記録をファイルに出力してセーブ機能をつけるなんてこともできそうですね。

完成コード

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

void play_game(int *);

int main() {
  /*result counter*/
  int result[6] = {0, 0, 0, 0, 0, 0}; //勝ち数, 負け数, あいこ数, 連勝数, スコア, 最大連勝数

  /*play*/
  int flag_continue;
  do {
    play_game(result);
    do {
      printf("じゃんけんゲームを続けますか?[0:いいえ、1:はい]\n");
      scanf("%d", &flag_continue);
    } while(flag_continue < 0 || 1 < flag_continue);
  } while(flag_continue);

  /*result output*/
  printf("総勝ち数:%d 総負け数:%d 総引き分け数:%d スコア:%d点 最大連勝数:%d\n", result[0], result[1], result[2], result[4], result[5]);
  return 0;
}

void play_game(int *cnt) {
  /*player input*/
  int player_hand;
  do {
    printf("じゃんけん……[0:グー、1:チョキ、2:パー]\n");
    scanf("%d", &player_hand);
  } while(player_hand < 0 || 2 < player_hand);

  /*computer lottery*/
  srand(time(NULL));
  int cp_hand = rand() % 3;

  /*output*/
  char hand_display[3][10] = {"グー", "チョキ", "パー"};
  printf("コンピュータの出した手は%sです\n", hand_display[cp_hand]);
  printf("あなたが出した手は%sです\n",hand_display[player_hand]);
  if(player_hand == cp_hand) {
    cnt[2]++;
    printf("結果はあいこです!!\n");
  } else if((player_hand == 0 && cp_hand == 1) || (player_hand == 1 && cp_hand == 2) || (player_hand == 2 && cp_hand == 0)) {
    cnt[0]++;
    cnt[3]++;
    cnt[4] += cnt[3];
    cnt[5] = (cnt[5] > cnt[3])? cnt[5] : cnt[3];
    printf("結果は勝利です!!\n");
  } else if((player_hand == 0 && cp_hand == 2) || (player_hand == 1 && cp_hand == 0) || (player_hand == 2 && cp_hand == 1)) {
    cnt[1]++;
    cnt[3] = 0;
    printf("結果は敗北です……\n");
  } else {
    printf("不正!!試合無効!!\n");
  }
  printf("勝ち:%d 負け:%d 引き分け:%d 連勝:%d スコア:%d点\n", cnt[0], cnt[1], cnt[2], cnt[3], cnt[4]);
  return;
}

C言語講座


最後まで記事を見ていただきありがとうございます。また別の記事でお会いできることを祈っております。

Print Friendly, PDF & Email

C言語カテゴリの最新記事