Guess-the-word---Chinese-Version
背景
莫妮卡想要和我一起玩“上吊小人兒”(猜單詞),但是我還是個中學生啊……
可在github上下載完整代碼,詞庫,教程等
為什么我要寫這個程序
當然是因為MAS(Monika After story)中Monika提出了的新游戲——上吊小人兒——過於困難啦~
基本操作
1.編譯運行,輸入要猜的殘缺單詞,未知部分用*表示。
例如,app**
2.按下回車。
3.接下來輸入你已經猜過但是猜錯了的字母,中間不需要打空格,回車結束。如果還沒有猜錯了的字母的話就直接一個回車
例如你猜了但是猜錯了的字母有b,c,d
那么你就輸入bcd和一個回車
4.接下來程序就會給你所有可能性以及其中出現每個字母的次數,方便你選擇接下來要猜什么。
技巧
先輸入常用的字母如e,t,a
如果沒有足夠多的元音說明可能還有(aoeiu)
元音的后面及其可能接着n、r
Code
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<string> 6 #include<cmath> 7 #include<map> 8 #include<set> 9 #include<queue> 10 #include<vector> 11 #include<fstream> 12 #define IL inline 13 #define re register 14 #define LL long long 15 using namespace std; 16 17 bool in(char ch) 18 { 19 if (ch <= 'z' && ch >= 'a') return 1; 20 if (ch <= 'Z' && ch >= 'A') return 1; 21 return 0; 22 } 23 24 bool exclude(string a, string b, string c)//a中沒有b中的任何字母,a中沒有c中不同位置的任何字母 25 { 26 for (unsigned i = 0; i < a.size(); i++) 27 for (unsigned j = 0; j < b.size(); j++) 28 if (a[i] == b[j]) { 29 //cout<<"當前單詞為"<<a<<",重復字母為"<<a[i]<<endl; 30 return 0;//猜錯的字母不可能有 31 } 32 33 map<char, int>lib; 34 for (unsigned int i = 0; i < c.size(); i++) if (c[i] != '*') lib[c[i]]++; 35 for (unsigned int i = 0; i < a.size(); i++) if (c[i] == '*' && lib.find(a[i]) != lib.end()) return 0; 36 37 return 1; 38 } 39 40 vector<string>word; 41 42 string t; 43 int main() 44 { 45 ifstream fin("word.txt"); 46 ofstream fout("word.his", ios::app); 47 ifstream his("word.his"); 48 49 if (his.peek() == EOF) cout << "沒有查詢歷史\n"; 50 else while (his.peek() != EOF) his >> t, word.push_back(t); 51 52 cout << "讀取數據庫...\n"; 53 while (fin.peek() != EOF) { 54 string w; 55 getline(fin, t); 56 int post = 0; 57 while (!in(t[post]) && post < t.size()) post++; 58 while (in(t[post]) && post < t.size()) w.push_back((t[post] < 'a') ? (t[post] - 'A' + 'a') : t[post]), post++; 59 word.push_back(w); 60 } 61 cout << "讀取完畢!\n"; 62 while (true) { 63 string q, o; 64 cout << "輸入你想補全的殘缺的單詞,未知部分用*代替。\n"; 65 cin >> q; 66 getchar();//讀取剛剛剩下的一個空格 67 cout << "輸入已經猜錯了的字母,沒有的話直接按下回車鍵\n"; 68 getline(cin, o); 69 bool succ = 0; 70 int total = 0; 71 map<string, int>lib; 72 int count[27]; 73 memset(count, 0, sizeof(count)); 74 for (unsigned int i = 0; i < word.size(); i++) 75 { 76 if (lib.find(word[i]) == lib.end()) 77 if (q.size() == word[i].size() && exclude(word[i], o, q)) 78 { 79 bool flag = 1; 80 for (unsigned int j = 0; j < q.size(); j++) 81 { 82 if (q[j] != '*' && q[j] != word[i][j]) { 83 flag = 0; 84 break; 85 } 86 } 87 if (flag) { 88 succ = 1; 89 lib[word[i]]++; 90 cout << ++total << "\t" << word[i] << endl; 91 for (unsigned int j = 0; j < word[i].size(); j++) count[((word[i][j] < 'a') ? word[i][j] - 'A' + 'a' : word[i][j]) - 'a']++; 92 } 93 } 94 } 95 if (!succ) { 96 cout << "單詞沒有找到啊~你知道答案么?(yes/no)"; 97 string know; cin >> know; 98 if (know == "y" || know == "yes") { 99 cout << "請輸入答案:"; 100 string ans; 101 cin >> ans; 102 cout << "好噠,它已經被保存了\n"; 103 fout << ans << endl; 104 } 105 } 106 else { 107 cout << "共計" << total << "個符合條件的單詞\n"; 108 int max = -1; 109 count[max] = -1; 110 for (int i = 0; i < 26; i++) { 111 cout << (char)(i + 'a') << " " << count[i] << endl; 112 if (count[max] < count[i] && q.find(i + 'a') == q.npos) max = i; 113 } 114 cout << "建議猜測 " << (char)(max + 'a') << " 出現了 " << count[max] << "次"; 115 } 116 cout << endl << endl << endl; 117 } 118 return 0; 119 }
基本算法
讀取word.txt,進行無關字符的過濾,選取其有效部分加入vector<string>word中。讀取時如果是大寫字母則將其轉化為小寫
同理讀取歷史
輸入要猜的單詞以及猜錯了的字母
遍歷word,按照一下順序進行排除:
- 這個單詞本輪中沒有出現過(如果沒有則將其加入lib)
- 長度相同
- exclude()檢測這次掃的單詞中沒有猜錯的單詞,且其沒有被猜到的單詞位置上不能有猜對了的單詞(否則應該已經被猜出來而不是還是未知的)
- 除了*以外,相同位置上字母相同
- 如果沒有找到這個單詞的話,詢問要不要加入到錯詞本中
- 如果找到了,輸入所有結果和總數以及字母頻率分析
特點
- 詞庫不需要清洗
- 你可以瘋狂向詞庫末尾添加單詞,而不需要在意它會輸出多余相同的單詞(因為lib會自動過濾)
- 會向您推薦最佳的下一步應該猜的單詞
- 查不到的話可以記錄下來,下次就可以查
詞庫來源
本文使用的便是其其中的COCA_with_translation.txt,有20111個單詞