Skip to content

Instantly share code, notes, and snippets.

@apainintheneck
Created July 10, 2022 16:54
Show Gist options
  • Save apainintheneck/60e8331e6fcdfa9084f130096c00a02a to your computer and use it in GitHub Desktop.
Save apainintheneck/60e8331e6fcdfa9084f130096c00a02a to your computer and use it in GitHub Desktop.
A simple program that finds partial anagrams of a given word.
#include <array>
#include <cctype>
#include <fstream>
#include <iostream>
#include <string>
/*
Usage: agram [base word] [min length]
Find partial anagrams using the /usr/share/dict/words list on mac.
Partial anagrams are words that can be created using the only the
letters found in the base word.
Example
-------
base_word = "bluebell"
partial_anagrams = [
"blue",
"bell",
]
*/
std::array<int, 26> build_freq_list(const std::string& word) {
std::array<int, 26> freq_list = {0};
for(char ch : word) {
ch = std::toupper(ch) - 'A';
freq_list[ch]++;
}
return freq_list;
}
bool is_partial_anagram(std::array<int, 26> base_freq_list, const std::string& word) {
for(char ch : word) {
ch = std::toupper(ch) - 'A';
if(base_freq_list[ch] == 0) return false;
base_freq_list[ch]--;
}
return true;
}
const auto word_list_path = "/usr/share/dict/words";
bool find_partial_anagrams(const std::string& base_word, const int min_length) {
std::ifstream infile(word_list_path);
if(not infile.is_open()) {
std::cout << "Unable to open: " << word_list_path << '\n';
exit(1);
}
const auto base_freq_list = build_freq_list(base_word);
bool found_match = false;
std::string buffer;
while(std::getline(infile, buffer)) {
if(buffer.size() > base_word.size()
or buffer.size() < min_length
or base_word == buffer) continue;
if(is_partial_anagram(base_freq_list, buffer)) {
std::cout << buffer << '\n';
found_match = true;
}
}
return found_match;
}
int main(int argc, const char * argv[]) {
if(argc < 2 or strlen(argv[1]) == 0) {
std::cout << "Usage: agram [base word] [min length]\n";
exit(1);
}
int min_length = 1;
if(argc >= 3) {
try {
min_length = std::stoi(argv[2]);
if(min_length < 1) throw std::invalid_argument("Negative number or zero");
} catch(...) {
std::cout << "Unable to read min length: must be an integer\n";
exit(1);
}
}
return find_partial_anagrams(argv[1], min_length) ? 0 : 1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment