はじめに
プログラミングの考え方には、大きく分けて「手続き型プログラミング」と「オブジェクト指向プログラミング」の2つがあります。C言語は、前者の「手続き型プログラミング言語」の代表例です。
手続き型プログラミングとは、プログラムを**一連の手順(プロシージャ、手続き)**の集まりとして捉える考え方です。料理のレシピのように、「最初にこれをやり、次にこれをやり…」と、処理の流れを順番に記述していきます。
この記事では、C言語の基本的な要素だけで作れる「じゃんけんゲーム」を題材に、手続き型プログラミングの考え方と、プログラムを関数に分割して構造化するメリットを解説します。
手続き型による「じゃんけんゲーム」のサンプルコード
このプログラムは、以下の4つの主要な手続き(関数)に分割されています。
getPlayerMove()
: プレイヤーの手を入力させる。getComputerMove()
: コンピュータの手をランダムに生成する。determineWinner()
: 両者の手を比較して、勝敗を判定する。displayResult()
: 判定結果を画面に表示する。
完成コード
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// --- 定数の定義 ---
#define ROCK 0
#define SCISSORS 1
#define PAPER 2
#define RESULT_WIN 0
#define RESULT_LOSE 1
#define RESULT_DRAW 2
// --- 関数のプロトタイプ宣言 ---
int getPlayerMove();
int getComputerMove();
int determineWinner(int player, int computer);
void displayResult(int result);
// --- メインの手続き ---
int main() {
int playerMove, computerMove, gameResult;
// 乱数の初期化
srand(time(NULL));
// 1. プレイヤーの手を取得
playerMove = getPlayerMove();
// 2. コンピュータの手を取得
computerMove = getComputerMove();
// 3. 勝敗を判定
gameResult = determineWinner(playerMove, computerMove);
// 4. 結果を表示
displayResult(gameResult);
return 0;
}
// プレイヤーの手を入力させる関数
int getPlayerMove() {
int move;
printf("0:グー, 1:チョキ, 2:パー\n");
printf("あなたの手を入力してください: ");
scanf("%d", &move);
return move;
}
// コンピュータの手をランダムに生成する関数
int getComputerMove() {
int move;
move = rand() % 3; // 0, 1, 2 のいずれかの値を生成
printf("コンピュータの手: %d\n", move);
return move;
}
// 勝敗を判定する関数
int determineWinner(int player, int computer) {
if (player == computer) {
return RESULT_DRAW; // 引き分け
} else if ((player == ROCK && computer == SCISSORS) ||
(player == SCISSORS && computer == PAPER) ||
(player == PAPER && computer == ROCK)) {
return RESULT_WIN; // 勝ち
} else {
return RESULT_LOSE; // 負け
}
}
// 結果を表示する関数
void displayResult(int result) {
if (result == RESULT_WIN) {
printf("あなたの勝ちです!\n");
} else if (result == RESULT_LOSE) {
printf("あなたの負けです。\n");
} else {
printf("引き分けです。\n");
}
}
コードの解説
手続き(関数)への分割
main
関数を見ると、プログラムの全体的な流れが「手を取得 → 手を取得 → 判定 → 表示」という4つのステップであることが一目で分かります。
このように、特定の役割を持つ処理を一つの関数としてまとめるのが、手続き型プログラミングの基本です。もし、これらを全てmain
関数の中に書いてしまうと、コードが長くなり、どこで何をしているのかが分かりにくくなってしまいます。
各手続き(関数)の役割
getPlayerMove()
: ユーザーからの入力を受け付ける、という手続きに特化しています。getComputerMove()
: 乱数を生成してコンピュータの手を決める、という手続きに特化しています。determineWinner(int player, int computer)
: 2つの手(player
とcomputer
)を引数として受け取り、じゃんけんのルールに基づいて勝敗を判定する、という手続きに特化しています。displayResult(int result)
: 判定結果(result
)を引数として受け取り、対応するメッセージを表示する、という手続きに特化しています。
まとめ
今回は、「じゃんけんゲーム」を例に、C言語における手続き型プログラミングの基本的な考え方を解説しました。
- プログラムを、一連の手順(手続き)の集まりとして設計する。
- 特定の機能や役割を持つ処理を、関数として分割することで、コードの可読性と保守性を高める。
main
関数を司令塔として、そこから様々な専門家(関数)を順番に呼び出していくようなイメージです。この「処理の分割」という考え方は、あらゆるプログラミングスタイルの基本となる、非常に重要な概念です。