summaryrefslogtreecommitdiffstats
path: root/labb2
diff options
context:
space:
mode:
authorGustav Sörnäs <gustav@sornas.net>2020-09-15 13:47:27 +0200
committerGustav Sörnäs <gustav@sornas.net>2020-09-15 13:47:27 +0200
commitaa9d7f6543982618e0b4c72cfbfd3ebfeda293c1 (patch)
tree5555cd3fb03b9f795a1f6eb71d0d2d11b0171cf2 /labb2
parent4f2bda6a9c188f0c7d028b02b93ab3978fb7543c (diff)
downloadtddd86-aa9d7f6543982618e0b4c72cfbfd3ebfeda293c1.tar.gz
TDDDD86 labb 2 redovisninglab2
Diffstat (limited to 'labb2')
-rw-r--r--labb2/evilhangman/src/evilhangman.cpp179
-rw-r--r--labb2/wordchain/src/wordchain.cpp17
2 files changed, 138 insertions, 58 deletions
diff --git a/labb2/evilhangman/src/evilhangman.cpp b/labb2/evilhangman/src/evilhangman.cpp
index ce30ad5..c57995b 100644
--- a/labb2/evilhangman/src/evilhangman.cpp
+++ b/labb2/evilhangman/src/evilhangman.cpp
@@ -1,14 +1,20 @@
#include <iostream>
#include <string>
#include <fstream>
-
#include <list>
#include <map>
#include <set>
using namespace std;
-void openDictionary(map<int, list<string>> &wordsByLength, string path) {
+static const string ALPHABET = "abcdefghijklmnopqrstuvwxyz";
+
+/*
+ * Populate `wordsByLength` with lists of strings from file `path`.
+ *
+ * `wordsByLength` is "indexed" by the length of the words in the list.
+ */
+void openDictionary(map<int, list<string>> &wordsByLength, const string &path) {
ifstream input;
input.open(path);
string word;
@@ -23,9 +29,9 @@ void openDictionary(map<int, list<string>> &wordsByLength, string path) {
}
/*
- * Given a word and a previous prototype, update the prototype with the char `guess`.
+ * Update the prototype with the char `guess` to match `word`.
*/
-void getWordPrototype(string &wordPrototype, string &word, char guess) {
+void getWordPrototype(string &wordPrototype, const string &word, const char guess) {
for (int i = 0; i < word.size(); i++) {
if (word[i] == guess) {
wordPrototype[i] = guess;
@@ -34,22 +40,23 @@ void getWordPrototype(string &wordPrototype, string &word, char guess) {
}
/*
- * Populate `wordGroup` with the largest word group after a `guess` was made,
- * given a previous word group. Returns whether the prototype has changed or not.
+ * Update `wordGroup` with the largest word group after `guess` was made,
+ * given a previous word group and prototype. Returns whether the guess
+ * was correct or not and updates the prototype.
*/
-bool getWordGroup(list<string> &wordGroup, string &wordPrototype, char guess) {
- map<string, list<string>> wordGroups; // { prototype: [ match1, match2, .. ] }
- for (string &word: wordGroup) {
- if (word.find(guess) == string::npos) {
- // word doesn't contain guess
+bool getWordGroup(list<string> &wordGroup, string &wordPrototype, const char guess) {
+ map<string, list<string>> wordGroups; // { prototype: [ match1, match2, .. ], .. }
+ for (string &word : wordGroup) {
+ if (word.find(guess) == string::npos) { // word doesn't contain guess
+ // initial empty list
if (wordGroups.count(wordPrototype) == 0) {
wordGroups[wordPrototype] = list<string>();
}
wordGroups[wordPrototype].push_back(word);
- } else {
- // word contains guess at least once
+ } else { // word contains guess at least once
string newWordPrototype(wordPrototype);
getWordPrototype(newWordPrototype, word, guess);
+ // initial empty list
if (wordGroups.count(newWordPrototype) == 0) {
wordGroups[newWordPrototype] = list<string>();
}
@@ -67,6 +74,8 @@ bool getWordGroup(list<string> &wordGroup, string &wordPrototype, char guess) {
maxPrototype = n.first;
}
}
+
+ // set wordgroup and prototype
wordGroup = wordGroups[maxPrototype];
if (wordPrototype == maxPrototype) {
return false;
@@ -76,65 +85,131 @@ bool getWordGroup(list<string> &wordGroup, string &wordPrototype, char guess) {
}
}
-int main() {
- cout << "Welcome to Hangman." << endl;
-
- map<int, list<string>> wordsByLength;
- openDictionary(wordsByLength, "res/dictionary.txt");
-
- int wordLength;
- while (cout << "Choose a word length to guess: " && cin >> wordLength) {
- if (wordsByLength.count(wordLength) == 0) {
- cout << "No words of that length found." << endl;
- } else {
- break;
- }
- }
- int guesses;
- cout << "Choose number of guesses: ";
- cin >> guesses;
-
- bool showWordsLeft;
- {
- char response;
- cout << "Would you like to see the number of words left? [Y/n]: ";
- cin >> response;
- showWordsLeft = (response != 'n');
- }
-
+/*
+ * Play (evil) hangman with the given parameters.
+ *
+ * `wordLength` is the length of the word to guess.
+ * `guesses` is the total amount of guesses.
+ * `showWordsLeft` is whether to print how many valid words are left in each stage.
+ * `wordGroup` is the initial group of valid words.
+ */
+bool hangman(const int wordLength, const int guesses, const bool showWordsLeft, list<string> &wordGroup) {
string wordPrototype;
for (int i = 0; i < wordLength; i++) {
wordPrototype.push_back('-');
}
- list<string> wordGroup = wordsByLength[wordLength];
set<char> guessedChars;
+ int guesses_left = guesses;
+ string line;
bool won = false;
- while (guesses > 0 && !won) {
+ while (guesses_left > 0 && !won) {
+ // print status
if (showWordsLeft) {
cout << "(" << wordGroup.size() << ") ";
}
- cout << wordPrototype << " with " << guesses << " guesses left. Guessed characters: ";
- for (char c: guessedChars) {
+ cout << wordPrototype << " with " << guesses_left << " guesses left. Guessed characters: ";
+ for (char c : guessedChars) {
cout << c;
}
cout << endl;
- cout << "Guess a letter: ";
+
+ // ask for guess
char guess;
- cin >> guess;
+ bool done = false;
+ while (!done) {
+ cout << "Guess a letter: ";
+ getline(cin, line);
+ if (line.size() != 1) {
+ cout << "Please input one character only." << endl;
+ continue;
+ }
+ guess = line[0];
+ if (ALPHABET.find(guess) == string::npos) {
+ cout << "Please input a valid (lower-case) character." << endl;
+ continue;
+ }
+ if (guessedChars.count(guess)) {
+ cout << "You have already guessed this character." << endl;
+ continue;
+ }
+ done = true;
+ }
+ guessedChars.insert(guess);
+
+ // check guess
if (getWordGroup(wordGroup, wordPrototype, guess)) {
- // new prototype, correct guess
+ // correct guess, new prototype
won = (wordPrototype.find('-') == string::npos);
} else {
// wrong guess
- guessedChars.insert(guess);
- guesses--;
+ guesses_left--;
}
}
- if (won) {
- cout << "Well done!" << endl;
- } else {
- cout << "The word was '" << wordGroup.front() << "'. Better luck next time." << endl;
+ return won;
+}
+
+int main() {
+ cout << "Welcome to Hangman." << endl;
+
+ cout << "Reading dictionary... " << endl;
+ map<int, list<string>> wordsByLength;
+ openDictionary(wordsByLength, "res/dictionary.txt");
+ cout << "done" << endl;
+
+ bool play = true;
+ while (play) {
+ string line;
+ int wordLength;
+ bool done = false;
+ while (!done) {
+ cout << "Choose a word length to guess: ";
+ getline(cin, line);
+ try {
+ wordLength = stoi(line);
+ } catch (const invalid_argument &) {
+ cout << "Not a number." << endl;
+ continue;
+ }
+ if (wordsByLength.count(wordLength) == 0) {
+ cout << "No words of that length found." << endl;
+ } else {
+ done = true;
+ }
+ }
+ int guesses;
+ done = false;
+ while (!done) {
+ cout << "Choose number of guesses: ";
+ getline(cin, line);
+ try {
+ guesses = stoi(line);
+ } catch (const invalid_argument &) {
+ cout << "Not a number." << endl;
+ continue;
+ }
+ if (guesses <= 0) {
+ cout << "Non-positive number of guesses doesn't make sense." << endl;
+ continue;
+ }
+ done = true;
+ }
+
+ cout << "Would you like to see the number of words left? [Y/n]: ";
+ getline(cin, line);
+ bool showWordsLeft = (line != "n");
+
+ list<string> wordGroup = wordsByLength[wordLength];
+
+ if (hangman(wordLength, guesses, showWordsLeft, wordGroup)) {
+ cout << "Well done!" << endl;
+ } else {
+ cout << "The word was '" << wordGroup.front() << "'. Better luck next time." << endl;
+ }
+ cout << "Play again? [Y/n]: ";
+ getline(cin, line);
+ play = (line != "n");
}
+ cout << "Goodbye" << endl;
}
diff --git a/labb2/wordchain/src/wordchain.cpp b/labb2/wordchain/src/wordchain.cpp
index 5eb44c6..93f66af 100644
--- a/labb2/wordchain/src/wordchain.cpp
+++ b/labb2/wordchain/src/wordchain.cpp
@@ -10,7 +10,7 @@ using namespace std;
const string ALPHABET = "abcdefghijklmnopqrstuvwxyz";
-void openDictionary(set<string> &words, string path) {
+void openDictionary(set<string> &words, const string &path) {
ifstream input;
input.open(path);
string word;
@@ -21,13 +21,14 @@ void openDictionary(set<string> &words, string path) {
}
/*
- * Populates `neighbours` with all valid word neighbours from `words`.
+ * Populate `neighbours` with all valid word neighbours
+ * (words with only one char differing) from `words`.
*/
-void getValidNeighbours(forward_list<string> &neighbours, string &word, set<string> &words) {
+void getValidNeighbours(forward_list<string> &neighbours, const string &word, const set<string> &words) {
for (int i = 0; i < word.length(); i++) {
string new_word = word;
char cur_c = word[i];
- for (char new_c: ALPHABET) {
+ for (char new_c : ALPHABET) {
if (new_c != cur_c) {
new_word[i] = new_c;
if (words.count(new_word)) {
@@ -38,7 +39,11 @@ void getValidNeighbours(forward_list<string> &neighbours, string &word, set<stri
}
}
-void wordchain(stack<string> &chain, string w1, string w2, set<string> &words) {
+/*
+ * Find the shortest word chain between `w1` and `w2`
+ * and store it in `chain`.
+ */
+void wordchain(stack<string> &chain, const string &w1, const string &w2, const set<string> &words) {
stack<string> firstChain;
firstChain.push(w1);
@@ -51,7 +56,7 @@ void wordchain(stack<string> &chain, string w1, string w2, set<string> &words) {
chains.pop();
forward_list<string> validNeighbours;
getValidNeighbours(validNeighbours, curChain.top(), words);
- for (string &w: validNeighbours) {
+ for (string &w : validNeighbours) {
if (w == w2) {
// done
chain.push(w);