字母拼词游戏开发:如何利用ofstream防止重复输入正确单词?
Hey there! Let's sort out that duplicate word problem you're facing. Right now, you're writing valid words to trial.txt but not verifying if the player has already used that word before accepting it. Here's a straightforward, efficient way to fix this:
Step 1: Track Used Words in Memory
Instead of relying on the file to check duplicates (which is slow and clunky), use an in-memory container like std::unordered_set<std::string>—it lets you check if a word exists in O(1) time. Add this declaration at the top of your start() function:
#include <unordered_set> // Don't forget to include this header! #include <string> // For std::string void start() { std::unordered_set<std::string> usedWords; // Tracks words the player has already submitted char ch; // ... rest of your code }
Step 2: Add Duplicate Check Before Validating the Word
When the player enters a word, first check if it's already in usedWords. If it is, prompt them to enter a new word. If not, proceed to validate it against your word list, then add it to the set and your output file.
Here's how to modify your input handling block:
cout << "\tEnter word: "; cin >> a; std::string inputWord(a); // Convert char array to std::string for easier handling // Check if word is already used if (usedWords.find(inputWord) != usedWords.end()) { cout << "You've already used this word! Try another one.\n"; delay(1000); continue; // Skip the rest of the loop and ask for a new word } // Now validate the word against your lvl1.txt ifstream fin("lvl1.txt"); if (fin.fail()) { cout << "File doesn't exist!"; exit(1); } bool isValid = false; int wordScore = 0; std::string dictWord; int dictScore; while (fin >> dictWord >> dictScore) { if (dictWord == inputWord) { isValid = true; wordScore = dictScore; break; } } fin.close(); if (!isValid) { cout << "Incorrect! Try Again!"; delay(1000); continue; } // If we get here, the word is valid and new usedWords.insert(inputWord); // Add to used set sum += wordScore; // Append to trial.txt (use ios::app to avoid overwriting the file) ofstream fout("trial.txt", ios::app); if (fout.fail()) { cout << "Output file opening failed.\n"; } else { fout << inputWord << "\n"; // Write each word on a new line for readability fout.close(); }
Step 3: Bonus Optimizations
- Preload the Dictionary: Instead of opening
lvl1.txtevery time the player enters a word, load all valid words and their scores into astd::unordered_map<std::string, int>at the start of the game. This will make validation much faster. - Fix the File Overwrite Issue: Your original code opens
trial.txtwithoutios::app, which erases the file every time. Usingios::appensures valid words are appended instead of overwritten. - Case Insensitivity: If you want to treat "Bast" and "bast" as the same word, convert the input to lowercase (or uppercase) before checking against the dictionary and used set.
Modified Full Code Snippet (Key Sections)
Here's how the updated start() function would look with these changes:
#include <iostream> #include <fstream> #include <cstring> #include <ctime> #include <unordered_set> #include <string> #include <conio.h> // Assuming you're using clrscr() and delay() from conio.h using namespace std; void start() { char ch; do { clrscr(); time_t start = time(nullptr); char arr[10][50] = {" B A N S E T ", " R E D G A E ", " S A H L E S ", " P R G N I S ", " A L E R L Y ", " L A C S A U ", " A C Q U K Y ", " M B L U E J ", " Z E D Z U B ", " L E A Z D Z "}; int i = 0, sum = 0, x; unordered_set<string> usedWords; while (i != 2) { clrscr(); sum = 0; do { clrscr(); cout << "\t**********************************************\n"; cout << "\t* W O R D S E E K E R *\n"; cout << "\t**********************************************\n"; cout << "\n\t\t\t\t\t SCORE: " << sum << " /50 pts" << "\n ******************************\n"; cout << " * " << arr[i] << " *\n"; cout << " ******************************\n\n"; cout << " 6 letter=10pts, 5 letter=8pts, 4 letters=6pts, 3 letter=4pts\n\n"; char a[20]; cout << "\tEnter word: "; cin >> a; string inputWord(a); // Check for duplicate if (usedWords.count(inputWord)) { cout << "Duplicate word! Try another.\n"; delay(1000); continue; } // Validate word ifstream fin("lvl1.txt"); if (fin.fail()) { cout << "File doesn't exist!"; exit(1); } bool isValid = false; int wordScore = 0; string dictWord; int dictScore; while (fin >> dictWord >> dictScore) { if (dictWord == inputWord) { isValid = true; wordScore = dictScore; break; } } fin.close(); if (!isValid) { cout << "Incorrect! Try Again!"; delay(1000); continue; } // Update score and used words sum += wordScore; usedWords.insert(inputWord); // Write to trial.txt ofstream fout("trial.txt", ios::app); if (!fout.fail()) { fout << inputWord << "\n"; fout.close(); } } while (sum < 50); i++; } x = time(nullptr) - start; cout << "\n\tGood Job! Your time is " << x << " seconds\n"; cout << "\tDo you want to continue?(Y/N): "; cin >> ch; } while (ch != 'n' && ch != 'N'); // Fixed the condition here! Original was using || which would loop forever }
A quick note: I fixed the loop condition at the end (ch != 'n' && ch != 'N')—your original code used ||, which would make the loop run forever no matter what input the user gave.
内容的提问来源于stack exchange,提问作者SmashMyKeyboard

