文章目录
-
- 概要
- 整体架构流程
- 技术名词解释
- 小结
1. 概要
~ Jack Qiao对米粒说:“前面咱们了解过“文件组织”,让我们利用“文件组织”来制作一个有趣的“石头、剪刀、布”小游戏。”举个栗子:
> 程序随机生成一个选择(石头、剪刀、布)。
> 用户输入自己的选择。
> 程序比较用户的选择和计算机的选择,决定胜负。
> 输出比赛结果。
~ 米粒思考后,将这个游戏分为3个部分:
> 头文件 rps.h:声明游戏相关的函数。
> 源文件 rps.c:实现游戏相关的函数。
> 主程序 main.c:调用游戏函数并运行游戏。
2. 整体架构流程
2.1. 头文件
#ifndef RPS_GAME_H #define RPS_GAME_H void play_rps(); #endif // RPS_GAME_H
> 声明了 play_rps 函数,以便在其他文件中调用。
2.2. 源文件
#include <stdio.h> #include <stdlib.h> #include <time.h> #include "rps_game.h" // 定义游戏选项 enum Choice { ROCK, PAPER, SCISSORS }; // 获取用户输入 int get_user_choice() { int choice; printf("请选择:1. 石头 2. 剪刀 3. 布\n"); int result = scanf("%d", &choice); // 检查 scanf 是否成功读取一个整数 if (result != 1) { printf("输入错误,请重新输入。\n"); // 清除输入缓冲区 while (getchar() != '\n'); return get_user_choice(); // 递归调用,重新获取输入 } while (choice < 1 || choice > 3) { printf("无效输入,请重新选择:1. 石头 2. 剪刀 3. 布\n"); result = scanf("%d", &choice); if (result != 1) { printf("输入错误,请重新输入。\n"); // 清除输入缓冲区 while (getchar() != '\n'); return get_user_choice(); // 递归调用,重新获取输入 } } return choice - 1; // 转换为0, 1, 2 } // 获取计算机选择 int get_computer_choice() { return rand() % 3; } // 判断胜负 char* determine_winner(int user_choice, int computer_choice) { if (user_choice == computer_choice) { return "平局"; } else if ((user_choice == ROCK && computer_choice == SCISSORS) || (user_choice == PAPER && computer_choice == ROCK) || (user_choice == SCISSORS && computer_choice == PAPER)) { return "你赢了"; } else { return "你输了"; } } // 打印选择 void print_choice(int choice) { switch (choice) { case ROCK: printf("石头"); break; case PAPER: printf("布"); break; case SCISSORS: printf("剪刀"); break; } } void play_rps() { // 初始化随机数生成器 srand(time(NULL)); int user_choice = get_user_choice(); int computer_choice = get_computer_choice(); printf("你的选择:"); print_choice(user_choice); printf("\n计算机的选择:"); print_choice(computer_choice); printf("\n"); char* result = determine_winner(user_choice, computer_choice); printf("%s\n", result); }
> 实现了 play_rps 函数,包含了游戏的主要逻辑,包括获取用户和计算机的选择、判断胜负和打印结果。
2.2.1. 定义游戏选项
enum Choice { ROCK, PAPER, SCISSORS };
> 这里枚举类型 (enum)
- 知识点:枚举类型 (enum) 是一种用户自定义的数据类型,用于定义一组命名的整数常量。在本程序中,ROCK、PAPER 和 SCISSORS 分别对应整数值 0、1 和 2。
- 作用:使用枚举类型可以使代码更具可读性和可维护性,避免使用魔法数字(如 0、1、2),使代码更清晰。
2.2.2. 输入验证和错误处理
int get_user_choice() { int choice; printf("请选择:1. 石头 2. 剪刀 3. 布\n"); int result = scanf("%d", &choice); if (result != 1) { printf("输入错误,请重新输入。\n"); while (getchar() != '\n'); return get_user_choice(); } while (choice < 1 || choice > 3) { printf("无效输入,请重新选择:1. 石头 2. 剪刀 3. 布\n"); result = scanf("%d", &choice); if (result != 1) { printf("输入错误,请重新输入。\n"); while (getchar() != '\n'); return get_user_choice(); } } return choice - 1; }
> 输入验证和错误处理
- 知识点:输入验证和错误处理是确保程序健壮性的关键。scanf 函数的返回值用于检查是否成功读取了预期的数据类型。
- 作用:通过检查 scanf 的返回值和清除输入缓冲区,确保用户输入有效,并在输入无效时提示用户重新输入
2.2.3. 随机数生成
int get_computer_choice() { return rand() % 3; } void play_rps() { srand(time(NULL)); // ... }
> 随机数生成器
- 知识点:rand() 函数生成一个伪随机数,srand() 函数用于初始化随机数生成器。
- 作用:rand() % 3 生成一个范围在 [0, 2] 之间的随机数,模拟计算机的选择。
- 其中:srand(time(NULL)) 使用当前时间作为种子,确保每次运行程序时生成的随机数序列不同。
2.3. 主程序
#include <stdio.h> #include "rps_game.h" int main() { play_rps(); return 0; }
> 主程序 main.c:调用了 play_rps 函数,启动游戏。
2.4. 运行结果
3. 技术名词解释
这里枚举类型 (enum)
- 知识点:枚举类型 (enum) 是一种用户自定义的数据类型,用于定义一组命名的整数常量。在本程序中,ROCK、PAPER 和 SCISSORS 分别对应整数值 0、1 和 2。
- 作用:使用枚举类型可以使代码更具可读性和可维护性,避免使用魔法数字(如 0、1、2),使代码更清晰。
- 举个栗子
#include <stdio.h> enum Color { RED, GREEN, BLUE }; int main() { enum Color myColor = GREEN; if (myColor == GREEN) { printf("颜色是绿色。\n"); } return 0; }
4. 小结
~ 通过这个小游戏,米粒深刻认识到:
> “文件组织”通过将功能相关的代码分组,枚举类型定义了游戏选项,提高了代码的可读性和可维护性。
> 函数封装和条件判断实现了游戏逻辑的清晰和模块化,使得代码结构更加简洁。