如何实现记忆配对游戏中用户自定义n×n配对矩阵的生成与读写
自定义规格配对记忆游戏实现方案
没问题,我帮你把原本固定6×6的记忆配对游戏改成支持用户自定义矩阵规格的版本,同时实现自动生成成对数字矩阵、写入文件再读取的完整流程。下面是具体的实现细节和完整代码:
一、核心需求拆解
首先明确我们要实现的功能:
- 允许用户输入矩阵的行数和列数(注意:必须是偶数×偶数,因为要生成成对数字,总元素数得是偶数)
- 自动生成包含成对数字的随机矩阵,每个数字恰好出现两次
- 将生成的矩阵写入
grid.txt文件 - 修改原有游戏逻辑,适配动态规格的矩阵
二、关键修改点说明
- 动态规格校验:添加了输入校验逻辑,确保用户输入的行×列结果是偶数,否则提示重新输入
- 随机矩阵生成:先用一维数组存储所有成对数字,再用
random_shuffle打乱顺序,最后转成二维矩阵,保证每个数字刚好出现两次 - 文件读写适配:把所有硬编码的
6替换成动态的rows和cols变量,支持任意合法规格的矩阵 - 游戏输入优化:添加了用户输入的合法性检查,比如不能选已配对的单元格、不能超出矩阵范围,提升游戏体验
三、完整代码实现
#include <algorithm> #include <iostream> #include <cstdlib> #include <ctime> #include <vector> #include <fstream> #include <string> #include <numeric> #include <limits> using namespace std; // 全局变量存储矩阵规格 int rows, cols; // 游戏相关的二维向量 vector<vector<int> > game_grid; vector<vector<int> > hidden_grid; vector<vector<int> > guessed; // 生成并写入配对矩阵到文件 void generate_and_write_grid() { // 校验矩阵规格合法性(总元素数必须为偶数) while (true) { cout << "请输入矩阵的行数:"; cin >> rows; cout << "请输入矩阵的列数:"; cin >> cols; if ((rows * cols) % 2 != 0) { cout << "错误:矩阵总元素数必须是偶数,请重新输入!" << endl; } else { break; } } // 初始化随机种子,保证每次生成不同矩阵 srand(time(0)); // 创建包含成对数字的一维数组 int total_elements = rows * cols; vector<int> nums(total_elements); int num_pairs = total_elements / 2; for (int i = 0; i < num_pairs; ++i) { nums[2*i] = i + 1; // 用1开始的数字,避免和隐藏标记-1冲突 nums[2*i + 1] = i + 1; } // 打乱数组顺序 random_shuffle(nums.begin(), nums.end()); // 转换为二维矩阵 game_grid.clear(); int idx = 0; for (int i = 0; i < rows; ++i) { vector<int> row; for (int j = 0; j < cols; ++j) { row.push_back(nums[idx++]); } game_grid.push_back(row); } // 写入文件 ofstream output_file("grid.txt"); if (output_file) { for (int i = 0; i < rows; ++i) { for (int j = 0; j < cols; ++j) { output_file << game_grid[i][j] << " "; } output_file << endl; } output_file.close(); cout << "矩阵已成功生成并写入grid.txt!" << endl; } else { cout << "错误:无法写入文件!" << endl; exit(1); } } // 修改后的初始化函数,读取动态规格的矩阵 void initialize_grid() { ifstream input_file("grid.txt"); if (!input_file) { cout << "Womp. File open failed!"; exit(1); } game_grid.clear(); hidden_grid.clear(); guessed.clear(); int num; for (int i = 0; i < rows; ++i) { vector<int> row; // 存储真实数字的网格 vector<int> row2; // 隐藏网格,-1表示未翻开 vector<int> row3; // 标记已配对的网格,1表示已配对 for (int j = 0; j < cols; ++j) { if (input_file >> num) row.push_back(num); row2.push_back(-1); row3.push_back(0); } game_grid.push_back(row); hidden_grid.push_back(row2); guessed.push_back(row3); } cout << "Get ready, Challenger!" << endl << endl; input_file.close(); } // 修改后的完整网格打印(调试用) void print_grid() { cout << "Game grid (debug use)" << endl; cout << string(cols * 4 + 1, '-') << endl; // 动态生成分隔线 for (int i = 0; i < rows; ++i) { cout << " | "; for (int j = 0; j < cols; ++j) { cout << game_grid[i][j] << " | "; } cout << endl << string(cols * 4 + 1, '-') << endl; } cout << endl; } // 修改后的隐藏网格打印,处理配对逻辑 void print_hidden_grid(int r1 = -1, int r2 = -1, int c1 = -1, int c2 = -1) { cout << "Attempt:" << endl; if (r1 != -1) { hidden_grid[r1][c1] = game_grid[r1][c1]; } if (r2 != -1) { hidden_grid[r2][c2] = game_grid[r2][c2]; } // 打印网格 cout << string(cols * 4 + 1, '-') << endl; for (int i = 0; i < rows; ++i) { cout << " | "; for (int j = 0; j < cols; ++j) { if (hidden_grid[i][j] > -1) { cout << hidden_grid[i][j] << " | "; } else { cout << " | "; // 空格对齐,保证网格美观 } } cout << endl << string(cols * 4 + 1, '-') << endl; } cout << endl; // 处理配对结果 if (r1 != -1) { if (game_grid[r1][c1] == game_grid[r2][c2]) { guessed[r1][c1] = 1; guessed[r2][c2] = 1; cout << "You have a match!" << endl << endl; } else { // 让用户看清数字后再隐藏 cout << "No match... hiding numbers in 2 seconds..." << endl; system("pause"); // 跨平台可替换为this_thread::sleep_for(chrono::seconds(2)) hidden_grid[r1][c1] = -1; hidden_grid[r2][c2] = -1; } } cout << endl << endl; } // 修改后的当前状态网格打印 void print_current_grid() { cout << "Current Grid:" << endl; cout << string(cols * 4 + 1, '-') << endl; for (int i = 0; i < rows; ++i) { cout << " | "; for (int j = 0; j < cols; ++j) { if (hidden_grid[i][j] > -1) { cout << hidden_grid[i][j] << " | "; } else { cout << " | "; } } cout << endl << string(cols * 4 + 1, '-') << endl; } cout << endl << endl; } // 检查游戏是否结束(所有单元格已配对) bool is_game_over() { for (int i = 0; i < rows; ++i) { for (int j = 0; j < cols; ++j) { if (guessed[i][j] == 0) { return false; } } } return true; } // 游戏主逻辑 void play_game() { while (!is_game_over()) { int r1, c1, r2, c2; print_current_grid(); // 输入第一个坐标 cout << "Enter first row (0 to " << rows-1 << "): "; while (!(cin >> r1) || r1 < 0 || r1 >= rows) { cin.clear(); cin.ignore(numeric_limits<streamsize>::max(), '\n'); cout << "Invalid input! Enter first row (0 to " << rows-1 << "): "; } cout << "Enter first column (0 to " << cols-1 << "): "; while (!(cin >> c1) || c1 < 0 || c1 >= cols || guessed[r1][c1] == 1) { cin.clear(); cin.ignore(numeric_limits<streamsize>::max(), '\n'); if (guessed[r1][c1] == 1) { cout << "This cell is already matched! Enter another column: "; } else { cout << "Invalid input! Enter first column (0 to " << cols-1 << "): "; } } // 显示第一个选中的单元格 print_hidden_grid(r1, -1, c1, -1); // 输入第二个坐标 cout << "Enter second row (0 to " << rows-1 << "): "; while (!(cin >> r2) || r2 < 0 || r2 >= rows || guessed[r2][c2] == 1) { cin.clear(); cin.ignore(numeric_limits<streamsize>::max(), '\n'); if (guessed[r2][c2] == 1) { cout << "This cell is already matched! Enter another row: "; } else { cout << "Invalid input! Enter second row (0 to " << rows-1 << "): "; } } cout << "Enter second column (0 to " << cols-1 << "): "; while (!(cin >> c2) || c2 < 0 || c2 >= cols || (r2 == r1 && c2 == c1) || guessed[r2][c2] == 1) { cin.clear(); cin.ignore(numeric_limits<streamsize>::max(), '\n'); if (r2 == r1 && c2 == c1) { cout << "Cannot choose the same cell! Enter another column: "; } else if (guessed[r2][c2] == 1) { cout << "This cell is already matched! Enter another column: "; } else { cout << "Invalid input! Enter second column (0 to " << cols-1 << "): "; } } // 处理配对并更新界面 print_hidden_grid(r1, r2, c1, c2); } cout << "Congratulations! You've matched all pairs! Game over!" << endl; } int main() { generate_and_write_grid(); initialize_grid(); // print_grid(); // 如需调试查看完整矩阵,取消注释此行 play_game(); return 0; }
四、使用说明
- 运行程序后,首先输入矩阵的行数和列数,必须保证两者乘积是偶数(比如3×4、10×10都可以)
- 程序会自动生成随机配对矩阵并写入
grid.txt - 游戏过程中,输入单元格的行和列索引(从0开始)来选择要翻开的数字
- 如果配对成功,数字会保持显示;如果失败,数字会在短暂停留后隐藏
- 所有数字配对完成后,游戏结束并显示恭喜信息
内容的提问来源于stack exchange,提问作者user8249477




