#include <stdio.h>
// 引入标准输入输出库,用于printf、scanf等函数
#include <stdlib.h>
// 引入标准库,用于rand、srand、malloc等函数
#include <time.h>
// 引入时间库,用于time、clock等时间相关函数
#include <ctype.h>
// 引入字符处理库,用于toupper等函数
#include <math.h>
// 引入数学库,用于sin、cos、tan等数学函数
#include <string.h>
// 引入字符串处理库,用于strcpy、strcat等函数
#include <stdbool.h>
// 引入布尔类型支持,用于bool、true、false
// 游戏配置常量定义
#define EASY_ATTEMPTS 15
// 简单模式允许的最大尝试次数
#define MEDIUM_ATTEMPTS 10
// 中等模式允许的最大尝试次数
#define HARD_ATTEMPTS 5
// 困难模式允许的最大尝试次数
#define EASY_RANGE 50
// 简单模式的数字范围(1-50)
#define MEDIUM_RANGE 100
// 中等模式的数字范围(1-100)
#define HARD_RANGE 200
// 困难模式的数字范围(1-200)
#define TIME_LIMIT_EASY 60
// 简单模式的限时时间(60秒)
#define TIME_LIMIT_MEDIUM 45
// 中等模式的限时时间(45秒)
#define TIME_LIMIT_HARD 30
// 困难模式的限时时间(30秒)
#define PI 3.14159265358979323846
// 定义π的近似值,用于数学计算
// 定义游戏历史记录结构体
typedef struct {
time_t playTime; // 游戏时间戳
int difficulty; // 游戏难度(1-简单,2-中等,3-困难)
int attempts; // 实际尝试次数
int won; // 是否获胜(1-是,0-否)
int secretNumber; // 目标数字
} GameRecord;
// 初始化游戏记录的函数
void initGameRecord(GameRecord *record, time_t playTime, int difficulty, int attempts, int won, int secretNumber) {
record->playTime = playTime; // 设置游戏时间
record->difficulty = difficulty; // 设置难度
record->attempts = attempts; // 设置尝试次数
record->won = won; // 设置胜负状态
record->secretNumber = secretNumber; // 设置目标数字
}
// 保存游戏记录到文件的函数
void saveGameRecord(const GameRecord *record) {
FILE *file = fopen("game_history.txt", "a"); // 以追加模式打开历史记录文件
if (file == NULL) { // 检查文件是否成功打开
perror("无法打开历史记录文件"); // 打印错误信息
return; // 返回
}
// 格式化写入记录到文件(时间戳,难度,尝试次数,胜负,目标数字)
fprintf(file, "%ld,%d,%d,%d,%d\n",
(long)record->playTime,
record->difficulty,
record->attempts,
record->won,
record->secretNumber);
fclose(file); // 关闭文件
}
// 定义游戏统计结构体
typedef struct {
int gamesPlayed; // 总游戏次数
int gamesWon; // 获胜次数
int bestScore; // 最佳成绩(最少尝试次数)
double averageAttempts; // 平均尝试次数
int totalAttempts; // 总尝试次数
} GameStats;
// 清除输入缓冲区的函数
void clearInputBuffer() {
while (getchar() != '\n'); // 读取并丢弃输入缓冲区中的所有字符,直到遇到换行符
}
// 显示游戏菜单的函数
void displayMenu() {
printf("\n===== 猜数字游戏 =====\n"); // 打印菜单标题
printf("1. 简单模式 (1-50, 15次机会)\n"); // 简单模式选项
printf("2. 中等模式 (1-100, 10次机会)\n"); // 中等模式选项
printf("3. 困难模式 (1-200, 5次机会)\n"); // 困难模式选项
printf("4. 游戏统计\n"); // 统计选项
printf("5. 退出游戏\n"); // 退出选项
printf("6. 数学提示模式\n"); // 数学提示模式
printf("7. 数学挑战模式\n"); // 数学挑战模式
printf("8. 限时模式\n"); // 限时模式
printf("9. 查看历史记录\n"); // 历史记录选项
printf("游戏小贴士:当你选择数学提示模式或数学挑战模式时,就相当于选择了一个盲盒,会爆出让你惊喜的彩蛋!\n"); // 游戏提示
printf("======================\n"); // 菜单分隔线
printf("请选择: "); // 提示用户输入选择
}
// 显示历史记录的函数
void displayHistory() {
FILE *file = fopen("game_history.txt", "r"); // 以只读模式打开历史记录文件
if (file == NULL) { // 检查文件是否成功打开
printf("无法打开历史记录文件。\n"); // 打印错误信息
return; // 返回
}
printf("\n=== Game History ===\n"); // 打印历史记录标题
printf("Time\t\tDifficulty\tAttempts\tWon\tNumber\n"); // 打印表头
char line[256]; // 定义行缓冲区
while (fgets(line, sizeof(line), file)) { // 逐行读取文件
time_t time; // 时间戳变量
int diff, attempts, won, number; // 其他记录字段
// 解析每行数据
if (sscanf(line, "%ld,%d,%d,%d,%d", &time, &diff, &attempts, &won, &number) == 5) {
// 打印格式化的历史记录
printf("%s\t%d\t%d\t%s\t%d\n", ctime(&time), diff, attempts, won ? "Yes" : "No", number);
}
}
fclose(file); // 关闭文件
printf("=====================\n"); // 打印分隔线
}
// 获取有效数字输入的函数
int getValidNumber(int min, int max) {
int number; // 存储用户输入的数字
while (1) { // 无限循环,直到获得有效输入
printf("请输入一个%d到%d之间的数字: ", min, max); // 提示输入范围
if (scanf("%d", &number) != 1) { // 检查输入是否为数字
clearInputBuffer(); // 清除输入缓冲区
printf("无效输入,请输入数字!\n"); // 错误提示
} else if (number < min || number > max) { // 检查数字是否在范围内
printf("数字超出范围,请重新输入!\n"); // 错误提示
} else {
clearInputBuffer(); // 清除输入缓冲区
return number; // 返回有效数字
}
}
}
// 获取有效菜单选择的函数
int getValidChoice(int min, int max) {
int choice; // 存储用户选择
while (1) { // 无限循环,直到获得有效输入
if (scanf("%d", &choice) != 1) { // 检查输入是否为数字
clearInputBuffer(); // 清除输入缓冲区
printf("无效输入,请输入数字!\n"); // 错误提示
} else if (choice < min || choice > max) { // 检查选择是否在范围内
printf("选择无效,请重新输入!\n"); // 错误提示
} else {
clearInputBuffer(); // 清除输入缓冲区
return choice; // 返回有效选择
}
}
}
// 根据猜测提供提示的函数
const char* getHint(int guess, int secret, int range) {
int difference = abs(guess - secret); // 计算猜测值与目标值的差值
float percent = (float)difference / range * 100; // 计算差值占范围的比例
if (guess == secret) { // 猜对了
return "恭喜你猜对了!";
} else if (guess < secret) { // 猜小了
if (percent < 10) return "猜小了,但非常接近!";
else if (percent < 30) return "猜小了,有点接近了。";
else return "猜小了,离得很远!";
} else { // 猜大了
if (percent < 10) return "猜大了,但非常接近!";
else if (percent < 30) return "猜大了,有点接近了。";
else return "猜大了,离得很远!";
}
}
// 更新游戏统计的函数
void updateStats(GameStats *stats, int attempts, int won) {
stats->gamesPlayed++; // 增加游戏次数
stats->totalAttempts += attempts; // 累加尝试次数
if (won) { // 如果获胜
stats->gamesWon++; // 增加获胜次数
if (attempts < stats->bestScore || stats->bestScore == 0) { // 如果是最佳成绩
stats->bestScore = attempts; // 更新最佳成绩
}
}
// 计算平均尝试次数
stats->averageAttempts = (float)stats->totalAttempts / stats->gamesPlayed;
}
// 显示游戏统计的函数
void displayStats(GameStats *stats) {
printf("\n===== 游戏统计 =====\n"); // 打印统计标题
printf("游戏次数: %d\n", stats->gamesPlayed); // 打印游戏次数
printf("胜利次数: %d\n", stats->gamesWon); // 打印获胜次数
// 计算并打印胜率
printf("胜率: %.1f%%\n", stats->gamesPlayed ? (float)stats->gamesWon / stats->gamesPlayed * 100 : 0);
printf("最佳成绩: %d次尝试\n", stats->bestScore ? stats->bestScore : -1); // 打印最佳成绩
printf("平均尝试次数: %.1f\n", stats->averageAttempts); // 打印平均尝试次数
printf("====================\n"); // 打印分隔线
}
// 生成数学提示的函数
const char* getMathHint(int secret) {
int hintType = rand() % 3; // 随机选择提示类型
switch (hintType) {
case 0: // 奇偶性提示
return secret % 2 == 0 ? "答案是偶数" : "答案是奇数";
case 1: // 3的倍数提示
return secret % 3 == 0 ? "答案是3的倍数" : "答案不是3的倍数";
case 2: // 十位数提示
if (secret >= 10) {
int tens = secret / 10;
return tens == 5 ? "答案的十位数字是5" : "答案的十位数字不是5";
} else {
return "答案是一位数";
}
default:
return "无数学提示";
}
}
// 数学挑战题的函数
void mathChallenge(int *extraAttempt) {
int angle_deg = rand() % 360; // 随机生成角度(0-359度)
double angle_rad = angle_deg * PI / 180.0; // 转换为弧度
double coefficient = (rand() % 5 + 1) * 0.5; // 随机系数(0.5-3.0)
double offset = rand() % 10 - 5; // 随机偏移量(-5到5)
int functionType = rand() % 4; // 随机选择函数类型
double result, answer; // 计算结果和用户答案
const char *functionName; // 函数名称
switch (functionType) {
case 0: // sin函数
result = coefficient * sin(angle_rad) + offset;
functionName = "sin";
break;
case 1: // cos函数
result = coefficient * cos(angle_rad) + offset;
functionName = "cos";
break;
case 2: // tan函数
result = coefficient * tan(angle_rad) + offset;
functionName = "tan";
break;
case 3: // sin×cos函数
result = coefficient * sin(angle_rad) * cos(angle_rad) + offset;
functionName = "sin×cos";
break;
}
// 打印数学题
printf("\n数学挑战: 计算 %.1f × %s(%d°) %c %.1f = ? (保留2位小数)\n",
coefficient, functionName, angle_deg,
offset >= 0 ? '+' : '-', fabs(offset));
while (1) { // 获取有效答案
if (scanf("%lf", &answer) != 1) { // 检查输入是否为数字
clearInputBuffer(); // 清除输入缓冲区
printf("无效输入,请输入数字!\n"); // 错误提示
} else {
clearInputBuffer(); // 清除输入缓冲区
break; // 退出循环
}
}
// 检查答案是否正确(允许0.01的误差)
if (fabs(answer - result) < 0.01) {
printf("回答正确!精确值为 %.2f,你获得了一次额外机会!\n", result);
(*extraAttempt)++; // 增加额外尝试次数
} else {
printf("回答错误!正确答案是 %.2f。\n", result);
}
}
// 限时模式的游戏函数
void timeLimitedGame(int min, int max, int maxAttempts, GameStats *stats, int timeLimit) {
int secretNumber = rand() % (max - min + 1) + min; // 生成随机目标数字
int attempts = 0, guess; // 初始化尝试次数和用户猜测
char playAgain; // 是否再玩一次
clock_t start, current; // 开始时间和当前时间
double elapsed; // 经过的时间
printf("\n限时模式开始!我已经想好了一个%d到%d之间的数字。\n", min, max);
printf("你有%d次机会来猜这个数字,时间限制为%d秒。\n", maxAttempts, timeLimit);
start = clock(); // 记录开始时间
do {
current = clock(); // 获取当前时间
elapsed = (double)(current - start) / CLOCKS_PER_SEC; // 计算经过的时间(秒)
// 检查是否超时
if (elapsed >= timeLimit) {
printf("\n时间到!你没有在规定时间内猜中。正确答案是%d。\n", secretNumber);
GameRecord record;
// 初始化并保存游戏记录
initGameRecord(&record, time(NULL), (max == EASY_RANGE) ? 1 : (max == MEDIUM_RANGE) ? 2 : 3, attempts, 0, secretNumber);
saveGameRecord(&record);
updateStats(stats, attempts, 0); // 更新统计
break;
}
printf("\n剩余时间: %.1f秒\n", timeLimit - elapsed); // 打印剩余时间
guess = getValidNumber(min, max); // 获取有效猜测
attempts++; // 增加尝试次数
printf("\n尝试 %d/%d: ", attempts, maxAttempts);
printf("%s\n", getHint(guess, secretNumber, max - min)); // 打印提示
// 检查是否猜中
if (guess == secretNumber) {
printf("\n太棒了!你用了%d次猜中了数字%d!\n", attempts, secretNumber);
GameRecord record;
// 初始化并保存游戏记录
initGameRecord(&record, time(NULL), (max == EASY_RANGE) ? 1 : (max == MEDIUM_RANGE) ? 2 : 3, attempts, 1, secretNumber);
saveGameRecord(&record);
updateStats(stats, attempts, 1); // 更新统计
break;
}
// 检查是否用完尝试次数
if (attempts >= maxAttempts) {
printf("\n很遗憾,你没有在%d次内猜中。正确答案是%d。\n", maxAttempts, secretNumber);
GameRecord record;
// 初始化并保存游戏记录
initGameRecord(&record, time(NULL), (max == EASY_RANGE) ? 1 : (max == MEDIUM_RANGE) ? 2 : 3, attempts, 0, secretNumber);
saveGameRecord(&record);
updateStats(stats, attempts, 0); // 更新统计
break;
}
printf("你还有%d次机会。\n", maxAttempts - attempts); // 打印剩余尝试次数
} while (1);
// 询问是否再玩一次
printf("想再玩一次吗?(Y/N): ");
scanf(" %c", &playAgain);
playAgain = toupper(playAgain); // 转换为大写
if (playAgain == 'Y') { // 如果选择再玩一次
timeLimitedGame(min, max, maxAttempts, stats, timeLimit); // 递归调用
}
}
// 数学提示模式的游戏函数
void mathHintGame(int min, int max, int maxAttempts, GameStats *stats) {
int secretNumber = rand() % (max - min + 1) + min; // 生成随机目标数字
int attempts = 0, guess; // 初始化尝试次数和用户猜测
char playAgain; // 是否再玩一次
printf("\n数学提示模式开始!我已经想好了一个%d到%d之间的数字。\n", min, max);
printf("你有%d次机会来猜这个数字。\n", maxAttempts);
do {
printf("\n可用数学提示: %s\n", getMathHint(secretNumber)); // 打印数学提示
guess = getValidNumber(min, max); // 获取有效猜测
attempts++; // 增加尝试次数
printf("\n尝试 %d/%d: ", attempts, maxAttempts);
printf("%s\n", getHint(guess, secretNumber, max - min)); // 打印提示
// 检查是否猜中
if (guess == secretNumber) {
printf("\n太棒了!你用了%d次猜中了数字%d!\n", attempts, secretNumber);
GameRecord record;
// 初始化并保存游戏记录
initGameRecord(&record, time(NULL), (max == EASY_RANGE) ? 1 : (max == MEDIUM_RANGE) ? 2 : 3, attempts, 1, secretNumber);
saveGameRecord(&record);
updateStats(stats, attempts, 1); // 更新统计
break;
}
// 检查是否用完尝试次数
if (attempts >= maxAttempts) {
printf("\n很遗憾,你没有在%d次内猜中。正确答案是%d。\n", maxAttempts, secretNumber);
GameRecord record;
// 初始化并保存游戏记录
initGameRecord(&record, time(NULL), (max == EASY_RANGE) ? 1 : (max == MEDIUM_RANGE) ? 2 : 3, attempts, 0, secretNumber);
saveGameRecord(&record);
updateStats(stats, attempts, 0); // 更新统计
break;
}
printf("你还有%d次机会。\n", maxAttempts - attempts); // 打印剩余尝试次数
} while (1);
// 询问是否再玩一次
printf("想再玩一次吗?(Y/N): ");
scanf(" %c", &playAgain);
playAgain = toupper(playAgain); // 转换为大写
if (playAgain == 'Y') { // 如果选择再玩一次
mathHintGame(min, max, maxAttempts, stats); // 递归调用
}
}
// 数学挑战模式的游戏函数
void mathChallengeGame(int min, int max, int maxAttempts, GameStats *stats) {
int secretNumber = rand() % (max - min + 1) + min; // 生成随机目标数字
int attempts = 0, guess, extraAttempt = 0; // 初始化尝试次数、用户猜测和额外尝试次数
char playAgain; // 是否再玩一次
printf("\n数学挑战模式开始!我已经想好了一个%d到%d之间的数字。\n", 1, 200);
printf("你有%d次机会来猜这个数字。\n", maxAttempts);
do {
// 随机机会进行数学挑战
if (rand() % 3 == 0) {
mathChallenge(&extraAttempt); // 进行数学挑战,可能获得额外尝试次数
}
guess = getValidNumber(1, 200); // 获取有效猜测
attempts++; // 增加尝试次数
printf("\n尝试 %d/%d: ", attempts, maxAttempts + extraAttempt);
printf("%s\n", getHint(guess, secretNumber, max - min)); // 打印提示
// 检查是否猜中
if (guess == secretNumber) {
printf("\n太棒了!你用了%d次猜中了数字%d!\n", attempts, secretNumber);
GameRecord record;
// 初始化并保存游戏记录
initGameRecord(&record, time(NULL), (max == EASY_RANGE) ? 1 : (max == MEDIUM_RANGE) ? 2 : 3, attempts, 1, secretNumber);
saveGameRecord(&record);
updateStats(stats, attempts, 1); // 更新统计
break;
}
// 检查是否用完尝试次数(包括额外尝试次数)
if (attempts >= maxAttempts + extraAttempt) {
printf("\n很遗憾,你没有在%d次内猜中。正确答案是%d。\n", maxAttempts + extraAttempt, secretNumber);
GameRecord record;
// 初始化并保存游戏记录
initGameRecord(&record, time(NULL), (max == EASY_RANGE) ? 1 : (max == MEDIUM_RANGE) ? 2 : 3, attempts, 0, secretNumber);
saveGameRecord(&record);
updateStats(stats, attempts, 0); // 更新统计
break;
}
printf("你还有%d次机会。\n", maxAttempts + extraAttempt - attempts); // 打印剩余尝试次数
} while (1);
// 询问是否再玩一次
printf("想再玩一次吗?(Y/N): ");
scanf(" %c", &playAgain);
playAgain = toupper(playAgain); // 转换为大写
if (playAgain == 'Y') { // 如果选择再玩一次
mathChallengeGame(min, max, maxAttempts, stats); // 递归调用
}
}
// 普通游戏模式的函数
void playGame(int min, int max, int maxAttempts, GameStats *stats) {
int secretNumber = rand() % (max - min + 1) + min; // 生成随机目标数字
int attempts = 0, guess; // 初始化尝试次数和用户猜测
char playAgain; // 是否再玩一次
printf("\n游戏开始!我已经想好了一个%d到%d之间的数字。\n", min, max);
printf("你有%d次机会来猜这个数字。\n", maxAttempts);
do {
guess = getValidNumber(min, max); // 获取有效猜测
attempts++; // 增加尝试次数
printf("\n尝试 %d/%d: ", attempts, maxAttempts);
printf("%s\n", getHint(guess, secretNumber, max - min)); // 打印提示
// 检查是否猜中
if (guess == secretNumber) {
printf("\n太棒了!你用了%d次猜中了数字%d!\n", attempts, secretNumber);
GameRecord record;
// 初始化并保存游戏记录
initGameRecord(&record, time(NULL), (max == EASY_RANGE) ? 1 : (max == MEDIUM_RANGE) ? 2 : 3, attempts, 1, secretNumber);
saveGameRecord(&record);
updateStats(stats, attempts, 1); // 更新统计
break;
}
// 检查是否用完尝试次数
if (attempts >= maxAttempts) {
printf("\n很遗憾,你没有在%d次内猜中。正确答案是%d。\n", maxAttempts, secretNumber);
GameRecord record;
// 初始化并保存游戏记录
initGameRecord(&record, time(NULL), (max == EASY_RANGE) ? 1 : (max == MEDIUM_RANGE) ? 2 : 3, attempts, 0, secretNumber);
saveGameRecord(&record);
updateStats(stats, attempts, 0); // 更新统计
break;
}
printf("你还有%d次机会。\n", maxAttempts - attempts); // 打印剩余尝试次数
} while (1);
// 询问是否再玩一次
printf("想再玩一次吗?(Y/N): ");
scanf(" %c", &playAgain);
playAgain = toupper(playAgain); // 转换为大写
if (playAgain == 'Y') { // 如果选择再玩一次
playGame(min, max, maxAttempts, stats); // 递归调用
}
}
// 主函数
int main() {
srand(time(NULL)); // 初始化随机数种子
GameStats stats = {0, 0, 0, 0.0, 0}; // 初始化游戏统计
int choice; // 用户选择
printf("欢迎来到猜数字游戏!\n"); // 打印欢迎信息
do {
displayMenu(); // 显示菜单
choice = getValidChoice(1, 9); // 获取有效选择
switch (choice) {
case 1: // 简单模式
playGame(1, EASY_RANGE, EASY_ATTEMPTS, &stats);
break;
case 2: // 中等模式
playGame(1, MEDIUM_RANGE, MEDIUM_ATTEMPTS, &stats);
break;
case 3: // 困难模式
playGame(1, HARD_RANGE, HARD_ATTEMPTS, &stats);
break;
case 4: // 游戏统计
displayStats(&stats);
break;
case 5: // 退出游戏
printf("\n谢谢游玩!再见!\n");
break;
case 6: // 数学提示模式
mathHintGame(1, HARD_RANGE, HARD_ATTEMPTS, &stats);
break;
case 7: // 数学挑战模式
mathChallengeGame(1, EASY_RANGE, EASY_ATTEMPTS, &stats);
break;
case 8: { // 限时模式
int difficulty;
printf("\n选择难度:\n");
printf("1. 简单 (60秒)\n");
printf("2. 中等 (45秒)\n");
printf("3. 困难 (30秒)\n");
printf("请选择: ");
difficulty = getValidChoice(1, 3); // 获取难度选择
switch (difficulty) {
case 1:
timeLimitedGame(1, EASY_RANGE, EASY_ATTEMPTS, &stats, TIME_LIMIT_EASY);
break;
case 2:
timeLimitedGame(1, MEDIUM_RANGE, MEDIUM_ATTEMPTS, &stats, TIME_LIMIT_MEDIUM);
break;
case 3:
timeLimitedGame(1, HARD_RANGE, HARD_ATTEMPTS, &stats, TIME_LIMIT_HARD);
break;
}
break;
}
case 9: // 查看历史记录
displayHistory();
break;
}
} while (choice != 5); // 如果选择不是退出,则继续循环
return 0; // 程序结束
}
解释每一行代码
最新发布