入遇到这样的需求
“有不定数量的游戏选项和不定的游戏人数选项给用户选择,我们按照 游戏人数<<24 | 游戏规则A<<16 | 游戏规则B<<8 | 游戏规则C 游戏规则D<<24 | 游戏规则E<<16 | 游戏规则F<<8 | 游戏规则G ........ 来生成所有规则可能选中和未选中的游戏码”
该需求中,不定数量的游戏选项和游戏人数需要动态输入 我们需要使用读取配置文件来获取多少游戏人数和游戏规则 这是待实现的功能1
根据获取数量的游戏选项 我们要生成所有可能的选中和未选中的排列组合 这是待实现的功能2
根据生成排列组合按照规则生成游戏码 还要说明游戏码中那些游戏选项被选中,也意味着需要进行排列组合和游戏规则的映射 这是待实现的功能3
读取配置文件来获取多少游戏人数和游戏规则 可以使用状态机分析配置文件 这之前已经有文章进行了介绍
地址
据获取数量的游戏选项 我们要生成所有可能的选中和未选中的排列组合 可以使用递归回溯来进行计算
整个流程如下
假设游戏规则有三个 游戏规则 A B C
步骤1 假设游戏规则A 被选中 生成编码1
步骤2 假设游戏规则B 被选中 生成编码11
步骤3 假设游戏规则C 被选中 生成第一个完整编码111
我们回退到步骤2 假设游戏规则B 被选中后 步骤3 假设游戏规则C未被选中 生成第二个完整编码 110 以此类推 。。。。。。
流程示意图
整个过程描述比较繁琐 但是对于使用递归回溯的函数 则十分简洁
void fillVecInner(int fillPos, map<int, string>& methodNumName) { if (fillPos == method_count) { //排列组合的位数与游戏选项的数目相同 说明生成了一个完整的排列组合 需要记录或者显示 for (int i = 0; i < vec.size(); i++) { if (1 == vec[i]) { std::cout << methodNumName[i] << " "; } } std::cout << std::endl; std::cout << std::endl; return; } for (int i = 0; i < 2; i++) { vec.push_back(i); //插入0 或者 1 fillVecInner(fillPos + 1, methodNumName); vec.pop_back(); //复原 进行下一次的插入 } }
游戏规则名称和生成排列组合的映射就比较简单了 在Cpp里就是一个map容器搞定
void GenmethodCode() { int iarr[3] = { 0 }; for (int i = 0; i < sizeof(iarr) / sizeof(iarr[0]); i++) { if (i < vec.size()) { iarr[i] = vec[i]; } } //打印根据游戏选项生成的游戏码 Caluateone(player_count, iarr[0], iarr[1], iarr[2]); if (vec.size() > 3) { int iarr[4] = { 0 }; for (int i = 0; i < sizeof(iarr) / sizeof(iarr[0]); i++) { if (i+3 < vec.size()) { iarr[i] = vec[i+3]; } } //打印根据游戏选项生成的游戏码 Caluatetwo( iarr[0], iarr[1], iarr[2], iarr[3]); } }
void GenmethodCode() { int iarr[3] = { 0 }; for (int i = 0; i < sizeof(iarr) / sizeof(iarr[0]); i++) { if (i < vec.size()) { iarr[i] = vec[i]; } } //打印根据游戏选项生成的游戏码 Caluateone(player_count, iarr[0], iarr[1], iarr[2]); if (vec.size() > 3) { int iarr[4] = { 0 }; for (int i = 0; i < sizeof(iarr) / sizeof(iarr[0]); i++) { if (i+3 < vec.size()) { iarr[i] = vec[i+3]; } } //打印根据游戏选项生成的游戏码 Caluatetwo( iarr[0], iarr[1], iarr[2], iarr[3]); } }
全部代码如下
1 #pragma once 2 3 #include <vector> 4 #include <iostream> 5 6 using namespace std; 7 8 /* 9 *作 者: itdef 10 *欢迎转帖 请保持文本完整并注明出处 11 *技术博客 http://www.cnblogs.com/itdef/ 12 *技术交流群 群号码:432336863 13 *欢迎c c++ windows驱动爱好者 服务器程序员沟通交流 14 *部分老代码存放地点 15 *http://www.oschina.net/code/list_by_user?id=614253 16 */ 17 18 class GenMethodArray { 19 public: 20 GenMethodArray(int MethodCount ,int playerCount):method_count(MethodCount), player_count(playerCount){} 21 ~GenMethodArray() {} 22 23 void fillVec(int fillPos, map<int, string>& methodNumName) { 24 fillVecInner(0, methodNumName); 25 } 26 void Caluateone(int playerNum, int j1, int j2, int j3) { 27 long i1 = 0; 28 29 i1 |= (playerNum << 24); 30 31 i1 |= (j1 << 16); 32 33 i1 |= (j2 << 8); 34 35 i1 |= j3; 36 37 std::cout << std::hex << "first = 0x" << i1 << std::endl; 38 //std::cout << "first = " << i1 << std::endl; 39 } 40 41 void Caluatetwo(int j4, int j5, int j6, int j7) { 42 long i1 = 0; 43 44 i1 |= (j4 << 24); 45 46 i1 |= (j5 << 16); 47 48 i1 |= (j6 << 8); 49 50 i1 |= j7; 51 52 std::cout << std::hex << "tow = 0x" << i1 << std::endl; 53 //std::cout << "tow = " << i1 << std::endl; 54 } 55 56 void GenmethodCode() { 57 int iarr[3] = { 0 }; 58 for (int i = 0; i < sizeof(iarr) / sizeof(iarr[0]); i++) { 59 if (i < vec.size()) { 60 iarr[i] = vec[i]; 61 } 62 } 63 //打印根据游戏选项生成的游戏码 64 Caluateone(player_count, iarr[0], iarr[1], iarr[2]); 65 66 if (vec.size() > 3) { 67 68 int iarr[4] = { 0 }; 69 for (int i = 0; i < sizeof(iarr) / sizeof(iarr[0]); i++) { 70 if (i+3 < vec.size()) { 71 iarr[i] = vec[i+3]; 72 } 73 } 74 //打印根据游戏选项生成的游戏码 75 Caluatetwo( iarr[0], iarr[1], iarr[2], iarr[3]); 76 } 77 } 78 79 80 private: 81 void fillVecInner(int fillPos, map<int, string>& methodNumName) { 82 if (fillPos == method_count) { 83 //打印游戏选项名称 若被选中 84 for (int i = 0; i < vec.size(); i++) { 85 if (1 == vec[i]) { 86 std::cout << methodNumName[i] << " "; 87 } 88 } 89 std::cout << std::endl; 90 91 /*for (int i = 0; i < vec.size(); i++) { 92 std::cout << vec[i]; 93 }*/ 94 //此函数中 打印根据游戏选项生成的游戏码 95 GenmethodCode(); 96 std::cout << std::endl; 97 std::cout << std::endl; 98 return; 99 } 100 101 for (int i = 0; i < 2; i++) { 102 vec.push_back(i); 103 fillVecInner(fillPos + 1, methodNumName); 104 vec.pop_back(); 105 } 106 } 107 108 int player_count; 109 int method_count; 110 vector<int> vec; 111 };
1 #pragma once 2 #include <iostream> 3 #include <fstream> 4 #include <cassert> 5 #include <string> 6 #include <iostream> 7 #include <vector> 8 #include <map> 9 10 using namespace std; 11 12 /* 13 *作 者: itdef 14 *欢迎转帖 请保持文本完整并注明出处 15 *技术博客 http://www.cnblogs.com/itdef/ 16 *技术交流群 群号码:432336863 17 *欢迎c c++ windows驱动爱好者 服务器程序员沟通交流 18 *部分老代码存放地点 19 *http://www.oschina.net/code/list_by_user?id=614253 20 */ 21 22 const string FILE_NAME = "config.txt"; 23 24 class ReadConfig { 25 public: 26 ReadConfig(string filename="") { 27 if (filename.empty()) { 28 file_name = FILE_NAME; 29 } 30 else { 31 file_name = filename; 32 } 33 } 34 ~ReadConfig(){} 35 36 map<string, string> Do() { 37 tar_path.clear(); 38 ifstream fin; 39 fin.open(file_name); 40 if (false == fin.is_open()) { 41 std::cerr << "open file failed!!" << std::endl; 42 return tar_path; 43 } 44 string s; 45 46 while (getline(fin, s)) 47 { 48 if ( '#' == s[0] || ( '/' == s[0] && '/' == s[1])) 49 continue; 50 size_t pos = s.find_first_of("="); 51 if (pos == std::string::npos || pos + 1 >= s.size()) 52 continue; 53 string targetName = s.substr(0, pos); 54 string path = s.substr(pos + 1); 55 std::cout << targetName << " = " << path << std::endl; 56 if(path[0] != ' ') 57 tar_path[targetName] = path; 58 } 59 fin.close(); 60 61 return tar_path; 62 } 63 64 private: 65 map<string, string> tar_path; 66 string file_name; 67 68 };
1 // CalculatePlayMethod.cpp: 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include "ReadConfig.h" 6 #include "GenMethodArray.h" 7 8 /* 9 *作 者: itdef 10 *欢迎转帖 请保持文本完整并注明出处 11 *技术博客 http://www.cnblogs.com/itdef/ 12 *技术交流群 群号码:432336863 13 *欢迎c c++ windows驱动爱好者 服务器程序员沟通交流 14 *部分老代码存放地点 15 *http://www.oschina.net/code/list_by_user?id=614253 16 */ 17 18 19 int main() 20 { 21 //获取配置 22 ReadConfig readcf; 23 map<string, string> targetMethod = readcf.Do(); 24 if (targetMethod.size() == 0) { 25 std::cerr << "get config error! exit!!" << std::endl; 26 return -1; 27 } 28 29 //获取玩家人数 30 int playerCount = atoi( targetMethod["playerNum"].c_str()); 31 if (0 == playerCount) { 32 playerCount = 4; 33 } 34 35 //获取玩法编号和玩法名称 36 map<int, string> methodNumName; 37 for (const auto& e : targetMethod) { 38 if (e.first != "playerNum" && e.second != "") { 39 //根据玩法标识最后一位的字符 与 ‘0’ 字符的差值 就是该字符表示的数值 40 //考虑到 数组与实际位值可能差1 所以是- ‘1’ 而不是 - ‘0’ 41 int i = (e.first)[e.first.size() - 1] - '1'; 42 methodNumName[i] = e.second; 43 } 44 } 45 46 //生成玩法的排列组合 47 GenMethodArray genMeArr(methodNumName.size(), playerCount); 48 genMeArr.fillVec(0, methodNumName); 49 50 system("pause"); 51 return 0; 52 }
配置文件内容
#注释可以使用 // 或者 #
playerNum=3
playMethod1=游戏模式A
playMethod2=游戏模式B
playMethod3=游戏模式C
playMethod4=游戏模式D
playMethod5=游戏模式E
playMethod6=
playMethod7=
playMethod8=
playMethod9=
//目前仅支持 7种玩法以内配置
运行效果如图
1 // 1111.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 2 // 3 4 #include "pch.h" 5 #include <iostream> 6 #include <vector> 7 #include <string> 8 9 10 using namespace std; 11 12 vector<vector<int>> init = { 13 {4},{0,1,2},{0,1},{0,1} 14 }; 15 vector<string> gv; 16 void findCombination (int index, const string& s) { 17 if (index == 4) { 18 gv.push_back(s); 19 return; 20 } 21 vector<int> v = init[index]; 22 for (int i = 0; i < v.size(); i++) { 23 findCombination(index + 1, s + to_string(v[i])); 24 } 25 26 } 27 int main() 28 { 29 std::cout << "Hello World! "; 30 findCombination(0,""); 31 for (int i = 0; i < gv.size(); i++) { 32 std::cout << gv[i] << std::endl; 33 } 34 } 35 36 // 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单 37 // 调试程序: F5 或调试 >“开始调试”菜单 38 39 // 入门提示: 40 // 1. 使用解决方案资源管理器窗口添加/管理文件 41 // 2. 使用团队资源管理器窗口连接到源代码管理 42 // 3. 使用输出窗口查看生成输出和其他消息 43 // 4. 使用错误列表窗口查看错误 44 // 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目 45 // 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件