主要优化细节

1.安全性:通过简单哈希函数处理密码,避免明文存储(实际项目可替换为 MD5/SHA 等更安全算法)

2.输入容错:所有用户输入均添加范围校验和格式校验,避免因无效输入导致程序崩溃

3.代码组织:使用GameCenter命名空间封装所有函数和变量,减少全局作用域污染

4.随机数优化:srand仅在main中初始化一次,保证随机数序列的随机性

用户体验:

增加游戏标题和分隔线,界面更清晰

输入提示更友好,错误信息明确

登录 / 注册支持多次重试,无需重启程序

健壮性:

文件操作增加打开失败判断

使用constexpr定义常量(如棋盘大小),便于维护

提取公共输入验证函数input_int,减少重复代码

</p>
/*
开发者:故渊(才译翔)
协助开发:(想成为者@才译翔,UID:2430)
*/
#include <iostream>
#include <fstream>
#include <map>
#include <cstdlib>
#include <ctime>
#include <string>
#include <limits>
#include <vector>
#include <utility>
#include <functional> // 用于std::hash
using namespace std;

// 命名空间封装,减少全局变量污染
namespace GameCenter {
	// 存储用户名、盐值和哈希后的密码(用户名 -> (盐值, 哈希密码))
	map<string, pair<string, string>> users; 
	constexpr int GOMOKU_SIZE = 15; // 五子棋棋盘大小
	char gomoku_board[GOMOKU_SIZE][GOMOKU_SIZE];
	
	// 生成随机盐值(增强哈希安全性)
	string generate_salt() {
		const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()";
		string salt;
		for (int i = 0; i < 16; ++i) { // 16位随机盐值
			salt += chars[rand() % chars.size()];
		}
		return salt;
	}
	
	// 增强的哈希函数(盐值+多次哈希)
	string hash_password(const string& pass, const string& salt) {
		string input = salt + pass; // 盐值拼接密码
		size_t hash_result = 0;
		
		// 多次哈希迭代,增加破解难度
		for (int i = 0; i < 10000; ++i) {
			hash_result ^= hash<string>{}(input + to_string(i) + to_string(hash_result));
		}
		
		return to_string(hash_result);
	}
	
	// 加载用户数据(适配新的存储格式)
	void load_users() {
		users.clear(); // 确保先清空现有数据
		ifstream fin("users.txt");
		if (!fin.is_open()) {
			// 首次运行无文件属于正常情况,不报错
			return;
		}
		
		string username, salt, hashed_pass;
		while (fin >> username >> salt >> hashed_pass) {
			users[username] = {salt, hashed_pass};
		}
		fin.close();
	}
	
	// 保存用户数据(适配新的存储格式)
	bool save_users() {
		ofstream fout("users.txt");
		if (!fout.is_open()) {
			cerr << "错误:无法打开用户数据文件进行写入!" << endl;
			return false;
		}
		
		for (const auto& p : users) {
			fout << p.first << " " << p.second.first << " " << p.second.second << endl;
		}
		fout.close();
		return true;
	}
	
	// 输入整数验证
	int input_int(const string& prompt, int min_val, int max_val) {
		int num;
		while (true) {
			cout << prompt;
			cin >> num;
			
			if (cin.good() && num >= min_val && num <= max_val) {
				// 清除输入缓冲区
				cin.ignore(numeric_limits<streamsize>::max(), '\n');
				return num;
			} else {
				cin.clear(); // 清除错误状态
				cin.ignore(numeric_limits<streamsize>::max(), '\n');
				cout << "输入无效,请输入" << min_val << "到" << max_val << "之间的数字!" << endl;
			}
		}
	}
	
	// 猜数字游戏
	void guess_number() {
		int secret = rand() % 100 + 1;
		int guess, cnt = 0;
		cout << "\n===== 猜数字游戏 =====" << endl;
		cout << "系统已生成1~100的随机数,开始猜测吧!" << endl;
		
		while (true) {
			guess = input_int("请输入你的猜测:", 1, 100);
			cnt++;
			if (guess == secret) {
				cout << "恭喜猜对了!共猜了" << cnt << "次!" << endl;
				break;
			} else if (guess < secret) {
				cout << "猜小了哦~" << endl;
			} else {
				cout << "猜大了哦~" << endl;
			}
		}
	}
	
