- 取石子
小游戏中心2.0
- 2025-10-4 15:12:23 @
主要优化细节
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;
}
信息
- ID
- 116
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 56
- 已通过
- 9
- 上传者