// Nik Johnson // 2-11-2024 // TA: Andy Ruan /* absurd wordle-like game instead of guessing one word, prolongs game as long as possible by testing users guess against every word in selected dictionary, and choosing the largest set of words associated with a possible pattern for the users guess. the game only ends when the next set to be considered is narrowed down to one, and the user guesses it. */ import java.util.*; import java.io.*; public class Absurdle { public static final String GREEN = "🟩"; public static final String YELLOW = "🟨"; public static final String GRAY = "⬜"; // [[ ALL OF MAIN PROVIDED ]] public static void main(String[] args) throws FileNotFoundException { Scanner console = new Scanner(System.in); System.out.println("Welcome to the game of Absurdle."); System.out.print("What dictionary would you like to use? "); String dictName = console.next(); System.out.print("What length word would you like to guess? "); int wordLength = console.nextInt(); List contents = loadFile(new Scanner(new File(dictName))); Set words = pruneDictionary(contents, wordLength); List guessedPatterns = new ArrayList<>(); while (!isFinished(guessedPatterns)) { System.out.print("> "); String guess = console.next(); String pattern = record(guess, words, wordLength); guessedPatterns.add(pattern); System.out.println(": " + pattern); System.out.println(); } System.out.println("Absurdle " + guessedPatterns.size() + "/∞"); System.out.println(); printPatterns(guessedPatterns); console.close(); } // [[ PROVIDED ]] // Prints out the given list of patterns. // - List patterns: list of patterns from the game public static void printPatterns(List patterns) { for (String pattern : patterns) { System.out.println(pattern); } } // [[ PROVIDED ]] // Returns true if the game is finished, meaning the user guessed the word. Returns // false otherwise. // - List patterns: list of patterns from the game public static boolean isFinished(List patterns) { if (patterns.isEmpty()) { return false; } String lastPattern = patterns.get(patterns.size() - 1); return !lastPattern.contains("⬜") && !lastPattern.contains("🟨"); } // [[ PROVIDED ]] // Loads the contents of a given file Scanner into a List and returns it. // - Scanner dictScan: contains file contents public static List loadFile(Scanner dictScan) { List contents = new ArrayList<>(); while (dictScan.hasNext()) { contents.add(dictScan.next()); } return contents; } /* look through list of words from dictionary, removing words that aren't of the user specified length. takes list of words from user specified dictionary, and user specified word length return set of words pruned according to user input if the user specified length is less than one, throw IllegalArgumentException */ public static Set pruneDictionary(List contents, int wordLength) { if (wordLength < 1) throw new IllegalArgumentException(); Set prunedDict = new HashSet<>(); for (String word : contents) { if (word.length() == wordLength) { prunedDict.add(word); } } return prunedDict; } /* evaluate users guess, looking for the largest set of words that have the pattern of the guess. if all possible patterns have the same number of words, pick the first one in alphabetical order. takes users guess, set of words determined by pruneDictionary, and length of users guess return the pattern associated with the largest set of words if the users guess is the wrong length, or there is no words to be guessed, throw IllegalArgumentException */ public static String record(String guess, Set words, int wordLength) { if (guess.length() != wordLength || words.isEmpty()) { throw new IllegalArgumentException(); } Map> wordMap = new TreeMap<>(); for (String word : words) { String nextPattern = patternFor(word, guess); if (!wordMap.containsKey(nextPattern)) { wordMap.put(nextPattern, new HashSet()); } wordMap.get(nextPattern).add(word); } Boolean allSameSize = true; int setSize1 = 0; for (String pattern : wordMap.keySet()) { int size = wordMap.get(pattern).size(); if (setSize1 == 0) setSize1 = size; if (setSize1 != size) allSameSize = false; } if (allSameSize) { for (String pattern : wordMap.keySet()) { removeAllNonMatching(words, wordMap.get(pattern)); return pattern; } } String pattern = ""; int setSize = 0; for (String word : wordMap.keySet()) { int nextSetSize = (wordMap.get(word)).size(); if (nextSetSize > setSize) { setSize = nextSetSize; pattern = word; } } removeAllNonMatching(words, wordMap.get(pattern)); return pattern; } /* helper method for record, removes words from next considered set that arent in the largest set determined in record takes next set of words to be considered as determined by record, which will be used to trim the previous set no return */ public static void removeAllNonMatching(Set words, Set match) { Iterator iter = words.iterator(); while(iter.hasNext()) { if(!match.contains(iter.next())) { iter.remove(); } } } /* produce pattern for users guess against every word in set of considered words. takes users guess, and the word to generate a pattern against return pattern of colored squares for use in record */ public static String patternFor(String word, String guess) { List splitGuess = new ArrayList<>(); String pattern = new String(); for (int i = 0;i < guess.length(); i++) { String nextChar = Character.toString(guess.charAt(i)); splitGuess.add(nextChar); } Map wordMap = new HashMap<>(); for (int j = 0; j < word.length(); j++) { char wordChar = word.charAt(j); if (!wordMap.containsKey(wordChar)) { wordMap.put(wordChar, 1); } else { wordMap.put(wordChar, (wordMap.get(wordChar) + 1)); } } for (int n = 0; n < splitGuess.size(); n++) { if ((Character.toString(word.charAt(n))).equals(splitGuess.get(n))) { int currCount = wordMap.get((splitGuess.get(n)).charAt(0)); wordMap.put(word.charAt(n), (currCount - 1)); splitGuess.set(n, GREEN); } } for (int n = 0; n < splitGuess.size(); n++) { char charToCheck = (splitGuess.get(n)).charAt(0); if ((wordMap.keySet()).contains(charToCheck) && wordMap.get(charToCheck) != 0) { int currCount2 = wordMap.get(charToCheck); wordMap.put(charToCheck, (currCount2 - 1)); splitGuess.set(n, YELLOW); } } for (int n = 0; n < splitGuess.size(); n++) { if ((splitGuess.get(n)).length() == 1) { splitGuess.set(n, GRAY); } } for (int i = 0; i < splitGuess.size(); i++) { pattern += splitGuess.get(i); } return pattern; } }