第21問

ジャンケンの結果を判定するプログラムを作りました。期待どおりに動作したのですが、悩みながら作ったせいか、どことなく読みづらいソースファイルになってしまいました。

どうすれば読みやすくなるか、分かりますか?
main.c
#include <stdio.h>
#include <stdlib.h>

typedef enum {
  rock, /* グー */
  Paper, /* パー */
  Scissors /* チョキ */
} Hand;

enum result {
  Won, /* 勝ち */
  Lost, /* 負け */
  draw /* 引き分け */
};

struct game {
  Hand myHand; /* 自分の手 */
  Hand your_hand; /* 相手の手 */
};

typedef struct {
  Hand wins; /* 自分が勝つときの、相手の手 */
  Hand loses; /* 自分が負けるときの、相手の手 */
} Rule;

enum result result_of(struct game game) {
  Rule rules[] = {
    [rock] = { .wins = Scissors, .loses = Paper },
    [Paper] = { .wins = rock, .loses = Scissors },
    [Scissors] = { .wins = Paper, .loses = rock }
  };

  Rule myRule = rules[game.myHand];
  if (myRule.wins == game.your_hand) { return Won; }
  if (myRule.loses == game.your_hand) { return Lost; }
  return draw;
}

void Play(struct game game) {
  switch (result_of(game)) {
    case Won:
      puts("The winner is me!");
      break;
    case Lost:
      puts("The winner is you!");
      break;
    case draw:
      puts("It's a draw.");
      break;
  }
}

int main(void) {
  Play((struct game) { .myHand = rock, .your_hand = Scissors });
  Play((struct game) { .myHand = Scissors, .your_hand = rock });
  Play((struct game) { .myHand = Paper, .your_hand = Paper });

  return EXIT_SUCCESS;
}
実行結果
The winner is me!
The winner is you!
It's a draw.
いつもより長めのソースファイルだけど、大丈夫かしら?
はい、たぶん……。
よしよし。まず、列挙型(enum)が2つあるわね。
列挙型は……あった!この2つか。
typedef enum {
  rock, /* グー */
  Paper, /* パー */
  Scissors /* チョキ */
} Hand;

enum result {
  Won, /* 勝ち */
  Lost, /* 負け */
  draw /* 引き分け */
};
1つ目はジャンケンの手が「グー」「チョキ」「パー」のどれかを、2つ目は結果が「勝ち」「負け」「引き分け」のどれかを表すものですね。
うんうん。じゃあ、構造体(struct)のほうはどう?
……これだな。
struct game {
  Hand myHand; /* 自分の手 */
  Hand your_hand; /* 相手の手 */
};
gameっていう名前で、自分と相手の手が格納されるみたいだから、ジャンケン1回分のデータを表してるんですかね。
そうね。あと、もう一つ構造体があるわね。
……うん、あるある。
typedef struct {
  Hand wins; /* 自分が勝つときの、相手の手 */
  Hand loses; /* 自分が負けるときの、相手の手 */
} Rule;
これですね。Ruleってことは、勝ち負けのルールみたいなものが入るとか……?
そうそう。result_of()の中で使われてるわね。
……あ、これか。
  Rule rules[] = {
    [rock] = { .wins = Scissors, .loses = Paper },
    [Paper] = { .wins = rock, .loses = Scissors },
    [Scissors] = { .wins = Paper, .loses = rock }
  };
  ……
この配列ですね。……あ、なるほど。「グー」は「チョキ」に勝つ、でも「パー」には負けるとかのルールが入ってますね。
そういうこと!少し長いプログラムだけれど、だいたい理解できたかしらね。
はい。あと、なんだか書き方がバラバラになってるのも分かったかも!
そうよね。そこをキレイに直す練習をしてみようっていうのが今回の問題よ。
やってみます!
直せる場所は1カ所だけではありません!