import java.io.*; import java.util.Scanner; import java.util.ArrayList; import java.util.Set; import java.util.TreeSet; /** * A word reduction is a list of words obtained by removing one * letter each time until the word contains a single letter. This * program finds all reducible words and prints them. * * @author Scot Drysdale, 1/14/2011 * @author Tom Cormen, modified to write results to a file */ public class WordReduction { /** * Reads a dictionary of words and puts all of ones that contain * either an "a" or an "i" into lists by length. * Assumes that the words are one per line. * * @param fileName the name of the file containing the dictionary. */ public static ArrayList> readWords(String fileName) { try { FileReader reader = new FileReader(fileName); Scanner in = new Scanner(reader); ArrayList> wordSets = new ArrayList>(); while (in.hasNextLine()) { String word = (in.nextLine()).toLowerCase(); if (word.contains("a") || word.contains("i")) { // Add lists for missing sizes while (word.length() > wordSets.size()) { wordSets.add(new TreeSet()); } wordSets.get(word.length()-1).add(word); // add the word to the correct list } } return wordSets; } catch (IOException exception) { System.out.println("File processing error: " + exception); } return null; // in case of an exception still need to return. } /** * Go through the wordSet and add any reducible words to goodWords. * Assumes that all good words shorter than the current word are * already in goodWords. * * @param wordSet list of words of a given length * @param goodWords set of all good words of shorter length */ public static void addGoodWords(Set wordSet, Set goodWords) { for (String word : wordSet) for (int pos = 0; pos < word.length(); pos++) if (goodWords.contains(dropLetter(word, pos))) goodWords.add(word); } /** * Returns the given word with letter in position pos dropped * * @param word the word to shorten * @param pos the position of the character to drop * @return word with letter in position pos dropped */ public static String dropLetter(String word, int pos) { return word.substring(0, pos) + word.substring(pos+1, word.length()); } /** * Prints the reduction chain starting with word * @param word the word to reduce * @param goodWords set of good words * @param outputFile file to write into */ public static void printReduction(String word, Set goodWords, PrintWriter outputFile) { String shortened; // the word with a letter dropped outputFile.print(word + " "); if (word.length() > 1) { for (int pos = 0; pos < word.length(); pos++) { shortened = dropLetter(word, pos); if (goodWords.contains(shortened)) { printReduction(shortened, goodWords, outputFile); return; } } System.err.println("Cannot reduce " + word); } } public static void main(String[] args) { Set goodWords = new TreeSet(); goodWords.add("i"); goodWords.add("a"); ArrayList> wordSets = readWords("/usr/share/dict/words"); System.out.println("Number of sets is " + wordSets.size()); for (Set wordSet : wordSets) addGoodWords(wordSet, goodWords); String outputFileName = "reductions.txt"; PrintWriter outputFile = null; try { outputFile = new PrintWriter(new File(outputFileName)); } catch (FileNotFoundException e) { System.err.println("Cannot open file: " + outputFileName); System.exit(1); } String longestWord = ""; for (String word : goodWords) { if (word.length() > longestWord.length()) longestWord = word; outputFile.print(word + ": "); for (int pos = 0; pos < word.length(); pos++) { String shortened = dropLetter(word, pos); if (goodWords.contains(shortened)) outputFile.print(shortened + " "); } outputFile.println(); } outputFile.println("Number of good words = " + goodWords.size()); outputFile.print("Longest word reduction: "); printReduction(longestWord, goodWords, outputFile); outputFile.println(); outputFile.close(); } }