Large amount of restructure and documentation
This commit is contained in:
parent
c469e978c4
commit
6cc32231c3
2 changed files with 223 additions and 96 deletions
122
ordle.cc
122
ordle.cc
|
@ -1,101 +1,69 @@
|
||||||
#include <iostream>
|
#include "ordle.h"
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <fstream>
|
#include <iostream>
|
||||||
#include <sstream>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
// Helper types and aliases
|
|
||||||
using size_type = std::string::size_type;
|
|
||||||
using letters_and_indices = std::map<size_type, std::string>;
|
|
||||||
|
|
||||||
// Function to read candidates from a file
|
|
||||||
std::vector<std::string> read_candidates(std::istream &input) {
|
std::vector<std::string> read_candidates(std::istream &input) {
|
||||||
std::vector<std::string> candidates;
|
std::vector<std::string> candidates;
|
||||||
std::string word;
|
std::string line;
|
||||||
|
|
||||||
while (input >> word) {
|
while (std::getline(input, line)) {
|
||||||
if (word.size() == 5) {
|
if (!line.empty() && line.back() == '\r') {
|
||||||
std::transform(word.begin(), word.end(), word.begin(), ::tolower);
|
line.pop_back();
|
||||||
candidates.push_back(word);
|
}
|
||||||
|
|
||||||
|
if (line.size() == 5) {
|
||||||
|
std::transform(line.begin(), line.end(), line.begin(), ::tolower);
|
||||||
|
candidates.push_back(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove duplicates
|
|
||||||
std::sort(candidates.begin(), candidates.end());
|
std::sort(candidates.begin(), candidates.end());
|
||||||
candidates.erase(std::unique(candidates.begin(), candidates.end()), candidates.end());
|
|
||||||
|
candidates.erase(std::unique(candidates.begin(), candidates.end()),
|
||||||
|
candidates.end());
|
||||||
|
|
||||||
return candidates;
|
return candidates;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper functions
|
bool wrong_fn::operator()(const std::string &word) const {
|
||||||
bool contains_any_of(const std::string &s, const std::string &cs) {
|
|
||||||
return std::any_of(cs.begin(), cs.end(), [&s](char c) { return s.find(c) != std::string::npos; });
|
|
||||||
}
|
|
||||||
|
|
||||||
bool contains_at(const std::string &s, char c, size_type pos) {
|
|
||||||
return pos < s.size() && s[pos] == c;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool contains_but_not_at(const std::string &s, char c, size_type pos) {
|
|
||||||
return s.find(c) != std::string::npos && !contains_at(s, c, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Functor for wrong letters
|
|
||||||
struct wrong_fn {
|
|
||||||
explicit wrong_fn(const std::string &letters) : l{letters} {}
|
|
||||||
|
|
||||||
bool operator()(const std::string &word) const {
|
|
||||||
return contains_any_of(word, l);
|
return contains_any_of(word, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
bool correct_fn::operator()(const std::string &word) const {
|
||||||
std::string l;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Functor for correct letters
|
|
||||||
struct correct_fn {
|
|
||||||
explicit correct_fn(const letters_and_indices &idxs) : m{idxs} {}
|
|
||||||
|
|
||||||
bool operator()(const std::string &word) const {
|
|
||||||
return std::all_of(m.begin(), m.end(), [&word](const auto &pair) {
|
return std::all_of(m.begin(), m.end(), [&word](const auto &pair) {
|
||||||
return contains_at(word, pair.second[0], pair.first);
|
return contains_at(word, pair.second[0], pair.first);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
letters_and_indices m;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Functor for misplaced letters
|
|
||||||
struct misplaced_fn {
|
|
||||||
explicit misplaced_fn(const letters_and_indices &idxs) : m{idxs} {}
|
|
||||||
|
|
||||||
bool operator()(const std::string &word) const {
|
|
||||||
return std::all_of(m.begin(), m.end(), [&word](const auto &pair) {
|
|
||||||
return contains_but_not_at(word, pair.second[0], pair.first);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
letters_and_indices m;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function to filter candidates
|
|
||||||
void do_filter(std::vector<std::string> &candidates, const std::string &wrong,
|
|
||||||
const letters_and_indices &green, const letters_and_indices &yellow) {
|
|
||||||
auto predicate = [&wrong, &green, &yellow](const std::string &word) {
|
|
||||||
return wrong_fn(wrong)(word) || !correct_fn(green)(word) || !misplaced_fn(yellow)(word);
|
|
||||||
};
|
|
||||||
|
|
||||||
candidates.erase(std::remove_if(candidates.begin(), candidates.end(), predicate), candidates.end());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// User interaction function
|
bool misplaced_fn::operator()(const std::string &word) const {
|
||||||
letters_and_indices build_list(const std::string &line) {
|
return std::all_of(m.begin(), m.end(), [&word](const auto &pair) {
|
||||||
|
auto a = contains_but_not_at(word, pair.second[0], pair.first);
|
||||||
|
if (a)
|
||||||
|
std::cout << "Misplaced: " << word << std::endl;
|
||||||
|
return a;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_filter(std::vector<std::string> &candidates, const std::string &wrong,
|
||||||
|
const IndexMap &green, const IndexMap &yellow) {
|
||||||
|
auto predicate = [&wrong, &green, &yellow](const std::string &word) {
|
||||||
|
return wrong_fn(wrong)(word) || !correct_fn(green)(word) ||
|
||||||
|
!misplaced_fn(yellow)(word);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove all words that do not satisfy the conditions
|
||||||
|
candidates.erase(
|
||||||
|
std::remove_if(candidates.begin(), candidates.end(), predicate),
|
||||||
|
candidates.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexMap build_list(const std::string &line) {
|
||||||
std::istringstream iss(line);
|
std::istringstream iss(line);
|
||||||
letters_and_indices result;
|
IndexMap result;
|
||||||
char letter;
|
char letter;
|
||||||
size_type index;
|
size_type index;
|
||||||
|
|
||||||
|
@ -106,7 +74,7 @@ letters_and_indices build_list(const std::string &line) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<std::string, letters_and_indices, letters_and_indices> prompt() {
|
std::tuple<std::string, IndexMap, IndexMap> prompt() {
|
||||||
std::string wrong;
|
std::string wrong;
|
||||||
std::cout << "Enter wrong letters:\n";
|
std::cout << "Enter wrong letters:\n";
|
||||||
std::getline(std::cin, wrong);
|
std::getline(std::cin, wrong);
|
||||||
|
|
205
ordle.h
205
ordle.h
|
@ -1,54 +1,213 @@
|
||||||
#ifndef ORDLE_H
|
#ifndef ORDLE_H
|
||||||
#define ORDLE_H
|
#define ORDLE_H
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// TODO: Evaluate need for helpers
|
||||||
|
|
||||||
// Helper types and aliases
|
// Helper types and aliases
|
||||||
using size_type = std::string::size_type;
|
using size_type = std::string::size_type;
|
||||||
using letters_and_indices = std::map<size_type, std::string>;
|
|
||||||
|
|
||||||
// Function declarations
|
/**
|
||||||
|
* @brief A mapping of indices to letters or strings.
|
||||||
|
*
|
||||||
|
* This type alias represents a map where each key is a position (index), and
|
||||||
|
* the value is a string (typically a single letter). It is used to track the
|
||||||
|
* correct or misplaced letter positions in word-guessing games, like Wordle, or
|
||||||
|
* similar puzzles.
|
||||||
|
*
|
||||||
|
* @note The `std::map` ensures that the indices are stored in sorted order,
|
||||||
|
* which is useful for efficiently checking conditions related to the positions
|
||||||
|
* of letters within words.
|
||||||
|
*
|
||||||
|
* @see correct_fn, misplaced_fn, build_list
|
||||||
|
*/
|
||||||
|
using IndexMap = std::map<size_type, std::string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a list of words from an input stream where each word is separated by a
|
||||||
|
* newline.
|
||||||
|
*
|
||||||
|
* @param input The input stream containing newline-separated words.
|
||||||
|
* @return A vector containing all the words from the input stream.
|
||||||
|
*/
|
||||||
std::vector<std::string> read_candidates(std::istream &input);
|
std::vector<std::string> read_candidates(std::istream &input);
|
||||||
|
|
||||||
bool contains_any_of(const std::string &s, const std::string &cs);
|
/**
|
||||||
bool contains_at(const std::string &s, char c, size_type pos);
|
* Checks if a string contains any character from a given set of characters.
|
||||||
bool contains_but_not_at(const std::string &s, char c, size_type pos);
|
*
|
||||||
|
* @param s The string to search within.
|
||||||
|
* @param cs A string containing the set of characters to look for.
|
||||||
|
* @return true if any character in 'cs' is found in 's'; otherwise, false.
|
||||||
|
*/
|
||||||
|
inline bool contains_any_of(const std::string &s, const std::string &cs) {
|
||||||
|
return std::any_of(cs.begin(), cs.end(),
|
||||||
|
[&s](char c) { return s.find(c) != std::string::npos; });
|
||||||
|
}
|
||||||
|
|
||||||
// Functors
|
/**
|
||||||
|
* Checks if a string contains a specific character at a given position.
|
||||||
|
*
|
||||||
|
* @param s The string to search within.
|
||||||
|
* @param c The character to check for.
|
||||||
|
* @param pos The position to check within the string.
|
||||||
|
* @return true if the character 'c' is found at position 'pos' in the string
|
||||||
|
* 's'; otherwise, false.
|
||||||
|
*/
|
||||||
|
inline bool contains_at(const std::string &s, char c, size_type pos) {
|
||||||
|
return pos < s.size() && s[pos] == c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a string contains a specific character, but not at a given
|
||||||
|
* position.
|
||||||
|
*
|
||||||
|
* @param s The string to search within.
|
||||||
|
* @param c The character to check for.
|
||||||
|
* @param pos The position where the character must not be located.
|
||||||
|
* @return true if the character 'c' is found in the string 's' and not at
|
||||||
|
* position 'pos'; otherwise, false.
|
||||||
|
*/
|
||||||
|
inline bool contains_but_not_at(const std::string &s, char c, size_type pos) {
|
||||||
|
for (size_type i = 0; i < s.size(); ++i) {
|
||||||
|
if (s[i] == c && i != pos) {
|
||||||
|
return true; // Found letter but not at the correct position
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false; // Letter not found or in the correct index
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A functor to filter words containing any of the specified letters.
|
||||||
|
*/
|
||||||
struct wrong_fn {
|
struct wrong_fn {
|
||||||
explicit wrong_fn(const std::string &letters);
|
/**
|
||||||
|
* Constructs a functor with the specified letters to filter against.
|
||||||
|
*
|
||||||
|
* @param letters A string containing the letters that words should not
|
||||||
|
* contain.
|
||||||
|
*/
|
||||||
|
wrong_fn(const std::string &letters) : l{letters} {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a word contains any of the specified "wrong" letters.
|
||||||
|
*
|
||||||
|
* @param word The word to be checked.
|
||||||
|
* @return True if the word contains any "wrong" letters; false otherwise.
|
||||||
|
*/
|
||||||
bool operator()(const std::string &word) const;
|
bool operator()(const std::string &word) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string l;
|
std::string l; ///< The letters considered "wrong".
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A functor to filter words based on exact character positions.
|
||||||
|
*/
|
||||||
struct correct_fn {
|
struct correct_fn {
|
||||||
explicit correct_fn(const letters_and_indices &idxs);
|
/**
|
||||||
|
* Constructs a functor with the specified indices and characters.
|
||||||
|
*
|
||||||
|
* @param idxs A map of indices to characters representing the exact
|
||||||
|
* matches.
|
||||||
|
*/
|
||||||
|
correct_fn(const IndexMap &idxs) : m{idxs} {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a word contains the correct characters at the specified
|
||||||
|
* indices.
|
||||||
|
*
|
||||||
|
* @param word The word to be checked.
|
||||||
|
* @return True if the word matches the correct indices; false otherwise.
|
||||||
|
*/
|
||||||
bool operator()(const std::string &word) const;
|
bool operator()(const std::string &word) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
letters_and_indices m;
|
IndexMap m; ///< Map of indices to expected characters.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A functor to filter words based on misplaced characters.
|
||||||
|
*/
|
||||||
struct misplaced_fn {
|
struct misplaced_fn {
|
||||||
explicit misplaced_fn(const letters_and_indices &idxs);
|
/**
|
||||||
|
* Constructs a functor with the specified indices and characters.
|
||||||
|
*
|
||||||
|
* @param idxs A map of indices to characters representing misplaced
|
||||||
|
* matches.
|
||||||
|
*/
|
||||||
|
misplaced_fn(const IndexMap &idxs) : m{idxs} {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a word contains the specified characters but at incorrect
|
||||||
|
* positions.
|
||||||
|
*
|
||||||
|
* @param word The word to be checked.
|
||||||
|
* @return True if the word contains the characters but at incorrect
|
||||||
|
* positions; false otherwise.
|
||||||
|
*/
|
||||||
bool operator()(const std::string &word) const;
|
bool operator()(const std::string &word) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
letters_and_indices m;
|
IndexMap m; ///< Map of indices to misplaced characters.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the `candidates` list by removing words that do not meet certain
|
||||||
|
* conditions based on the given `wrong`, `green`, and `yellow` parameters.
|
||||||
|
*
|
||||||
|
* The conditions are as follows:
|
||||||
|
* - A word is removed if it contains any of the incorrect letters specified in
|
||||||
|
* `wrong`.
|
||||||
|
* - A word is removed if it does not match the positions of the letters
|
||||||
|
* specified in `green` (green letters must be in the exact same positions).
|
||||||
|
* - A word is removed if it does not correctly place the yellow letters
|
||||||
|
* specified in `yellow` (yellow letters must be in the word but at different
|
||||||
|
* positions).
|
||||||
|
*
|
||||||
|
* @param candidates A reference to the vector of candidate words to filter.
|
||||||
|
* @param wrong A string of incorrect letters that should not appear in the
|
||||||
|
* word.
|
||||||
|
* @param green An `IndexMap` representing the correct letters and their exact
|
||||||
|
* positions in the word.
|
||||||
|
* @param yellow An `IndexMap` representing the letters that should appear in
|
||||||
|
* the word but in incorrect positions.
|
||||||
|
*/
|
||||||
void do_filter(std::vector<std::string> &candidates, const std::string &wrong,
|
void do_filter(std::vector<std::string> &candidates, const std::string &wrong,
|
||||||
const letters_and_indices &green, const letters_and_indices &yellow);
|
const IndexMap &green, const IndexMap &yellow);
|
||||||
|
|
||||||
letters_and_indices build_list(const std::string &line);
|
/**
|
||||||
std::tuple<std::string, letters_and_indices, letters_and_indices> prompt();
|
* Constructs an `IndexMap` from the provided string.
|
||||||
|
* The function parses the string and maps the indices of letters to their
|
||||||
|
* respective positions in a way that is suitable for the filtering logic in the
|
||||||
|
* Wordle solver.
|
||||||
|
*
|
||||||
|
* @param line A string representing the word or feedback line to process (e.g.,
|
||||||
|
* "G__Y_").
|
||||||
|
*
|
||||||
|
* @return An `IndexMap` where the key is the index of the letter, and the value
|
||||||
|
* represents the status of that letter. This could be an enumeration or an
|
||||||
|
* integer representing the state of the letter (e.g., green, yellow, or gray).
|
||||||
|
*/
|
||||||
|
IndexMap build_list(const std::string &line);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prompts the user (or simulation) for input, typically to get a guess and
|
||||||
|
* feedback from the user. This function returns the guessed word along with its
|
||||||
|
* green and yellow feedback in the form of `IndexMap`s.
|
||||||
|
*
|
||||||
|
* @return A tuple containing three elements:
|
||||||
|
* - A string representing the guessed word.
|
||||||
|
* - An `IndexMap` for the positions and letters that are correct (green
|
||||||
|
* letters).
|
||||||
|
* - An `IndexMap` for the positions and letters that are in the word
|
||||||
|
* but misplaced (yellow letters).
|
||||||
|
*/
|
||||||
|
std::tuple<std::string, IndexMap, IndexMap> prompt();
|
||||||
|
|
||||||
#endif // ORDLE_H
|
#endif // ORDLE_H
|
||||||
|
|
Loading…
Reference in a new issue