	// 石头剪刀布游戏
	void rock_paper_scissors() {
		const string choice[3] = {"石头", "剪刀", "布"};
		int user_choice = input_int(
									"\n===== 石头剪刀布 =====" 
									"\n0-石头  1-剪刀  2-布" 
									"\n请选择:", 0, 2);
		
		int computer_choice = rand() % 3;
		cout << "你出:" << choice[user_choice] << endl;
		cout << "电脑出:" << choice[computer_choice] << endl;
		
		if (user_choice == computer_choice) {
			cout << "平局!" << endl;
		} else if ((user_choice == 0 && computer_choice == 1) || 
				   (user_choice == 1 && computer_choice == 2) || 
				   (user_choice == 2 && computer_choice == 0)) {
			cout << "你赢了!" << endl;
		} else {
			cout << "你输了!" << endl;
		}
	}
	
	// 计算器
	void calculator() {
		double a, b;
		char op;
		cout << "\n===== 简易计算器 =====" << endl;
		cout << "请输入表达式(格式:数字 运算符 数字,如 2 + 3):";
		
		// 处理输入格式错误
		while (!(cin >> a >> op >> b)) {
			cin.clear();
			cin.ignore(numeric_limits<streamsize>::max(), '\n');
			cout << "输入格式错误,请重新输入(如 2 + 3):";
		}
		
		switch (op) {
			case '+': cout << "结果:" << a + b << endl; break;
			case '-': cout << "结果:" << a - b << endl; break;
			case '*': cout << "结果:" << a * b << endl; break;
			case '/': 
			if (b == 0) {
				cout << "错误:除数不能为0!" << endl;
			} else {
				cout << "结果:" << a / b << endl;
			}
			break;
			default: cout << "错误:不支持的运算符!" << endl;
		}
	}
	
	// 五子棋工具函数:打印棋盘
	void print_gomoku_board() {
		cout << "   ";
		for (int i = 0; i < GOMOKU_SIZE; ++i) {
			cout << (i < 10 ? " " : "") << i << " ";
		}
		cout << endl;
		for (int i = 0; i < GOMOKU_SIZE; ++i) {
			cout << (i < 10 ? " " : "") << i << " ";
			for (int j = 0; j < GOMOKU_SIZE; ++j) {
				cout << (gomoku_board[i][j] == 0 ? ".  " : string(1, gomoku_board[i][j]) + "  ");
			}
			cout << endl;
		}
	}
	
	// 五子棋工具函数:检查获胜
	bool check_gomoku_win(int x, int y, char c) {
		// 四个方向:横、竖、斜下、斜上
		const int dx[] = {1, 0, 1, 1};
		const int dy[] = {0, 1, 1, -1};
		
		for (int d = 0; d < 4; ++d) {
			int count = 1;
			// 正方向检查
			for (int k = 1; k < 5; ++k) {
				int nx = x + dx[d] * k;
				int ny = y + dy[d] * k;
				if (nx < 0 || nx >= GOMOKU_SIZE || ny < 0 || ny >= GOMOKU_SIZE) break;
				if (gomoku_board[nx][ny] == c) count++;
				else break;
			}
			// 反方向检查
			for (int k = 1; k < 5; ++k) {
				int nx = x - dx[d] * k;
				int ny = y - dy[d] * k;
				if (nx < 0 || nx >= GOMOKU_SIZE || ny < 0 || ny >= GOMOKU_SIZE) break;
				if (gomoku_board[nx][ny] == c) count++;
				else break;
			}
			if (count >= 5) return true;
		}
		return false;
	}
	
	// 五子棋工具函数:初始化棋盘
	void init_gomoku_board() {
		for (int i = 0; i < GOMOKU_SIZE; ++i) {
			for (int j = 0; j < GOMOKU_SIZE; ++j) {
				gomoku_board[i][j] = 0;
			}
		}
	}
	
	// 五子棋-双人对战
	void gomoku_pvp() {
		init_gomoku_board();
		cout << "\n===== 五子棋-双人对战 =====" << endl;
		cout << "玩家1使用 X,玩家2使用 O,先连成5子获胜!" << endl;
		int turn = 0; // 0-玩家1,1-玩家2
		
		while (true) {
			print_gomoku_board();
			char current_player = (turn % 2 == 0) ? 'X' : 'O';
			int x = input_int("玩家" + to_string(turn % 2 + 1) + "(" + current_player + ")请输入行坐标:", 0, GOMOKU_SIZE - 1);
			int y = input_int("玩家" + to_string(turn % 2 + 1) + "(" + current_player + ")请输入列坐标:", 0, GOMOKU_SIZE - 1);
			
			if (gomoku_board[x][y] != 0) {
				cout << "该位置已落子,请重新选择!" << endl;
				continue;
			}
			
			gomoku_board[x][y] = current_player;
			if (check_gomoku_win(x, y, current_player)) {
				print_gomoku_board();
				cout << "恭喜玩家" << (turn % 2 + 1) << "获胜!" << endl;
				break;
			}
			
			turn++;
			if (turn == GOMOKU_SIZE * GOMOKU_SIZE) {
				print_gomoku_board();
				cout << "棋盘已满,平局!" << endl;
				break;
			}
		}
	}
	
	// 五子棋AI评估函数
	int evaluate_line(int x, int y, int dx, int dy, char c, char opponent) {
		int count = 1; // 当前位置已有一个子
		int empty_ends = 0; // 两端的空位数
		
		// 正向检查
		for (int i = 1; i <= 4; ++i) {
			int nx = x + dx * i;
			int ny = y + dy * i;
			if (nx < 0 || nx >= GOMOKU_SIZE || ny < 0 || ny >= GOMOKU_SIZE) break;
			if (gomoku_board[nx][ny] == c) count++;
			else if (gomoku_board[nx][ny] == 0) { empty_ends++; break; }
			else break; // 被对方棋子阻挡
		}
		
		// 反向检查
		for (int i = 1; i <= 4; ++i) {
			int nx = x - dx * i;
			int ny = y - dy * i;
			if (nx < 0 || nx >= GOMOKU_SIZE || ny < 0 || ny >= GOMOKU_SIZE) break;
			if (gomoku_board[nx][ny] == c) count++;
			else if (gomoku_board[nx][ny] == 0) { empty_ends++; break; }
			else break; // 被对方棋子阻挡
		}
		
		// 根据连子数量和活度评分
		if (count >= 5) return 100000; // 五子连珠(必胜)
		else if (count == 4 && empty_ends >= 1) return 10000; // 冲四
		else if (count == 3 && empty_ends == 2) return 1000; // 活三
		else if (count == 3 && empty_ends == 1) return 500; // 冲三
		else if (count == 2 && empty_ends == 2) return 100; // 活二
		else if (count == 2 && empty_ends == 1) return 50; // 冲二
		return 0;
	}
	
	// 评估位置得分
	int evaluate_position(int x, int y, char c) {
		if (gomoku_board[x][y] != 0) return -1; // 非空位不得分
		char opponent = (c == 'X') ? 'O' : 'X';
		int score = 0;
		int dirs[4][2] = {{1,0}, {0,1}, {1,1}, {1,-1}}; // 四个方向
		
		for (auto &d : dirs) {
			score += evaluate_line(x, y, d[0], d[1], c, opponent);
		}
		return score;
	}
	
	// 找到AI最佳落子位置
	pair<int, int> find_best_move() {
		int max_score = -1;
		vector<pair<int, int>> candidates;
		
		// 遍历所有空位评估得分
		for (int i = 0; i < GOMOKU_SIZE; ++i) {
			for (int j = 0; j < GOMOKU_SIZE; ++j) {
				if (gomoku_board[i][j] == 0) {
					// 计算AI落子得分和玩家威胁得分(需要阻挡)
					int ai_score = evaluate_position(i, j, 'O');
					int player_score = evaluate_position(i, j, 'X');
					int total = ai_score + player_score * 0.9; // 稍微优先阻挡
					
					if (total > max_score) {
						max_score = total;
						candidates.clear();
						candidates.emplace_back(i, j);
					} else if (total == max_score) {
						candidates.emplace_back(i, j);
					}
				}
			}
		}
		
		// 从最佳候选中随机选择
		int idx = rand() % candidates.size();
		return candidates[idx];
	}
	
