diff options
-rw-r--r-- | hashstrings.cpp | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/hashstrings.cpp b/hashstrings.cpp new file mode 100644 index 0000000..35d9dac --- /dev/null +++ b/hashstrings.cpp @@ -0,0 +1,136 @@ +#include <cmath> +#include <cstring> +#include <fstream> +#include <iostream> + +// Toggles whether generated strings are printed as they are generated. It looks +// cool and lets you see the progress, but slows down the process a lot. +#define PRINT_GENERATED_STRINGS 0 +#define MAX_GENERATED_STRING_LENGTH 8 + +// This function uses the same algorithm as Java's String.hashCode method. This +// implementation was stolen from OpenJDK. +int compute_hash_code(const std::string& str) +{ + int result = 0; + for (int i = 0; i < str.length(); i++) + result = 31 * result + str[i]; + return result; +} + +// This function checks if the hash matches for both the original string and the +// same string with the first letter capitalized. +bool compare_with_case_insensivity(std::string& str, int hash_to_find) +{ + int hash_code = compute_hash_code(str); + if (hash_code == hash_to_find) { + std::cout << str << std::endl; + return true; + } + + // Early exit if the first character is already uppercase. + if (std::isupper(str[0])) + return false; + + str[0] = std::toupper(str[0]); + hash_code = compute_hash_code(str); + if (hash_code == hash_to_find) { + std::cout << str << std::endl; + return true; + } + return false; +} + +bool find_from_dictionary(int hash_to_find) +{ + bool found = false; + + std::ifstream in_file("/usr/share/dict/words"); + if (!in_file.is_open()) { + std::cerr << "Failed to read dictionary file" << std::endl; + return false; + } + + std::string line; + while (std::getline(in_file, line)) { + found |= compare_with_case_insensivity(line, hash_to_find); + } + + in_file.close(); + return found; +} + +bool generate_all_strings(const std::string& prefix, int hash_to_find, int k) +{ + bool found = false; + if (k == 0) { +#if PRINT_GENERATED_STRINGS + std::cout << prefix << "\t\r" << std::flush; +#endif + + // Make a copy so the comparison function can safely modify the + // capitalization of the string. + std::string string_to_test = prefix; + return compare_with_case_insensivity(string_to_test, hash_to_find); + } + + for (char c = 'a'; c <= 'z'; c++) { + std::string new_prefix; + new_prefix = prefix + c; + found |= generate_all_strings(new_prefix, hash_to_find, k - 1); + } + + return found; +} + +// Generate every possible string using the lowercase alphabet with sizes up to +// max_length and test each and every one to see if it matches the wanted value. +bool find_from_generated_strings(int hash_to_find, int max_length) +{ + bool found = false; + + std::string str; + for (int length = 1; length <= max_length; length++) { + std::cout << "Checking strings of length " << length << '\n'; + found |= generate_all_strings(str, hash_to_find, length); + } + + return found; +} + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + std::cerr << "Please specify a hash code to find strings for.\n"; + return 1; + } + + if (strncmp(argv[1], "compute", 7) == 0) { + if (argc < 3) { + std::cerr << "Please specify a string to compute a hash for.\n"; + return 1; + } + std::cout << compute_hash_code(argv[2]) << std::endl; + return 0; + } + + int hash_to_find = std::atoi(argv[1]); + if (hash_to_find == 0) { + std::cerr << "The hash code you specified was invalid.\n"; + return 1; + } + + bool found = false; + + std::cout << "Searching dictionary... " << std::endl; + found = find_from_dictionary(hash_to_find); + if (!found) + std::cout << "Nothing found." << std::endl; + + std::cout << "Generating names up to " << MAX_GENERATED_STRING_LENGTH << " chars..." << std::endl; + found = find_from_generated_strings(hash_to_find, MAX_GENERATED_STRING_LENGTH); + if (!found) + std::cout << "Nothing found." << std::endl; + + return 0; +} |