1 package org.guru.boggle;
3 import java.io.BufferedReader;
4 import java.io.FileReader;
5 import java.io.IOException;
8 import com.google.common.base.Objects;
9 import com.google.common.base.Preconditions;
10 import com.google.common.collect.ImmutableSet;
11 import com.google.common.collect.Sets;
13 public class DictionaryTrie {
15 private static class Node {
16 private boolean wordEndsHere;
17 private final Node[] children = new Node[26];
19 public Node(boolean wordEndsHere) {
20 this.wordEndsHere = wordEndsHere;
23 private int letterToIndex(char letter) {
24 Preconditions.checkArgument(letter >= 'A' && letter <= 'Z', "Expect uppercase letter");
29 public Node childForLetter(char letter) {
30 return children[letterToIndex(letter)];
33 public void addChildAtLetter(Node child, char letter) {
34 Preconditions.checkState(!hasChildAtLetter(letter), "I already have a child");
35 children[letterToIndex(letter)] = child;
38 public boolean hasChildAtLetter(char letter) {
39 return children[letterToIndex(letter)] != null;
42 public Set<Character> childrenList() {
43 Set<Character> result = Sets.newHashSetWithExpectedSize(8);
44 for (int i = 0; i < 26; ++i) {
45 if (children[i] != null) {
46 result.add((char) (i + 'A'));
52 public boolean doesWordEndHere() {
56 public void markWordEndsHere() {
61 public String toString() {
62 return Objects.toStringHelper(this)
63 .add("wordEndsHere", wordEndsHere)
64 .add("children", children)
69 private final Node root = new Node(false);
71 public DictionaryTrie(String inputFilePath) throws IOException {
72 FileReader fr = new FileReader(inputFilePath);
73 BufferedReader br = new BufferedReader(fr);
76 while ((line = br.readLine()) != null) {
77 line = line.toUpperCase();
79 for (int i = 0; i < line.length(); ++i) {
80 char letter = line.charAt(i);
81 if (!Character.isUpperCase(letter)) {
84 boolean lastCharacter = (i == line.length() - 1);
85 if (node.hasChildAtLetter(letter)) {
86 node = node.childForLetter(letter);
88 node.markWordEndsHere();
91 Node child = new Node(lastCharacter);
92 node.addChildAtLetter(child, letter);
95 System.out.printf("Added %s\n", line);
97 } catch (IOException e) {
98 System.err.println("Error: " + e);
106 private Node traverse(String word) {
108 for (int i = 0; i < word.length(); ++i) {
109 char letter = word.charAt(i);
110 if (!Character.isUpperCase(letter)) {
113 if (node.hasChildAtLetter(letter)) {
114 node = node.childForLetter(letter);
122 public boolean containsWord(String word) {
123 Node node = traverse(word);
124 return node != null && node.doesWordEndHere();
127 public Set<Character> possibleSuccessorLetters(String prefix) {
128 Node node = traverse(prefix);
130 return ImmutableSet.of();
132 return node.childrenList();