	// 五子棋-AI对战
	void gomoku_ai() {
		init_gomoku_board();
		cout << "\n===== 五子棋-AI对战 =====" << endl;
		cout << "你使用 X,AI使用 O,先连成5子获胜!" << endl;
		int turn = 0; // 0-玩家,1-AI
		
		while (true) {
			print_gomoku_board();
			if (turn % 2 == 0) { // 玩家回合
				int x = input_int("请输入行坐标:", 0, GOMOKU_SIZE - 1);
				int y = input_int("请输入列坐标:", 0, GOMOKU_SIZE - 1);
				
				if (gomoku_board[x][y] != 0) {
					cout << "该位置已落子,请重新选择!" << endl;
					continue;
				}
				
				gomoku_board[x][y] = 'X';
				if (check_gomoku_win(x, y, 'X')) {
					print_gomoku_board();
					cout << "恭喜你获胜!" << endl;
					break;
				}
			} else { // AI回合
				auto [ai_x, ai_y] = find_best_move();
				gomoku_board[ai_x][ai_y] = 'O';
				cout << "AI落子:行" << ai_x << " 列" << ai_y << endl;
				if (check_gomoku_win(ai_x, ai_y, 'O')) {
					print_gomoku_board();
					cout << "AI获胜!再接再厉!" << endl;
					break;
				}
			}
			
			turn++;
			if (turn == GOMOKU_SIZE * GOMOKU_SIZE) {
				print_gomoku_board();
				cout << "棋盘已满,平局!" << endl;
				break;
			}
		}
	}
	
	// 游戏菜单
	void game_menu() {
		while (true) {
			cout << "\n===== 游戏菜单 =====" << endl;
			int sel = input_int(
								"1. 猜数字\n"
								"2. 石头剪刀布\n"
								"3. 计算器\n"
								"4. 五子棋-双人\n"
								"5. 五子棋-AI\n"
								"6. 退出\n"
								"请选择:", 1, 6);
			
			switch (sel) {
				case 1: guess_number(); break;
				case 2: rock_paper_scissors(); break;
				case 3: calculator(); break;
				case 4: gomoku_pvp(); break;
				case 5: gomoku_ai(); break;
				case 6: 
				cout << "感谢游玩,再见!" << endl;
				return;
			}
		}
	}
	
	// 用户注册登录流程(适配新的哈希方式)
	void user_auth() {
		load_users(); // 确保先加载用户数据
		bool logged_in = false;
		
		while (!logged_in) {
			cout << "\n===== 用户中心 =====" << endl;
			int choice = input_int("1. 注册\n2. 登录\n请选择:", 1, 2);
			
			string username, password;
			if (choice == 1) { // 注册
				cout << "请输入用户名:";
				cin >> username;
				// 清除输入缓冲区,防止后续输入问题
				cin.ignore(numeric_limits<streamsize>::max(), '\n');
				
				if (users.find(username) != users.end()) {
					cout << "用户名已存在!" << endl;
					continue;
				}
				
				cout << "请输入密码:";
				cin >> password;
				
				// 生成盐值并计算哈希
				string salt = generate_salt();
				string hashed_pass = hash_password(password, salt);
				users[username] = {salt, hashed_pass};
				
				if (save_users()) {
					cout << "注册成功!即将进入游戏菜单~" << endl;
					logged_in = true;
				} else {
					cout << "注册失败,请重试!" << endl;
					// 移除未保存成功的用户
					users.erase(username);
				}
			} else { // 登录
				cout << "请输入用户名:";
				cin >> username;
				// 清除输入缓冲区
				cin.ignore(numeric_limits<streamsize>::max(), '\n');
				
				cout << "请输入密码:";
				cin >> password;
				
				// 验证密码(使用存储的盐值重新计算哈希)
				auto it = users.find(username);
				if (it != users.end()) {
					string salt = it->second.first;
					string input_hash = hash_password(password, salt);
					if (input_hash == it->second.second) {
						cout << "登录成功!即将进入游戏菜单~" << endl;
						logged_in = true;
					} else {
						cout << "用户名或密码错误,请重试!" << endl;
					}
				} else {
					cout << "用户名或密码错误,请重试!" << endl;
				}
			}
		}
		
		game_menu();
	}
}

int main() {
	// 初始化随机数(用于盐值生成和游戏随机逻辑)
	srand((unsigned)time(0));
	
	// 版权信息
	cout << "开发者:故渊(才译翔)\n";
	cout << "协助开发:(想成为者@才译翔,UID:2430)\n";
	cout << "协助开发者:曹莫凡,UID:1619\n\n";
	
	// 启动用户认证和游戏流程
	GameCenter::user_auth();
	
	return 0;
}

5 条评论

  • 1

信息

ID
116
时间
1000ms
内存
256MiB
难度
8
标签
递交数
56
已通过
9
上传者