├── .idea ├── .gitignore ├── misc.xml ├── modules.xml ├── uiDesigner.xml ├── vcs.xml └── workspace.xml ├── Graph-Data-Structure.iml ├── Graph.java ├── LargeWordGraph ├── LargeWordGraph_SmallerFileForExtraTest ├── Length3WordGraph ├── README.md ├── Tester.java ├── WordLadders.java ├── out └── production │ └── Graph-Data-Structure │ ├── .idea │ ├── .gitignore │ ├── misc.xml │ ├── modules.xml │ ├── uiDesigner.xml │ └── vcs.xml │ ├── Graph$1.class │ ├── Graph$2.class │ ├── Graph$GraphNode.class │ ├── Graph-Data-Structure.iml │ ├── Graph.class │ ├── LargeWordGraph │ ├── LargeWordGraph_SmallerFileForExtraTest │ ├── Length3WordGraph │ ├── Tester$CustomKeyClass.class │ ├── Tester.class │ ├── WordLadders.class │ ├── testFileForRead.txt │ ├── testWordGraph.txt │ ├── testWordGraph2.txt │ └── text_input.txt ├── testFileForRead.txt ├── testWordGraph.txt ├── testWordGraph2.txt └── text_input.txt /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 13 | 19 | 25 | 26 | 28 | { 29 | "associatedIndex": 4 30 | } 31 | 32 | 33 | 34 | 37 | { 38 | "keyToString": { 39 | "ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true", 40 | "Downloaded.Files.Path.Enabled": "false", 41 | "JUnit.Tester.executor": "Run", 42 | "Repository.Attach.Annotations": "false", 43 | "Repository.Attach.JavaDocs": "false", 44 | "Repository.Attach.Sources": "false", 45 | "RunOnceActivity.OpenProjectViewOnStart": "true", 46 | "RunOnceActivity.ShowReadmeOnStart": "true", 47 | "git-widget-placeholder": "main", 48 | "ignore.virus.scanning.warn.message": "true", 49 | "kotlin-language-version-configured": "true", 50 | "nodejs_package_manager_path": "npm", 51 | "settings.editor.selected.configurable": "preferences.general", 52 | "vue.rearranger.settings.migration": "true" 53 | } 54 | } 55 | 56 | 57 | 58 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 1707721262476 84 | 90 | 91 | 98 | 101 | 102 | 104 | 105 | 106 | 108 | -------------------------------------------------------------------------------- /Graph-Data-Structure.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Graph.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.FileReader; 3 | import java.io.IOException; 4 | import java.io.FileNotFoundException; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Comparator; 8 | import java.util.List; 9 | import java.util.Arrays; 10 | 11 | /** 12 | * A class that represents and stores a Graph data structure. It holds data of types Key (K) and Value (V). Each edge in 13 | * the graph is done by adding the nodes to be connected to each other's list of neighbors. 14 | * 15 | * @param Any generic type K. 16 | * @param Any generic type V. 17 | * 18 | * @author David Nguyen 19 | * @since 04/30/2023 20 | * @version 1.0 21 | */ 22 | public class Graph { 23 | 24 | // A field that is a list that stores all nodes in this graph 25 | private List listOfGraphNodes; 26 | 27 | /** 28 | * A constructor that creates a Graph data structure 29 | */ 30 | public Graph() { 31 | // Initialize necessary fields 32 | this.listOfGraphNodes = new ArrayList(); 33 | } 34 | 35 | /** 36 | * A method that adds a node to this graph and checks for duplicates. If a node with the same name and data already 37 | * exists in the graph, it will not be added to the graph and the method returns FALSE. Otherwise, it will be added 38 | * to the graph and the method will return TRUE. 39 | * 40 | * @param name Any name to add a new node to the graph with. 41 | * @param data The data of the new node to be added. 42 | * @return True or False depending on whether the node is successfully added to the graph or not. 43 | */ 44 | public boolean addNode(K name, V data) { 45 | // A variable that keeps track of whether the new node is successfully added or not 46 | boolean addNodeSuccess = false; 47 | // Checks if the key given is null to avoid NullPointerException 48 | if (name == null) { 49 | return false; // Return false if the key is null 50 | } 51 | // Otherwise, let the method continue normally 52 | else { 53 | ; 54 | } 55 | /* 56 | * Find if the node with the specified name and data already exists in the graph. If it exists, then the method 57 | * stops early and the new node will not be added. It will also return false by setting the addNodeSuccess 58 | * variable to false. 59 | */ 60 | if (findNodeWithName(name) != null) { 61 | // Sets the addNodeSuccess variable to false 62 | addNodeSuccess = false; 63 | // Return the variable so that the method will stop here 64 | return addNodeSuccess; 65 | } 66 | // Otherwise, do nothing and let the method continue as normal 67 | else { 68 | ; 69 | } 70 | // A variable that stores the new node that will be added to the graph 71 | GraphNode nodeToBeAdded = new GraphNode(name, data); 72 | // Add that node to the graph's list of nodes to add it to the graph 73 | this.listOfGraphNodes.add(nodeToBeAdded); 74 | // Sets the addNodeSuccess variable to true to indicate that the node has been successfully added 75 | addNodeSuccess = true; 76 | // Return the addNodeSuccess variable in order to end the method 77 | return addNodeSuccess; 78 | } 79 | 80 | /** 81 | * A method that adds a list of nodes to this graph and also checks for duplicated nodes. If any node with the same 82 | * name and data already exists in the graph, it will not be added to the graph and the method returns FALSE. 83 | * Otherwise, it will be added normally and the method returns TRUE. The two input arrays must be of the same length. 84 | * Note that null keys will not be added to avoid NullPointerExceptions later on. 85 | * 86 | * @param names Any name to add a new node to the graph with. 87 | * @param data The data of the new node to be added. 88 | * @return True or False depending on whether the node is successfully added to the graph or not. 89 | * @throws IllegalArgumentException Throws an IllegalArgumentException if the two given arrays have different lengths. 90 | */ 91 | public boolean addNodes(K[] names, V[] data) { 92 | // A variable that keeps track of whether the new node is successfully added or not 93 | boolean addNodesSuccess = true; 94 | // Throws an IllegalArgumentException if the two given arrays have different lengths: 95 | if (names.length != data.length) { 96 | throw new IllegalArgumentException("The given names and data arrays have different length - " + 97 | "They must have the same length!"); 98 | } 99 | // Otherwise, let the method continue as normal 100 | else { 101 | ; 102 | } 103 | // A loop that iterates through the two given arrays to add the nodes to this graph, one by one: 104 | for (int index = 0; index < names.length && index < data.length; index = index + 1) { 105 | // If the node to be added's key is null, skip it because we cannot allow null keys in our graph 106 | if (names[index] == null) { 107 | continue; // Skip the null key 108 | } 109 | // Otherwise, let the method continue normally 110 | else { 111 | ; 112 | } 113 | /* 114 | * A variable that stores whether a node constructed by the data in the given two arrays has been successfully 115 | * added to this graph or not 116 | */ 117 | boolean ifAddThisNodeSuccessful = addNode(names[index], data[index]); 118 | /* 119 | * Updates the addNodeSuccess variable to the value of the comparison between itself and the variable 120 | * ifAddThisNodeSuccessful in order to keep track of whether the new node has been successfully added to the 121 | * graph or not 122 | */ 123 | addNodesSuccess = addNodesSuccess && ifAddThisNodeSuccessful; 124 | } 125 | // Return the addNodeSuccess variable in order to end the method 126 | return addNodesSuccess; 127 | } 128 | 129 | /** 130 | * A method that adds an undirected edge from Node FROM to Node TO. It will connect the two nodes together using an 131 | * edge, and these two nodes will also become neighbors of each other. 132 | * Please Note: Duplicated edges are not allowed, and they will not be added. 133 | * 134 | * @param from Any node to add the edge from. 135 | * @param to Any node to add the edge to. 136 | * @return True or False depending on whether the new edge has been successfully added to the graph or not. 137 | */ 138 | public boolean addEdge(K from, K to) { 139 | // If the node to add edge from or node to add edge to is null, no edge should be added here to avoid exceptions 140 | if (from == null || to == null) { 141 | return false; // Return false if either of the keys is null 142 | } 143 | // Otherwise, let the method continue normally 144 | else { 145 | ; 146 | } 147 | // A variable that stores the node from which the new edge will be added and connected 148 | GraphNode addEdgeFromThisNode = findNodeWithName(from); 149 | // A variable that stores the node to which the new edge will be added and connected 150 | GraphNode connectEdgeToThisNode = findNodeWithName(to); 151 | // A variable that keeps track of whether the new edge is successfully added or not 152 | boolean addEdgeSuccess = false; 153 | // Checks if Node FROM is null. If it is, no new edge can be added and the method stops early and returns false 154 | if (addEdgeFromThisNode == null) { 155 | // Sets the addEdgeSuccess variable to false in order to indicate that no new edge can be added 156 | addEdgeSuccess = false; 157 | // Return the addEdgeSuccess variable to stop the method 158 | return addEdgeSuccess; 159 | } 160 | // Otherwise, let the method continue as normal 161 | else { 162 | ; 163 | } 164 | // Check if Node TO is null. If it is, no new edge can be added and the method stops early and returns false 165 | if (connectEdgeToThisNode == null) { 166 | // Sets the addEdgeSuccess variable to false in order to indicate that no new edge can be added 167 | addEdgeSuccess = false; 168 | // Return the addEdgeSuccess variable to stop the method 169 | return addEdgeSuccess; 170 | } 171 | // Otherwise, let the method continue as normal 172 | else { 173 | ; 174 | } 175 | // A variable that stores whether the Node FROM has the same neighbors as the Node TO 176 | boolean isFromNodeHasSameNeighborsAsToNode = addEdgeFromThisNode.getNeighborsList().contains(connectEdgeToThisNode); 177 | /* 178 | * If the Node FROM has the same neighbors as the Node TO, then no new edge will be added and the method returns 179 | * FALSE. 180 | */ 181 | if (isFromNodeHasSameNeighborsAsToNode == true) { 182 | // Sets the addEdgeSuccess variable to false in order to indicate that no new edge can be added 183 | addEdgeSuccess = false; 184 | // Return the addEdgeSuccess variable to stop the method 185 | return addEdgeSuccess; 186 | } 187 | // Otherwise, let the method continue as normal 188 | else { 189 | ; 190 | } 191 | // Add the Node TO to Node FROM's list of neighbors in order to connect them together - establishing an 'Edge' 192 | addEdgeFromThisNode.getNeighborsList().add(connectEdgeToThisNode); 193 | // Add the Node FROM to Node TO's list of neighbors in order to connect them together 194 | connectEdgeToThisNode.getNeighborsList().add(addEdgeFromThisNode); 195 | // Sets the addEdgeSuccess variable to true in order to indicate that an edge has been successfully added 196 | addEdgeSuccess = true; 197 | // Return the addEdgeSuccess variable in order to stop the method 198 | return addEdgeSuccess; 199 | } 200 | 201 | /** 202 | * A method that adds an undirected edge from Node FROM to each and all nodes in the given toList. It will connect 203 | * Node FROM to each node in toList together, and each pair of nodes will also become neighbors of each other. 204 | * Please Note: Duplicated edges are not allowed, and they will not be added. 205 | * 206 | * @param from Any node to add edges from. 207 | * @param toList The list of nodes to add edges to. 208 | * @return True or False depending on whether the new edges have been successfully added to the graph or not. 209 | */ 210 | public boolean addEdges(K from, K... toList) { 211 | // If node from is null, no further operation can be appropriately done with it, return false 212 | if (from == null) { 213 | return false; 214 | } 215 | // Otherwise, let the method continue normally 216 | else { 217 | ; 218 | } 219 | // A variable that keeps track of whether the new edges are successfully added or not 220 | boolean addEdgesSuccess = true; 221 | // A loop that adds each edge from Node FROM to each node in toList 222 | for (K nodeToAddEdgeTo : toList) { 223 | // Checks if the nodeToAddEdgeTo is null, it will be skipped as no operations can be done with it 224 | if (nodeToAddEdgeTo == null) { 225 | continue; // Skip the null key 226 | } 227 | // Otherwise, let the method continue normally 228 | else { 229 | ; 230 | } 231 | // Variable that stores whether each pair of nodes has been successfully connected or not 232 | boolean ifAddThisEdgeSuccessful = addEdge(from, nodeToAddEdgeTo); 233 | /* 234 | * Updates the addEdgeSuccess variable to the value of the comparison between itself and the variable 235 | * ifAddThisEdgeSuccessful in order to keep track of whether the new edge has been successfully added to the 236 | * graph or not. 237 | */ 238 | addEdgesSuccess = addEdgesSuccess && ifAddThisEdgeSuccessful; 239 | } 240 | // Return the addEdgeSuccess variable in order to stop the method 241 | return addEdgesSuccess; 242 | } 243 | 244 | /** 245 | * A method that removes a node from the graph along with all connected edges. It will take the name of the node to 246 | * be removed and removes it from the graph. 247 | * 248 | * @param name The name of the node to be removed 249 | * @return True or False depending on whether the node have been successfully removed from the graph or not. 250 | */ 251 | public boolean removeNode(K name) { 252 | // Checks if the given node name is null and stop the method early in this case to avoid NullPointerExceptions 253 | if (name == null) { 254 | return false; // Return false if the key is null 255 | } 256 | // Otherwise, let the method continue normally 257 | else { 258 | ; 259 | } 260 | // A variable that stores the node to be removed from the graph with the specified name 261 | GraphNode nodeToRemove = findNodeWithName(name); 262 | // A variable to store whether the specified node has been successfully removed or not 263 | boolean removeNodeSuccess = false; 264 | // Checks if the node to be removed is NULL or not. If it is, it can't be removed and the method returns false. 265 | if (nodeToRemove == null) { 266 | // Sets the removeNodeSuccess variable to false in order to indicate that the specified node cannot be removed 267 | removeNodeSuccess = false; 268 | // Return the removeNodeSuccess variable to end the method 269 | return removeNodeSuccess; 270 | } 271 | // Otherwise, let the method continue as normal 272 | else { 273 | ; 274 | } 275 | // A variable that stores the length of the neighbors list of the node to be removed 276 | int lengthOfNodeNeighbors = nodeToRemove.getNeighborsList().size(); 277 | // A loop that iterates through the node to be removed's list of neighbors to remove all of its connected edges 278 | for (int index = 0; index < lengthOfNodeNeighbors; index = index + 1) { 279 | // A variable that stores each neighbor of the neighbors list of the node to be removed 280 | GraphNode everyNeighborOfRemovedNode = nodeToRemove.getNeighborsList().get(index); 281 | // Remove the node to be removed from the neighbor's list of neighbors to remove the connection between them 282 | everyNeighborOfRemovedNode.getNeighborsList().remove(nodeToRemove); 283 | } 284 | // Remove the node to be removed from the graph 285 | this.listOfGraphNodes.remove(nodeToRemove); 286 | // Sets the removeNodeSuccess to true to indicate that the node to be removed has been successfully removed 287 | removeNodeSuccess = true; 288 | // Returns the removeNodeSuccess in order to stop the method 289 | return removeNodeSuccess; 290 | } 291 | 292 | /** 293 | * A method that removes each node in nodelist and all of their associated edges from this graph. 294 | * 295 | * @param nodelist The list containing all nodes to be removed from this graph. 296 | * @return True or False depending on whether all nodes in nodelist have been successfully removed or not. 297 | */ 298 | public boolean removeNodes(K... nodelist) { 299 | // A variable to store whether all nodes in nodelist have been successfully removed or not. 300 | boolean removeNodesSuccess = true; 301 | // A loop that removes each node in nodelist from this graph 302 | for (K everyNodeToBeRemoved : nodelist) { 303 | // A variable that stores the current node in the list that will be removed from this graph 304 | boolean ifRemoveThisNodeSuccessful = removeNode(everyNodeToBeRemoved); 305 | /* 306 | * Updates the removeNodesSuccess variable to the value of the comparison between itself and the variable 307 | * ifRemoveThisNodeSuccessful in order to keep track of whether the new node has been successfully removed 308 | * from this graph or not. 309 | */ 310 | removeNodesSuccess = removeNodesSuccess && ifRemoveThisNodeSuccessful; 311 | } 312 | // Return the removeNodesSuccess variable in order to stop the method 313 | return removeNodesSuccess; 314 | } 315 | 316 | /** 317 | * A method that prints the graph in this adjacency list format: (nodename1) (neighbor1) (neighbor2) (neighbor3). 318 | * The nodes and their neighbors will also be listed in ALPHABETICAL ORDER. If there is any value associated with 319 | * this node, it will also be printed next to nodename1, like this: (nodename1) (nodevalue1) (neighbor1) (neighbor2) 320 | * (neighbor3), and so on. 321 | */ 322 | public void printGraph() { 323 | // Sort the list of graph nodes based on their key's string representations (ascending order) 324 | this.listOfGraphNodes.sort(new Comparator() { 325 | // A method that compare each pair of nodes with each other - Override the inherited method from Comparator: 326 | @Override 327 | public int compare(GraphNode node1, GraphNode node2) { 328 | // A variable that stores node 1's key in its string representation 329 | String node1Key = node1.getKey().toString(); 330 | // A variable that stores node 2's key in its string representation 331 | String node2Key = node2.getKey().toString(); 332 | /* 333 | * A variable that stores the comparison results of node 1's key and node 2's key in their string 334 | * representations: 335 | */ 336 | int comparisonResult = node1Key.compareTo(node2Key); 337 | // Returns comparisonResult variable to end the method early 338 | return comparisonResult; 339 | } 340 | }); 341 | // A loop that iterates through each node in the list of graph nodes 342 | for (int index1 = 0; index1 < this.listOfGraphNodes.size(); index1 = index1 + 1) { 343 | // A variable that stores every node in the list of graph nodes of this Graph 344 | GraphNode everyNodeInGraph = this.listOfGraphNodes.get(index1); 345 | // A variable that stores the keys of every node in the list of graph nodes of this Graph 346 | K keyOfEveryNode = everyNodeInGraph.getKey(); 347 | // Print the node's key to System.out and, if available, its value 348 | System.out.print(keyOfEveryNode); 349 | // A variable that stores every node in the graph's value in order to print it to System.out later 350 | if (everyNodeInGraph.getValue() != null) { 351 | // Print every node in the graph's value to System.out 352 | System.out.print("(" + everyNodeInGraph.getValue() + ")"); 353 | } 354 | // Otherwise, let the method continue as normal 355 | else { 356 | ; 357 | } 358 | // Print the neighbors of each node in the graph to System.out 359 | System.out.print(" "); 360 | // Now, sort the neighbors of the current node based on their key's string representation 361 | everyNodeInGraph.getNeighborsList().sort(new Comparator() { 362 | /* 363 | * A method that compare each pair of neighbor nodes of this node with each other - Override the 364 | * inherited method from Comparator: 365 | */ 366 | @Override 367 | public int compare(GraphNode neighbor1, GraphNode neighbor2) { 368 | // A variable that stores node 1's neighbor's key in its string representation 369 | String neighbor1Key = neighbor1.getKey().toString(); 370 | // A variable that stores node 2's neighbor's key in its string representation 371 | String neighbor2Key = neighbor2.getKey().toString(); 372 | /* 373 | * A variable that stores the comparison results of node 1's neighbor's key and node 2's neighbor's 374 | * key in their string representations: 375 | */ 376 | int comparisonResult = neighbor1Key.compareTo(neighbor2Key); 377 | // Returns comparisonResult variable to end the method early 378 | return comparisonResult; 379 | } 380 | }); 381 | // A loop that iterates through each neighbor of the current node and print their key to System.out 382 | for (int index2 = 0; index2 < everyNodeInGraph.getNeighborsList().size(); index2 = index2 + 1) { 383 | GraphNode everyNeighbor = everyNodeInGraph.getNeighborsList().get(index2); 384 | // Print all the neighbors' their key to System.out 385 | System.out.print(everyNeighbor.getKey() + " "); 386 | } 387 | // Print a new line before moving to the next node to give the command output some space 388 | System.out.println(); 389 | } 390 | } 391 | 392 | /** 393 | * A method that constructs a graph from a text file using the format: (nodename1) (neighbor1) (neighbor2) ... and 394 | * (nodename2) (neighbor1) (neighbor2) ... Names of node can be any alphanumeric strings using white spaces as 395 | * separators. It is able to construct more complex graphs with a simple specification from a text file. 396 | * 397 | * @param filename The specified name of file from which a new graph will be constructed. 398 | * @return A new graph that has its key of type String and its value of any type that is constructed from the given 399 | * file. 400 | * @param Any type V for the value of the graph to be created. 401 | */ 402 | public static Graph read(String filename) { 403 | // Create a new empty graph to construct from the given, specified file 404 | Graph graphToBeConstructed = new Graph(); 405 | // Try-catch block to detect possible IOException from invalid file or filename 406 | try { 407 | // A variable of type FileReader to open the file and read it to the program with the given filename 408 | FileReader fileReaderForGivenFileName = new FileReader(filename); 409 | // A variable of type BufferedReader to create a buffered reader to read the file line by line 410 | BufferedReader bufferedReaderForGivenFileName = new BufferedReader(fileReaderForGivenFileName); 411 | // A variable to store each line in the file 412 | String everySingleLineInFile = new String(); 413 | // A loop that loops through all lines in the file to read them and construct nodes in the graph from them 414 | while ((everySingleLineInFile = bufferedReaderForGivenFileName.readLine()) != null) { 415 | /* 416 | * Split the line into an array of strings using whitespace as the delimiter and store it in a variable 417 | * of type String 418 | */ 419 | String[] splitLines = everySingleLineInFile.split("\\s+"); 420 | /* 421 | * A variable that stores the node from the first element of the array - this node will be the node to 422 | * be added to graph later 423 | */ 424 | String nodeFromSplitLine = splitLines[0]; 425 | // Add the node to the graph with a null value 426 | graphToBeConstructed.addNode(nodeFromSplitLine, null); 427 | // A loop that iterates through the remaining elements in the array, which represent neighbors 428 | for (int index = 1; index < splitLines.length; index = index + 1) { 429 | // A string variable that stores the neighbor's name 430 | String neighborOfNodeToBeAdded = splitLines[index]; 431 | // Add an edge between the current node and its neighbor 432 | graphToBeConstructed.addEdge(nodeFromSplitLine, neighborOfNodeToBeAdded); 433 | } 434 | } 435 | } 436 | // If any Exception type is caught, print its message to System.out 437 | catch (IOException exception) { 438 | // If there's an error reading the file, print error messages to System.out 439 | System.out.println("Unfortunately, there is an error reading this file: " + exception.getMessage()); 440 | // Prompts the user to re-check their desired filename (file must be in the same directory as the project) 441 | System.out.println("Please check your filename!"); 442 | } 443 | // Return the constructed graph from the given file 444 | return graphToBeConstructed; 445 | } 446 | 447 | /** 448 | * A method that finds and returns the path (i.e. a list of node names) of depth-first search between node FROM and 449 | * node TO. It will return an empty array if no path exists between the two given nodes. The first entry of the 450 | * returned array will be the FROM node and the last value of the array will be the TO node. 451 | * 452 | * @param from A node from which the path will be found using DFS. 453 | * @param to A node to which the path will be found using DFS. 454 | * @return A path between node FROM and node TO found using DFS. 455 | */ 456 | public K[] DFS(K from, K to) { 457 | // A node from which the path will be found using DFS 458 | GraphNode nodeToPerformDFSFrom = findNodeWithName(from); 459 | // A node to which the path will be found using DFS 460 | GraphNode nodeToPerformDFSUntil = findNodeWithName(to); 461 | // If node FROM is null or does not exist in the graph, returns an empty list or array as no path can be found with it 462 | if (nodeToPerformDFSFrom == null) { 463 | // A variable that stores the return array which will be empty in this case 464 | Object[] returnArray = new Object[0]; 465 | // A variable that stores the above array but was casted to the type of K 466 | K[] castedReturnArray = (K[]) returnArray; 467 | // Returns the casted return array as above 468 | return castedReturnArray; 469 | } 470 | // Otherwise, let the method continue as normal 471 | else { 472 | ; 473 | } 474 | // If node TO is null or does not exist in the graph, returns an empty list or array as no path can be found with it 475 | if (nodeToPerformDFSUntil == null) { 476 | // A variable that stores the return array which will be empty in this case 477 | Object[] returnArray = new Object[0]; 478 | // A variable that stores the above array but was casted to the type of K 479 | K[] castedReturnArray = (K[]) returnArray; 480 | // Returns the casted return array as above 481 | return castedReturnArray; 482 | } 483 | // Otherwise, let the method continue as normal 484 | else { 485 | ; 486 | } 487 | /* 488 | * A list that will store the path that will be the result of this DFS method. 489 | * It will call another helper method to help find the DFS path. 490 | */ 491 | List pathOfDFS = performDFSearch(nodeToPerformDFSFrom, nodeToPerformDFSUntil, new ArrayList()); 492 | // If there is no such path between the two given nodes FROM and TO, return an empty list (i.e. path) 493 | if (pathOfDFS == null) { 494 | // A variable that stores the return array which will be empty in this case 495 | Object[] returnArray = new Object[0]; 496 | // A variable that stores the above array but was casted to the type of K 497 | K[] castedReturnArray = (K[]) returnArray; 498 | // Returns the casted return array as above 499 | return castedReturnArray; 500 | } 501 | // Otherwise, let the method continue as normal 502 | else { 503 | ; 504 | } 505 | // A variable that stores the return array - the path between the two given nodes, found with DFS 506 | Object[] pathOfDFSInNodes = pathOfDFS.toArray(new Object[0]); 507 | // A variable that stores the above array but was casted to the type of K 508 | K[] castedPath = (K[]) pathOfDFSInNodes; 509 | // Returns the casted return array as above 510 | return castedPath; 511 | } 512 | 513 | /** 514 | * A method that finds and returns the path (i.e. a list of node names) of breadth-first search between node FROM 515 | * and node TO. It will return an empty array if no path exists between the two given nodes. The first entry of the 516 | * returned array will be the FROM node and the last value of the array will be the TO node. 517 | * 518 | * @param from A node from which the path will be found using BFS. 519 | * @param to A node to which the path will be found using BFS 520 | * @return A path between node FROM and node TO found using BFS. 521 | */ 522 | public K[] BFS(K from, K to) { 523 | // A node from which the path will be found using BFS 524 | GraphNode nodeToPerformBFSFrom = findNodeWithName(from); 525 | // A node to which the path will be found using BFS 526 | GraphNode nodeToPerformBFSTo = findNodeWithName(to); 527 | // If node FROM is null or does not exist in the graph, returns an empty list or array as no path can be found with it 528 | if (nodeToPerformBFSFrom == null) { 529 | // A variable that stores the return array which will be empty in this case 530 | Object[] returnArray = new Object[0]; 531 | // A variable that stores the above array but was casted to the type of K 532 | K[] castedReturnArray = (K[]) returnArray; 533 | // Returns the casted return array as above 534 | return castedReturnArray; 535 | } 536 | // Otherwise, let the method continue as normal 537 | else { 538 | ; 539 | } 540 | // If node TO is null or does not exist in the graph, returns an empty list or array as no path can be found with it 541 | if (nodeToPerformBFSTo == null) { 542 | // A variable that stores the return array which will be empty in this case 543 | Object[] returnArray = new Object[0]; 544 | // A variable that stores the above array but was casted to the type of K 545 | K[] castedReturnArray = (K[]) returnArray; 546 | // Returns the casted return array as above 547 | return castedReturnArray; 548 | } 549 | // Otherwise, let the method continue as normal 550 | else { 551 | ; 552 | } 553 | /* 554 | * A list that will store the path that will be the result of this BFS method. 555 | * It will call another helper method to help find and determine the BFS path. 556 | */ 557 | List pathOfBFS = performBFSearch(nodeToPerformBFSFrom, nodeToPerformBFSTo); 558 | // If there is no such path between the two given nodes FROM and TO, return an empty list (i.e. path) 559 | if (pathOfBFS == null) { 560 | // A variable that stores the return array which will be empty in this case 561 | Object[] returnArray = new Object[0]; 562 | // A variable that stores the above array but was casted to the type of K 563 | K[] castedReturnArray = (K[]) returnArray; 564 | // Returns the casted return array as above 565 | return castedReturnArray; 566 | } 567 | // Otherwise, let the method continue as normal 568 | else { 569 | ; 570 | } 571 | // A variable that stores the return array - the path between the two given nodes, found with BFS 572 | Object[] pathOfBFSInNodes = pathOfBFS.toArray(new Object[0]); 573 | // A variable that stores the above array but was casted to the type of K 574 | K[] castedPath = (K[]) pathOfBFSInNodes; 575 | // Returns the casted return array as above 576 | return castedPath; 577 | } 578 | 579 | /** 580 | * A private class that represents and creates a node in the graph. Each node will have its key (i.e. name) and 581 | * value (i.e. data). 582 | * 583 | * @author David Nguyen 584 | * @since 04/30/2023 585 | * @version 1.0 586 | */ 587 | private class GraphNode { 588 | 589 | // A field that stores this graph node's key (or name) 590 | K key; 591 | 592 | // A field that stores this graph node's value (or data) 593 | V value; 594 | 595 | // A field that stores a list of this graph node's edges (or its neighbors) 596 | List neighborsOfThisNode; 597 | 598 | /** 599 | * A constructor that creates this instance of GraphNode that takes in a key (or name) and value (or data). 600 | * 601 | * @param key Any key (or name) to create a new GraphNode with. 602 | * @param value Any value (or data) to create a new GraphNode with. 603 | */ 604 | public GraphNode(K key, V value) { 605 | // Initializes all necessary fields: 606 | this.key = key; 607 | this.value = value; 608 | this.neighborsOfThisNode = new ArrayList(); 609 | } 610 | 611 | /** 612 | * A getter method for the key (or name) of this GraphNode instance. 613 | * 614 | * @return The key (or name) of this GraphNode instance. 615 | */ 616 | private K getKey() { 617 | return this.key; 618 | } 619 | 620 | /** 621 | * A getter method for the value (or data) of this GraphNode instance. 622 | * 623 | * @return The value (or data) of this GraphNode instance. 624 | */ 625 | private V getValue() { 626 | return this.value; 627 | } 628 | 629 | /** 630 | * A getter method for the list of this GraphNode instance's neighbors. 631 | * 632 | * @return The list of this GraphNode instance's neighbors. 633 | */ 634 | private List getNeighborsList() { 635 | return this.neighborsOfThisNode; 636 | } 637 | 638 | } 639 | 640 | /** 641 | * A recursive helper method that helps perform DFS search and find its path in this Graph instance. 642 | * 643 | * @param beginningNode The node from which DFS will be performed. 644 | * @param endingNode The node to which DFS will be performed. 645 | * @param visitedNodes The list of nodes that are visited along the finding of the path. 646 | * @return The path found between beginningNode and endingNode using DFS. 647 | */ 648 | private List performDFSearch(GraphNode beginningNode, GraphNode endingNode, List visitedNodes) { 649 | // A variable that checks if the beginning node is the same as the ending node 650 | boolean checkIfBeginningEqualsEndingNode = beginningNode.equals(endingNode); 651 | // If they are equal to each other, it is the BASE CASE. Here, stops the recursion: 652 | if (checkIfBeginningEqualsEndingNode == true) { 653 | // A variable that stores the list that is also the path found by DFS from the beginningNode to the endingNode 654 | List pathFromBeginningToEnd = new ArrayList(); 655 | // A variable that stores the key of the beginning node 656 | K keyOfBeginningNode = beginningNode.getKey(); 657 | // Add the key to the path 658 | pathFromBeginningToEnd.add(keyOfBeginningNode); 659 | // Then, return the path having only one key here in the base case 660 | return pathFromBeginningToEnd; 661 | } 662 | // Otherwise, let the method continue as normal 663 | else { 664 | ; 665 | } 666 | // Add the beginningNode to the list of visited nodes 667 | visitedNodes.add(beginningNode); 668 | // A loop that iterates through the beginningNode's neighbors list to perform DFS with: 669 | for (int index = 0; index < beginningNode.getNeighborsList().size(); index = index + 1) { 670 | // A list that stores the list of neighbors of the beginningNode 671 | List neighborsOfBeginningNodeList = beginningNode.getNeighborsList(); 672 | // A variable that stores a neighbor of the above list of neighbors 673 | GraphNode neighborOfBeginningNode = neighborsOfBeginningNodeList.get(index); 674 | // If the neighbor node above is NOT already visited, then perform DFS to find a path to it: 675 | if (visitedNodes.contains(neighborOfBeginningNode) == false) { 676 | /* 677 | * A list that recursively calls this performDFSearch to find the path from the neighbor node above to 678 | * the ending node, with the visitedNodes also being accounted for: 679 | */ 680 | List pathFromBeginningToEnd = performDFSearch(neighborOfBeginningNode, endingNode, visitedNodes); 681 | /* 682 | * If the path cannot be found or does not exist, add the key of the beginning node to the path and stops 683 | * the method: 684 | */ 685 | if (pathFromBeginningToEnd != null) { 686 | // A variable that stores the key of the beginning node 687 | K keyOfBeginningNode = beginningNode.getKey(); 688 | // Add the key of the beginning node to the path above 689 | pathFromBeginningToEnd.add(0, keyOfBeginningNode); 690 | // Returns the path and stops the method and ends this instance of recursion 691 | return pathFromBeginningToEnd; 692 | } 693 | // Otherwise, let the method continue as normal 694 | else { 695 | ; 696 | } 697 | } 698 | // Otherwise, do not find a DFS path to the neighbor node: 699 | else { 700 | ; 701 | } 702 | } 703 | // At the end, if no such path can be found between beginning and ending nodes, returns a null and empty list 704 | List returnNullList = null; 705 | // Returns a null and empty list in this case 706 | return returnNullList; 707 | } 708 | 709 | /** 710 | * A recursive helper method that helps perform BFS search and find the path between the beginning node and the 711 | * ending node in this Graph instance. 712 | * 713 | * @param beginningNode The node from which DFS will be performed. 714 | * @param endingNode The node to which DFS will be performed. 715 | * @return The path found between beginningNode and endingNode using BFS. 716 | */ 717 | private List performBFSearch(GraphNode beginningNode, GraphNode endingNode) { 718 | // A list that stores another list of BFS possible search paths between the beginning and ending nodes 719 | List> listOfBFSearchPaths = new ArrayList>(); 720 | // A list that stores all the visited nodes 721 | List listOfVisitedNodes = new ArrayList(); 722 | // A list that stores the first, initial path that will be considered for BFS search 723 | List firstPathForBFSearch = new ArrayList(); 724 | // Add the beginning node to the first, initial path above 725 | firstPathForBFSearch.add(beginningNode); 726 | // Also add the first, initial path above to the list of possible BFS search paths 727 | listOfBFSearchPaths.add(firstPathForBFSearch); 728 | // A loop that iterates through the list of BFS search path and do the following: 729 | while (listOfBFSearchPaths.isEmpty() == false) { 730 | // A variable that stores a second, alternative path for BFSearch 731 | List alternativePathForBFSearch = listOfBFSearchPaths.get(0); 732 | // Remove the first path in the list of BFS search paths 733 | listOfBFSearchPaths.remove(0); 734 | // A variable that stores the current node in the graph 735 | GraphNode currentGraphNode = alternativePathForBFSearch.get(alternativePathForBFSearch.size() - 1); 736 | // A variable that checks whether the current node is the ending node 737 | boolean ifCurrentNodeIsEndingNode = currentGraphNode.equals(endingNode); 738 | // If the current node is the node ending node: 739 | if (ifCurrentNodeIsEndingNode == true) { 740 | // A list that stores the final path of the BFS search from the beginning to the ending nodes 741 | List finalPathForBFSearch = new ArrayList(); 742 | // A loop that iterates through the alternative path of the BFS to determine and find the final path for BFS 743 | for (int index = 0; index < alternativePathForBFSearch.size(); index = index + 1) { 744 | // A variable that stores the final nodes from the above alternative path to be returned later on 745 | GraphNode finalNodeInPath = alternativePathForBFSearch.get(index); 746 | /* 747 | * A variable that stores the key of the final nodes from the above alternative path to be returned 748 | * later on 749 | */ 750 | K keyOfFinalNodeInPath = finalNodeInPath.getKey(); 751 | // Add the key of the final nodes in the final path to the final path that will be returned later on 752 | finalPathForBFSearch.add(keyOfFinalNodeInPath); 753 | } 754 | // A list that stores the final path for BFS search to be returned now 755 | List finalPathForReturn = finalPathForBFSearch; 756 | // Return the above list to stop the method 757 | return finalPathForReturn; 758 | } 759 | // Otherwise, let the method continue as normal 760 | else { 761 | ; 762 | } 763 | /* 764 | * However, if the current node has not been visited, add it to the list of visited nodes and add it to 765 | * the lists of visited nodes and possible BFS paths above. 766 | */ 767 | boolean ifCurrentNodeIsVisited = listOfVisitedNodes.contains(currentGraphNode); 768 | /* 769 | * If the current node is NOT visited, add it to the list of visited nodes and add the path to it to the list 770 | * of all possible BFS paths above. 771 | */ 772 | if (ifCurrentNodeIsVisited == false) { 773 | // Add the current node to the list of visited nodes 774 | listOfVisitedNodes.add(currentGraphNode); 775 | // A variable that stores the size of the current node's neighbors list 776 | int sizeOfCurrentNodeNeighborsList = currentGraphNode.getNeighborsList().size(); 777 | // A loop that iterates through the list of the neighbors of the current node 778 | for (int index = 0; index < sizeOfCurrentNodeNeighborsList; index = index + 1) { 779 | // A variable that stores each and every neighbor of the current node 780 | GraphNode neighborOfCurrentNode = currentGraphNode.getNeighborsList().get(index); 781 | // If the neighbor has not been visited, add the path to it to the list of the possible BFS paths 782 | if (listOfVisitedNodes.contains(neighborOfCurrentNode) == false) { 783 | // A variable that stores the path from the current node to its neighbor nodes 784 | List pathToNeighborNodes = new ArrayList(alternativePathForBFSearch); 785 | // Add the neighbor of the current node to the list (or path) above 786 | pathToNeighborNodes.add(neighborOfCurrentNode); 787 | // Add the path to the neighbor nodes above to the list of all possible search paths of BFS 788 | listOfBFSearchPaths.add(pathToNeighborNodes); 789 | } 790 | // Otherwise, let the method continue as normal 791 | else { 792 | ; 793 | } 794 | } 795 | } 796 | // Otherwise, let the method continue as normal 797 | else { 798 | ; 799 | } 800 | } 801 | // At the end, if no such path can be found between beginning and ending nodes, returns a null and empty list 802 | ArrayList returnVal = null; 803 | // Returns a null and empty list in this case 804 | return returnVal; 805 | } 806 | 807 | /** 808 | * A method that helps find the node in this Graph instance with the given, specified name. It iterates through the 809 | * graph's list of nodes in order to find it. 810 | * 811 | * @param name Any name to find the node in this Graph instance with. 812 | * @return The node in this Graph instance that has the given, specified name. 813 | */ 814 | private GraphNode findNodeWithName(K name) { 815 | // A loop that iterates through the list of nodes in this Graph instance to find the exact node with the given name 816 | for (int index = 0; index < this.listOfGraphNodes.size(); index = index + 1) { 817 | // A variable that stores every node in this graph during the loop 818 | GraphNode everyNodeInGraph = this.listOfGraphNodes.get(index); 819 | // A variable that stores the key of the above node 820 | K keyOfEveryNodeInGraph = everyNodeInGraph.getKey(); 821 | // If the above, current node has its key the same as the given, specified key, return it 822 | if (keyOfEveryNodeInGraph.equals(name) == true) { 823 | // Return the node that has its key the same as the given, specified key 824 | return everyNodeInGraph; 825 | } 826 | // Otherwise, let the method continue as normal 827 | else { 828 | ; 829 | } 830 | } 831 | /* 832 | * A variable that stores the return value of null for this method if no nodes with the given name is found in 833 | * this graph instance 834 | */ 835 | GraphNode returnVal = null; 836 | // Return the null variable above in order to end the method 837 | return returnVal; 838 | } 839 | 840 | } -------------------------------------------------------------------------------- /Length3WordGraph: -------------------------------------------------------------------------------- 1 | 0 aah 875 649 589 324 150 70 50 2 1 2 | 1 aal 697 590 283 71 61 28 19 2 0 3 | 2 aas 845 819 760 654 595 477 436 408 328 288 237 74 65 53 48 23 10 1 0 4 | 3 aba 59 56 35 31 25 17 14 5 4 5 | 4 abo 66 58 16 9 5 3 6 | 5 aby 40 4 3 7 | 6 ace 366 64 63 60 57 54 44 41 37 27 15 7 8 | 7 act 49 42 39 30 24 13 6 9 | 8 add 550 36 18 11 10 9 10 | 9 ado 805 66 58 16 11 10 8 4 11 | 10 ads 552 369 65 53 48 23 11 9 8 2 12 | 11 adz 10 9 8 13 | 12 aff 554 202 45 13 14 | 13 aft 555 204 49 42 39 30 24 12 7 15 | 14 aga 59 56 35 31 25 17 16 15 3 16 | 15 age 64 63 60 57 54 44 41 37 27 16 14 6 17 | 16 ago 206 66 58 15 14 9 4 18 | 17 aha 855 59 56 35 31 25 14 3 19 | 18 aid 889 673 488 453 419 342 299 251 167 85 36 24 23 22 21 20 19 8 20 | 19 ail 777 559 523 490 254 61 28 24 23 22 21 20 18 1 21 | 20 aim 830 719 675 524 491 344 170 47 24 23 22 21 19 18 22 | 21 ain 890 859 831 778 720 676 616 455 421 395 345 302 255 171 87 62 24 23 22 20 19 18 23 | 22 air 722 492 256 24 23 21 20 19 18 24 | 23 ais 874 860 832 780 723 618 493 457 347 89 65 53 48 24 22 21 20 19 18 10 2 25 | 24 ait 861 807 781 724 619 526 458 423 348 304 257 173 90 49 42 39 30 23 22 21 20 19 18 13 7 26 | 25 ala 59 56 35 31 30 29 28 27 26 17 14 3 27 | 26 alb 30 29 28 27 25 28 | 27 ale 563 64 63 60 57 54 44 41 37 30 29 28 26 25 15 6 29 | 28 all 372 211 61 30 29 27 26 25 19 1 30 | 29 alp 52 33 30 28 27 26 25 31 | 30 alt 49 42 39 29 28 27 26 25 24 13 7 32 | 31 ama 59 56 35 34 33 32 25 17 14 3 33 | 32 ami 38 34 33 31 34 | 33 amp 809 373 52 34 32 31 29 35 | 34 amu 216 33 32 31 36 | 35 ana 59 56 40 39 38 37 36 31 25 17 14 3 37 | 36 and 217 40 39 38 37 35 18 8 38 | 37 ane 565 64 63 60 57 54 44 41 40 39 38 36 35 27 15 6 39 | 38 ani 40 39 37 36 35 32 40 | 39 ant 49 42 40 38 37 36 35 30 24 13 7 41 | 40 any 39 38 37 36 35 5 42 | 41 ape 569 64 63 60 57 54 44 42 37 27 15 6 43 | 42 apt 571 49 41 39 30 24 13 7 44 | 43 arc 574 49 48 47 46 45 44 45 | 44 are 575 378 222 64 63 60 57 54 49 48 47 46 45 43 41 37 27 15 6 46 | 45 arf 49 48 47 46 44 43 12 47 | 46 ark 379 55 51 49 48 47 45 44 43 48 | 47 arm 49 48 46 45 44 43 20 49 | 48 ars 576 226 65 53 49 47 46 45 44 43 23 10 2 50 | 49 art 577 48 47 46 45 44 43 42 39 30 24 13 7 51 | 50 ash 53 52 51 0 52 | 51 ask 794 55 53 52 50 46 53 | 52 asp 53 51 50 33 29 54 | 53 ass 227 65 52 51 50 48 23 10 2 55 | 54 ate 64 63 60 57 44 41 37 27 15 6 56 | 55 auk 897 51 46 57 | 56 ava 582 59 58 57 35 31 25 17 14 3 58 | 57 ave 230 64 63 60 58 56 54 44 41 37 27 15 6 59 | 58 avo 66 57 56 16 9 4 60 | 59 awa 802 62 61 60 56 35 31 25 17 14 3 61 | 60 awe 583 231 64 63 62 61 59 57 54 44 41 37 27 15 6 62 | 61 awl 584 62 60 59 28 19 1 63 | 62 awn 585 61 60 59 21 64 | 63 axe 64 60 57 54 44 41 37 27 15 6 65 | 64 aye 873 804 691 644 469 232 194 112 65 63 60 57 54 44 41 37 27 15 6 66 | 65 ays 113 64 53 48 23 10 2 67 | 66 azo 58 16 9 4 68 | 67 baa 102 91 76 75 74 73 72 71 70 69 68 69 | 68 bad 839 751 694 647 588 471 431 321 280 233 148 115 104 93 85 77 76 75 74 73 72 71 70 69 67 70 | 69 bag 899 841 753 696 648 515 473 432 384 323 282 234 149 105 94 86 79 76 75 74 73 72 71 70 68 67 71 | 70 bah 875 649 589 324 150 76 75 74 73 72 71 69 68 67 0 72 | 71 bal 697 590 283 80 76 75 74 73 72 70 69 68 67 1 73 | 72 ban 842 818 756 652 592 474 285 235 117 107 87 81 76 75 74 73 71 70 69 68 67 74 | 73 bar 879 844 759 594 545 476 435 386 287 236 195 119 108 76 75 74 72 71 70 69 68 67 75 | 74 bas 845 819 760 654 595 477 436 408 328 288 237 113 109 97 89 76 75 73 72 71 70 69 68 67 2 76 | 75 bat 846 820 761 699 655 596 546 478 437 409 329 289 238 196 120 110 98 90 82 76 74 73 72 71 70 69 68 67 77 | 76 bay 881 849 703 658 599 517 480 440 410 388 331 290 240 155 122 111 101 83 75 74 73 72 71 70 69 68 67 78 | 77 bed 902 851 767 661 601 442 291 241 104 93 85 83 82 81 80 79 78 68 79 | 78 bee 903 852 824 768 706 662 602 519 443 389 292 242 157 123 112 83 82 81 80 79 77 80 | 79 beg 825 769 603 444 413 105 94 86 83 82 81 80 78 77 69 81 | 80 bel 708 481 293 201 159 83 82 81 79 78 77 71 82 | 81 ben 884 853 770 709 604 483 414 333 243 160 107 87 83 82 80 79 78 77 72 83 | 82 bet 887 854 826 711 668 608 520 484 447 390 337 295 245 110 98 90 83 81 80 79 78 77 75 84 | 83 bey 451 417 340 296 248 165 111 101 82 81 80 79 78 77 76 85 | 84 bib 717 672 522 487 452 393 298 250 166 103 92 90 89 88 87 86 85 86 | 85 bid 889 673 488 453 419 342 299 251 167 104 93 90 89 88 87 86 84 77 68 18 87 | 86 big 904 858 674 615 489 394 301 253 169 105 94 90 89 88 87 85 84 79 69 88 | 87 bin 890 859 831 778 720 676 616 455 421 395 345 302 255 171 107 90 89 88 86 85 84 81 72 21 89 | 88 bio 95 90 89 87 86 85 84 90 | 89 bis 874 860 832 780 723 618 493 457 347 113 109 97 90 88 87 86 85 84 74 23 91 | 90 bit 861 807 781 724 619 526 458 423 348 304 257 173 110 98 89 88 87 86 85 84 82 75 24 92 | 91 boa 906 495 424 306 102 101 100 99 98 97 96 95 94 93 92 67 93 | 92 bob 729 678 528 496 459 396 349 307 262 125 103 101 100 99 98 97 96 95 94 93 91 84 94 | 93 bod 892 782 730 680 623 529 497 350 308 126 104 101 100 99 98 97 96 95 94 92 91 85 77 68 95 | 94 bog 784 530 498 460 398 352 264 176 127 105 101 100 99 98 97 96 95 93 92 91 86 79 69 96 | 95 boo 907 866 787 533 502 461 309 130 101 100 99 98 97 96 94 93 92 91 88 97 | 96 bop 867 788 733 627 503 462 425 353 267 131 101 100 99 98 97 95 94 93 92 91 98 | 97 bos 868 734 535 427 181 132 113 109 101 100 99 98 96 95 94 93 92 91 89 74 99 | 98 bot 869 790 735 682 628 568 536 505 463 399 354 311 182 133 110 101 100 99 97 96 95 94 93 92 91 90 82 75 100 | 99 bow 896 870 835 791 737 683 629 537 506 464 400 355 183 134 101 100 98 97 96 95 94 93 92 91 101 | 100 box 836 738 630 465 312 270 135 101 99 98 97 96 95 94 93 92 91 102 | 101 boy 792 739 401 356 313 271 136 111 100 99 98 97 96 95 94 93 92 91 83 76 103 | 102 bra 572 221 91 67 104 | 103 bub 795 744 684 634 539 357 274 185 139 111 110 109 108 107 106 105 104 92 84 105 | 104 bud 872 635 579 507 275 187 140 111 110 109 108 107 106 105 103 93 85 77 68 106 | 105 bug 837 796 686 636 508 466 402 359 276 189 111 110 109 108 107 106 104 103 94 86 79 69 107 | 106 bum 746 687 509 467 361 315 142 111 110 109 108 107 105 104 103 108 | 107 bun 798 747 688 638 540 510 403 362 316 277 191 111 110 109 108 106 105 104 103 87 81 72 109 | 108 bur 640 580 278 144 111 110 109 107 106 105 104 103 73 110 | 109 bus 641 541 511 404 113 111 110 108 107 106 105 104 103 97 89 74 111 | 110 but 800 689 642 581 542 512 405 364 317 145 111 109 108 107 106 105 104 103 98 90 82 75 112 | 111 buy 318 110 109 108 107 106 105 104 103 101 83 76 113 | 112 bye 873 804 691 644 469 232 194 113 78 64 114 | 113 bys 112 109 97 89 74 65 115 | 114 cab 838 750 692 513 429 406 383 279 147 139 125 122 121 120 119 118 117 116 115 116 | 115 cad 839 751 694 647 588 471 431 321 280 233 148 140 126 122 121 120 119 118 117 116 114 68 117 | 116 cam 877 755 651 591 433 385 326 284 152 146 142 122 121 120 119 118 117 115 114 118 | 117 can 842 818 756 652 592 474 285 235 129 122 121 120 119 118 116 115 114 72 119 | 118 cap 900 878 843 758 698 653 593 516 475 434 327 286 153 143 131 122 121 120 119 117 116 115 114 120 | 119 car 879 844 759 594 545 476 435 386 287 236 195 144 122 121 120 118 117 116 115 114 73 121 | 120 cat 846 820 761 699 655 596 546 478 437 409 329 289 238 196 145 133 122 121 119 118 117 116 115 114 75 122 | 121 caw 880 847 823 764 701 656 597 479 438 387 330 154 134 122 120 119 118 117 116 115 114 123 | 122 cay 881 849 703 658 599 517 480 440 410 388 331 290 240 155 138 136 121 120 119 118 117 116 115 114 76 124 | 123 cee 903 852 824 768 706 662 602 519 443 389 292 242 157 141 78 125 | 124 chi 610 418 297 126 | 125 cob 729 678 528 496 459 396 349 307 262 139 137 136 135 134 133 132 131 130 129 128 127 126 114 92 127 | 126 cod 892 782 730 680 623 529 497 350 308 140 137 136 135 134 133 132 131 130 129 128 127 125 115 93 128 | 127 cog 784 530 498 460 398 352 264 176 137 136 135 134 133 132 131 130 129 128 126 125 94 129 | 128 col 731 626 499 177 137 136 135 134 133 132 131 130 129 127 126 125 130 | 129 con 894 865 834 786 732 501 377 266 220 179 137 136 135 134 133 132 131 130 128 127 126 125 117 131 | 130 coo 907 866 787 533 502 461 309 137 136 135 134 133 132 131 129 128 127 126 125 95 132 | 131 cop 867 788 733 627 503 462 425 353 267 143 137 136 135 134 133 132 130 129 128 127 126 125 118 96 133 | 132 cos 868 734 535 427 181 137 136 135 134 133 131 130 129 128 127 126 125 97 134 | 133 cot 869 790 735 682 628 568 536 505 463 399 354 311 182 145 137 136 135 134 132 131 130 129 128 127 126 125 120 98 135 | 134 cow 896 870 835 791 737 683 629 537 506 464 400 355 183 137 136 135 133 132 131 130 129 128 127 126 125 121 99 136 | 135 cox 836 738 630 465 312 270 137 136 134 133 132 131 130 129 128 127 126 125 100 137 | 136 coy 792 739 401 356 313 271 138 137 135 134 133 132 131 130 129 128 127 126 125 122 101 138 | 137 coz 136 135 134 133 132 131 130 129 128 127 126 125 139 | 138 cry 871 793 632 273 184 136 122 140 | 139 cub 795 744 684 634 539 357 274 185 145 144 143 142 141 140 125 114 103 141 | 140 cud 872 635 579 507 275 187 145 144 143 142 141 139 126 115 104 142 | 141 cue 745 685 428 358 188 145 144 143 142 140 139 123 143 | 142 cum 746 687 509 467 361 315 146 145 144 143 141 140 139 116 106 144 | 143 cup 898 799 748 639 363 193 145 144 142 141 140 139 131 118 145 | 144 cur 640 580 278 145 143 142 141 140 139 119 108 146 | 145 cut 800 689 642 581 542 512 405 364 317 144 143 142 141 140 139 133 120 110 147 | 146 cwm 142 116 148 | 147 dab 838 750 692 513 429 406 383 279 185 166 156 155 154 153 152 151 150 149 148 114 149 | 148 dad 839 751 694 647 588 471 431 321 280 233 187 167 155 154 153 152 151 150 149 147 115 68 150 | 149 dag 899 841 753 696 648 515 473 432 384 323 282 234 189 176 169 155 154 153 152 151 150 148 147 69 151 | 150 dah 875 649 589 324 155 154 153 152 151 149 148 147 70 0 152 | 151 dak 876 544 155 154 153 152 150 149 148 147 153 | 152 dam 877 755 651 591 433 385 326 284 178 170 155 154 153 151 150 149 148 147 116 154 | 153 dap 900 878 843 758 698 653 593 516 475 434 327 286 193 172 155 154 152 151 150 149 148 147 118 155 | 154 daw 880 847 823 764 701 656 597 479 438 387 330 183 163 155 153 152 151 150 149 148 147 121 156 | 155 day 881 849 703 658 599 517 480 440 410 388 331 290 240 184 165 154 153 152 151 150 149 148 147 122 76 157 | 156 deb 850 659 518 185 166 165 164 163 162 161 160 159 158 157 147 158 | 157 dee 903 852 824 768 706 662 602 519 443 389 292 242 194 188 175 168 165 164 163 162 161 160 159 158 156 123 78 159 | 158 dei 707 664 445 190 165 164 163 162 161 160 159 157 156 160 | 159 del 708 481 293 201 177 165 164 163 162 161 160 158 157 156 80 161 | 160 den 884 853 770 709 604 483 414 333 243 191 179 171 165 164 163 162 161 159 158 157 156 81 162 | 161 des 886 667 607 553 336 181 165 164 163 162 160 159 158 157 156 163 | 162 dev 669 449 165 164 163 161 160 159 158 157 156 164 | 163 dew 888 771 712 609 521 485 392 338 247 183 165 164 162 161 160 159 158 157 156 154 165 | 164 dex 827 713 670 450 416 339 165 163 162 161 160 159 158 157 156 166 | 165 dey 451 417 340 296 248 184 164 163 162 161 160 159 158 157 156 155 83 167 | 166 dib 717 672 522 487 452 393 298 250 185 173 172 171 170 169 168 167 156 147 84 168 | 167 did 889 673 488 453 419 342 299 251 187 173 172 171 170 169 168 166 148 85 18 169 | 168 die 829 776 614 454 343 300 252 194 188 175 173 172 171 170 169 167 166 157 170 | 169 dig 904 858 674 615 489 394 301 253 189 176 173 172 171 170 168 167 166 149 86 171 | 170 dim 830 719 675 524 491 344 178 173 172 171 169 168 167 166 152 20 172 | 171 din 890 859 831 778 720 676 616 455 421 395 345 302 255 191 179 173 172 170 169 168 167 166 160 87 21 173 | 172 dip 905 891 779 721 677 617 525 456 422 346 303 193 173 171 170 169 168 167 166 153 174 | 173 dit 861 807 781 724 619 526 458 423 348 304 257 182 172 171 170 169 168 167 166 90 24 175 | 174 doc 679 186 183 182 181 180 179 178 177 176 175 176 | 175 doe 863 833 783 681 397 351 263 194 188 183 182 181 180 179 178 177 176 174 168 157 177 | 176 dog 784 530 498 460 398 352 264 189 183 182 181 180 179 178 177 175 174 169 149 127 94 178 | 177 dol 731 626 499 183 182 181 180 179 178 176 175 174 159 128 179 | 178 dom 893 785 532 500 183 182 181 180 179 177 176 175 174 170 152 180 | 179 don 894 865 834 786 732 501 377 266 220 191 183 182 181 180 178 177 176 175 174 171 160 129 181 | 180 dor 789 534 504 426 310 268 183 182 181 179 178 177 176 175 174 182 | 181 dos 868 734 535 427 183 182 180 179 178 177 176 175 174 161 132 97 183 | 182 dot 869 790 735 682 628 568 536 505 463 399 354 311 183 181 180 179 178 177 176 175 174 173 133 98 184 | 183 dow 896 870 835 791 737 683 629 537 506 464 400 355 182 181 180 179 178 177 176 175 174 163 154 134 99 185 | 184 dry 871 793 632 273 165 155 138 186 | 185 dub 795 744 684 634 539 357 274 193 192 191 190 189 188 187 186 166 156 147 139 103 187 | 186 duc 193 192 191 190 189 188 187 185 174 188 | 187 dud 872 635 579 507 275 193 192 191 190 189 188 186 185 167 148 140 104 189 | 188 due 745 685 428 358 194 193 192 191 190 189 187 186 185 175 168 157 141 190 | 189 dug 837 796 686 636 508 466 402 359 276 193 192 191 190 188 187 186 185 176 169 149 105 191 | 190 dui 797 193 192 191 189 188 187 186 185 158 192 | 191 dun 798 747 688 638 540 510 403 362 316 277 193 192 190 189 188 187 186 185 179 171 160 107 193 | 192 duo 193 191 190 189 188 187 186 185 194 | 193 dup 898 799 748 639 363 192 191 190 189 188 187 186 185 172 153 143 195 | 194 dye 873 804 691 644 469 232 188 175 168 157 112 64 196 | 195 ear 879 844 759 594 545 476 435 386 287 236 225 197 196 119 73 197 | 196 eat 846 820 761 699 655 596 546 478 437 409 329 289 238 204 197 195 120 75 198 | 197 eau 821 762 700 216 199 196 195 199 | 198 ebb 200 | 199 ecu 216 197 201 | 200 edh 229 202 | 201 eel 708 481 293 211 159 80 203 | 202 eff 554 209 204 203 12 204 | 203 efs 370 227 226 219 215 213 204 202 205 | 204 eft 555 203 202 196 13 206 | 205 egg 223 218 206 207 | 206 ego 205 16 208 | 207 eke 808 561 232 231 230 222 214 209 | 208 eld 562 217 213 212 211 210 209 210 | 209 elf 213 212 211 210 208 202 211 | 210 elk 371 213 212 211 209 208 212 | 211 ell 372 213 212 210 209 208 201 28 213 | 212 elm 213 211 210 209 208 214 | 213 els 227 226 219 215 212 211 210 209 208 203 215 | 214 eme 232 231 230 222 216 215 207 216 | 215 ems 564 227 226 219 216 214 213 203 217 | 216 emu 215 214 199 197 34 218 | 217 end 219 218 208 36 219 | 218 eng 223 219 217 205 220 | 219 ens 810 566 376 227 226 218 217 215 213 203 221 | 220 eon 894 865 834 786 732 501 377 266 224 179 129 222 | 221 era 572 228 226 225 224 223 222 102 223 | 222 ere 575 378 232 231 230 226 225 224 223 221 214 207 44 224 | 223 erg 226 225 224 222 221 218 205 225 | 224 ern 814 226 225 223 222 221 220 226 | 225 err 226 224 223 222 221 195 227 | 226 ers 576 227 225 224 223 222 221 219 215 213 203 48 228 | 227 ess 226 219 215 213 203 53 229 | 228 eta 816 229 221 230 | 229 eth 538 228 200 231 | 230 eve 232 231 222 214 207 57 232 | 231 ewe 583 232 230 222 214 207 60 233 | 232 eye 873 804 691 644 469 231 230 222 214 207 194 112 64 234 | 233 fad 839 751 694 647 588 471 431 321 280 275 251 241 240 239 238 237 236 235 234 148 115 68 235 | 234 fag 899 841 753 696 648 515 473 432 384 323 282 276 264 253 240 239 238 237 236 235 233 149 69 236 | 235 fan 842 818 756 652 592 474 285 277 266 255 243 240 239 238 237 236 234 233 117 72 237 | 236 far 879 844 759 594 545 476 435 386 287 278 268 256 244 240 239 238 237 235 234 233 195 119 73 238 | 237 fas 845 819 760 654 595 477 436 408 328 288 240 239 238 236 235 234 233 74 2 239 | 238 fat 846 820 761 699 655 596 546 478 437 409 329 289 257 245 240 239 237 236 235 234 233 196 120 75 240 | 239 fax 901 848 765 702 657 598 439 270 258 240 238 237 236 235 234 233 241 | 240 fay 881 849 703 658 599 517 480 440 410 388 331 290 273 271 261 248 239 238 237 236 235 234 233 155 122 76 242 | 241 fed 902 851 767 661 601 442 291 275 251 249 248 247 246 245 244 243 242 233 77 243 | 242 fee 903 852 824 768 706 662 602 519 443 389 292 263 252 249 248 247 246 245 244 243 241 157 123 78 244 | 243 fen 884 853 770 709 604 483 414 333 277 266 255 249 248 247 246 245 244 242 241 235 160 81 245 | 244 fer 710 606 335 278 268 256 249 248 247 246 245 243 242 241 236 246 | 245 fet 887 854 826 711 668 608 520 484 447 390 337 295 257 249 248 247 246 244 243 242 241 238 82 247 | 246 feu 448 391 269 260 249 248 247 245 244 243 242 241 248 | 247 few 888 771 712 609 521 485 392 338 249 248 246 245 244 243 242 241 163 249 | 248 fey 451 417 340 296 273 271 261 249 247 246 245 244 243 242 241 240 165 83 250 | 249 fez 259 248 247 246 245 244 243 242 241 251 | 250 fib 717 672 522 487 452 393 298 274 262 259 258 257 256 255 254 253 252 251 166 84 252 | 251 fid 889 673 488 453 419 342 299 275 259 258 257 256 255 254 253 252 250 241 233 167 85 18 253 | 252 fie 829 776 614 454 343 300 263 259 258 257 256 255 254 253 251 250 242 168 254 | 253 fig 904 858 674 615 489 394 301 276 264 259 258 257 256 255 254 252 251 250 234 169 86 255 | 254 fil 777 559 523 490 259 258 257 256 255 253 252 251 250 19 256 | 255 fin 890 859 831 778 720 676 616 455 421 395 345 302 277 266 259 258 257 256 254 253 252 251 250 243 235 171 87 21 257 | 256 fir 722 492 278 268 259 258 257 255 254 253 252 251 250 244 236 22 258 | 257 fit 861 807 781 724 619 526 458 423 348 304 259 258 256 255 254 253 252 251 250 245 238 173 90 24 259 | 258 fix 725 621 527 494 270 259 257 256 255 254 253 252 251 250 239 260 | 259 fiz 862 258 257 256 255 254 253 252 251 250 249 261 | 260 flu 269 261 246 262 | 261 fly 728 622 273 271 260 248 240 263 | 262 fob 729 678 528 496 459 396 349 307 274 271 270 269 268 267 266 265 264 263 250 125 92 264 | 263 foe 863 833 783 681 397 351 271 270 269 268 267 266 265 264 262 252 242 175 265 | 264 fog 784 530 498 460 398 352 276 271 270 269 268 267 266 265 263 262 253 234 176 127 94 266 | 265 foh 624 567 531 271 270 269 268 267 266 264 263 262 267 | 266 fon 894 865 834 786 732 501 377 277 271 270 269 268 267 265 264 263 262 255 243 235 220 179 129 268 | 267 fop 867 788 733 627 503 462 425 353 271 270 269 268 266 265 264 263 262 131 96 269 | 268 for 789 534 504 426 310 278 271 270 269 267 266 265 264 263 262 256 244 236 180 270 | 269 fou 895 736 271 270 268 267 266 265 264 263 262 260 246 271 | 270 fox 836 738 630 465 312 271 269 268 267 266 265 264 263 262 258 239 135 100 272 | 271 foy 792 739 401 356 313 273 270 269 268 267 266 265 264 263 262 261 248 240 136 101 273 | 272 fro 631 273 274 | 273 fry 871 793 632 272 271 261 248 240 184 138 275 | 274 fub 795 744 684 634 539 357 278 277 276 275 262 250 185 139 103 276 | 275 fud 872 635 579 507 278 277 276 274 251 241 233 187 140 104 277 | 276 fug 837 796 686 636 508 466 402 359 278 277 275 274 264 253 234 189 105 278 | 277 fun 798 747 688 638 540 510 403 362 316 278 276 275 274 266 255 243 235 191 107 279 | 278 fur 640 580 277 276 275 274 268 256 244 236 144 108 280 | 279 gab 838 750 692 513 429 406 383 307 298 290 289 288 287 286 285 284 283 282 281 280 147 114 281 | 280 gad 839 751 694 647 588 471 431 321 308 299 291 290 289 288 287 286 285 284 283 282 281 279 233 148 115 68 282 | 281 gae 840 752 695 514 472 407 322 300 292 290 289 288 287 286 285 284 283 282 280 279 283 | 282 gag 899 841 753 696 648 515 473 432 384 323 301 290 289 288 287 286 285 284 283 281 280 279 234 149 69 284 | 283 gal 697 590 314 293 290 289 288 287 286 285 284 282 281 280 279 71 1 285 | 284 gam 877 755 651 591 433 385 326 319 315 294 290 289 288 287 286 285 283 282 281 280 279 152 116 286 | 285 gan 842 818 756 652 592 474 316 302 290 289 288 287 286 284 283 282 281 280 279 235 117 72 287 | 286 gap 900 878 843 758 698 653 593 516 475 434 327 320 303 290 289 288 287 285 284 283 282 281 280 279 153 118 288 | 287 gar 879 844 759 594 545 476 435 386 310 290 289 288 286 285 284 283 282 281 280 279 236 195 119 73 289 | 288 gas 845 819 760 654 595 477 436 408 328 290 289 287 286 285 284 283 282 281 280 279 237 74 2 290 | 289 gat 846 820 761 699 655 596 546 478 437 409 329 317 311 304 295 290 288 287 286 285 284 283 282 281 280 279 238 196 120 75 291 | 290 gay 881 849 703 658 599 517 480 440 410 388 331 318 313 296 289 288 287 286 285 284 283 282 281 280 279 240 155 122 76 292 | 291 ged 902 851 767 661 601 442 308 299 296 295 294 293 292 280 241 77 293 | 292 gee 903 852 824 768 706 662 602 519 443 389 300 296 295 294 293 291 281 242 157 123 78 294 | 293 gel 708 481 314 296 295 294 292 291 283 201 159 80 295 | 294 gem 665 482 332 319 315 296 295 293 292 291 284 296 | 295 get 887 854 826 711 668 608 520 484 447 390 337 317 311 304 296 294 293 292 291 289 245 82 297 | 296 gey 451 417 340 318 313 295 294 293 292 291 290 248 165 83 298 | 297 ghi 610 418 124 299 | 298 gib 717 672 522 487 452 393 307 304 303 302 301 300 299 279 250 166 84 300 | 299 gid 889 673 488 453 419 342 308 304 303 302 301 300 298 291 280 251 167 85 18 301 | 300 gie 829 776 614 454 343 304 303 302 301 299 298 292 281 252 168 302 | 301 gig 904 858 674 615 489 394 304 303 302 300 299 298 282 253 169 86 303 | 302 gin 890 859 831 778 720 676 616 455 421 395 345 316 304 303 301 300 299 298 285 255 171 87 21 304 | 303 gip 905 891 779 721 677 617 525 456 422 346 320 304 302 301 300 299 298 286 172 305 | 304 git 861 807 781 724 619 526 458 423 348 317 311 303 302 301 300 299 298 295 289 257 173 90 24 306 | 305 gnu 307 | 306 goa 906 495 424 313 312 311 310 309 308 307 91 308 | 307 gob 729 678 528 496 459 396 349 313 312 311 310 309 308 306 298 279 262 125 92 309 | 308 god 892 782 730 680 623 529 497 350 313 312 311 310 309 307 306 299 291 280 126 93 310 | 309 goo 907 866 787 533 502 461 313 312 311 310 308 307 306 130 95 311 | 310 gor 789 534 504 426 313 312 311 309 308 307 306 287 268 180 312 | 311 got 869 790 735 682 628 568 536 505 463 399 354 317 313 312 310 309 308 307 306 304 295 289 182 133 98 313 | 312 gox 836 738 630 465 313 311 310 309 308 307 306 270 135 100 314 | 313 goy 792 739 401 356 318 312 311 310 309 308 307 306 296 290 271 136 101 315 | 314 gul 637 318 317 316 315 293 283 316 | 315 gum 746 687 509 467 361 319 318 317 316 314 294 284 142 106 317 | 316 gun 798 747 688 638 540 510 403 362 318 317 315 314 302 285 277 191 107 318 | 317 gut 800 689 642 581 542 512 405 364 318 316 315 314 311 304 295 289 145 110 319 | 318 guy 317 316 315 314 313 296 290 111 320 | 319 gym 320 315 294 284 321 | 320 gyp 365 319 303 286 322 | 321 had 839 751 694 647 588 471 431 350 342 331 330 329 328 327 326 325 324 323 322 280 233 148 115 68 323 | 322 hae 840 752 695 514 472 407 358 351 343 331 330 329 328 327 326 325 324 323 321 281 324 | 323 hag 899 841 753 696 648 515 473 432 384 359 352 331 330 329 328 327 326 325 324 322 321 282 234 149 69 325 | 324 hah 875 649 589 360 331 330 329 328 327 326 325 323 322 321 150 70 0 326 | 325 haj 754 650 331 330 329 328 327 326 324 323 322 321 327 | 326 ham 877 755 651 591 433 385 361 344 332 331 330 329 328 327 325 324 323 322 321 284 152 116 328 | 327 hap 900 878 843 758 698 653 593 516 475 434 365 363 353 346 334 331 330 329 328 326 325 324 323 322 321 286 153 118 329 | 328 has 845 819 760 654 595 477 436 408 347 336 331 330 329 327 326 325 324 323 322 321 288 237 74 2 330 | 329 hat 846 820 761 699 655 596 546 478 437 409 364 354 348 337 331 330 328 327 326 325 324 323 322 321 289 238 196 120 75 331 | 330 haw 880 847 823 764 701 656 597 479 438 387 355 338 331 329 328 327 326 325 324 323 322 321 154 121 332 | 331 hay 881 849 703 658 599 517 480 440 410 388 356 340 330 329 328 327 326 325 324 323 322 321 290 240 155 122 76 333 | 332 hem 665 482 361 344 340 339 338 337 336 335 334 333 326 294 334 | 333 hen 884 853 770 709 604 483 414 362 345 340 339 338 337 336 335 334 332 243 160 81 335 | 334 hep 885 666 605 415 365 363 353 346 340 339 338 337 336 335 333 332 327 336 | 335 her 710 606 340 339 338 337 336 334 333 332 244 337 | 336 hes 886 667 607 553 347 340 339 338 337 335 334 333 332 328 161 338 | 337 het 887 854 826 711 668 608 520 484 447 390 364 354 348 340 339 338 336 335 334 333 332 329 295 245 82 339 | 338 hew 888 771 712 609 521 485 392 355 340 339 337 336 335 334 333 332 330 247 163 340 | 339 hex 827 713 670 450 416 340 338 337 336 335 334 333 332 164 341 | 340 hey 451 417 356 339 338 337 336 335 334 333 332 331 296 248 165 83 342 | 341 hic 775 718 613 348 347 346 345 344 343 342 343 | 342 hid 889 673 488 453 419 350 348 347 346 345 344 343 341 321 299 251 167 85 18 344 | 343 hie 829 776 614 454 358 351 348 347 346 345 344 342 341 322 300 252 168 345 | 344 him 830 719 675 524 491 361 348 347 346 345 343 342 341 332 326 170 20 346 | 345 hin 890 859 831 778 720 676 616 455 421 395 362 348 347 346 344 343 342 341 333 302 255 171 87 21 347 | 346 hip 905 891 779 721 677 617 525 456 422 365 363 353 348 347 345 344 343 342 341 334 327 303 172 348 | 347 his 874 860 832 780 723 618 493 457 348 346 345 344 343 342 341 336 328 89 23 349 | 348 hit 861 807 781 724 619 526 458 423 364 354 347 346 345 344 343 342 341 337 329 304 257 173 90 24 350 | 349 hob 729 678 528 496 459 396 357 356 355 354 353 352 351 350 307 262 125 92 351 | 350 hod 892 782 730 680 623 529 497 356 355 354 353 352 351 349 342 321 308 126 93 352 | 351 hoe 863 833 783 681 397 358 356 355 354 353 352 350 349 343 322 263 175 353 | 352 hog 784 530 498 460 398 359 356 355 354 353 351 350 349 323 264 176 127 94 354 | 353 hop 867 788 733 627 503 462 425 365 363 356 355 354 352 351 350 349 346 334 327 267 131 96 355 | 354 hot 869 790 735 682 628 568 536 505 463 399 364 356 355 353 352 351 350 349 348 337 329 311 182 133 98 356 | 355 how 896 870 835 791 737 683 629 537 506 464 400 356 354 353 352 351 350 349 338 330 183 134 99 357 | 356 hoy 792 739 401 355 354 353 352 351 350 349 340 331 313 271 136 101 358 | 357 hub 795 744 684 634 539 364 363 362 361 360 359 358 349 274 185 139 103 359 | 358 hue 745 685 428 364 363 362 361 360 359 357 351 343 322 188 141 360 | 359 hug 837 796 686 636 508 466 402 364 363 362 361 360 358 357 352 323 276 189 105 361 | 360 huh 364 363 362 361 359 358 357 324 362 | 361 hum 746 687 509 467 364 363 362 360 359 358 357 344 332 326 315 142 106 363 | 362 hun 798 747 688 638 540 510 403 364 363 361 360 359 358 357 345 333 316 277 191 107 364 | 363 hup 898 799 748 639 365 364 362 361 360 359 358 357 353 346 334 327 193 143 365 | 364 hut 800 689 642 581 542 512 405 363 362 361 360 359 358 357 354 348 337 329 317 145 110 366 | 365 hyp 363 353 346 334 327 320 367 | 366 ice 378 368 367 6 368 | 367 ich 368 366 369 | 368 icy 382 367 366 370 | 369 ids 552 381 376 370 10 371 | 370 ifs 381 376 369 203 372 | 371 ilk 379 374 372 210 373 | 372 ill 371 211 28 374 | 373 imp 809 33 375 | 374 ink 379 376 375 371 376 | 375 inn 377 376 374 377 | 376 ins 810 566 381 375 374 370 369 219 378 | 377 ion 894 865 834 786 732 501 375 266 220 179 129 379 | 378 ire 575 379 366 222 44 380 | 379 irk 378 374 371 46 381 | 380 ism 382 | 381 its 817 376 370 369 383 | 382 ivy 368 384 | 383 jab 838 750 692 513 429 406 396 393 388 387 386 385 384 279 147 114 385 | 384 jag 899 841 753 696 648 515 473 432 402 398 394 388 387 386 385 383 323 282 234 149 69 386 | 385 jam 877 755 651 591 433 388 387 386 384 383 326 284 152 116 387 | 386 jar 879 844 759 594 545 476 435 388 387 385 384 383 287 236 195 119 73 388 | 387 jaw 880 847 823 764 701 656 597 479 438 400 392 388 386 385 384 383 330 154 121 389 | 388 jay 881 849 703 658 599 517 480 440 410 401 387 386 385 384 383 331 290 240 155 122 76 390 | 389 jee 903 852 824 768 706 662 602 519 443 397 392 391 390 292 242 157 123 78 391 | 390 jet 887 854 826 711 668 608 520 484 447 405 399 392 391 389 337 295 245 82 392 | 391 jeu 448 392 390 389 246 393 | 392 jew 888 771 712 609 521 485 400 391 390 389 387 338 247 163 394 | 393 jib 717 672 522 487 452 396 395 394 383 298 250 166 84 395 | 394 jig 904 858 674 615 489 402 398 395 393 384 301 253 169 86 396 | 395 jin 890 859 831 778 720 676 616 455 421 403 394 393 345 302 255 171 87 21 397 | 396 job 729 678 528 496 459 401 400 399 398 397 393 383 349 307 262 125 92 398 | 397 joe 863 833 783 681 401 400 399 398 396 389 351 263 175 399 | 398 jog 784 530 498 460 402 401 400 399 397 396 394 384 352 264 176 127 94 400 | 399 jot 869 790 735 682 628 568 536 505 463 405 401 400 398 397 396 390 354 311 182 133 98 401 | 400 jow 896 870 835 791 737 683 629 537 506 464 401 399 398 397 396 392 387 355 183 134 99 402 | 401 joy 792 739 400 399 398 397 396 388 356 313 271 136 101 403 | 402 jug 837 796 686 636 508 466 405 404 403 398 394 384 359 276 189 105 404 | 403 jun 798 747 688 638 540 510 405 404 402 395 362 316 277 191 107 405 | 404 jus 641 541 511 405 403 402 109 406 | 405 jut 800 689 642 581 542 512 404 403 402 399 390 364 317 145 110 407 | 406 kab 838 750 692 513 429 410 409 408 407 383 279 147 114 408 | 407 kae 840 752 695 514 472 428 410 409 408 406 322 281 409 | 408 kas 845 819 760 654 595 477 436 427 410 409 407 406 328 288 237 74 2 410 | 409 kat 846 820 761 699 655 596 546 478 437 423 410 408 407 406 329 289 238 196 120 75 411 | 410 kay 881 849 703 658 599 517 480 440 417 409 408 407 406 388 331 290 240 155 122 76 412 | 411 kea 882 766 704 600 441 424 417 416 415 414 413 412 413 | 412 kef 663 420 417 416 415 414 413 411 414 | 413 keg 825 769 603 444 417 416 415 414 412 411 79 415 | 414 ken 884 853 770 709 604 483 421 417 416 415 413 412 411 333 243 160 81 416 | 415 kep 885 666 605 425 422 417 416 414 413 412 411 334 417 | 416 kex 827 713 670 450 417 415 414 413 412 411 339 164 418 | 417 key 451 416 415 414 413 412 411 410 340 296 248 165 83 419 | 418 khi 610 297 124 420 | 419 kid 889 673 488 453 423 422 421 420 342 299 251 167 85 18 421 | 420 kif 423 422 421 419 412 422 | 421 kin 890 859 831 778 720 676 616 455 423 422 420 419 414 395 345 302 255 171 87 21 423 | 422 kip 905 891 779 721 677 617 525 456 425 423 421 420 419 415 346 303 172 424 | 423 kit 861 807 781 724 619 526 458 422 421 420 419 409 348 304 257 173 90 24 425 | 424 koa 906 495 427 426 425 411 306 91 426 | 425 kop 867 788 733 627 503 462 427 426 424 422 415 353 267 131 96 427 | 426 kor 789 534 504 427 425 424 310 268 180 428 | 427 kos 868 734 535 426 425 424 408 181 132 97 429 | 428 kue 745 685 407 358 188 141 430 | 429 lab 838 750 692 513 459 452 440 439 438 437 436 435 434 433 432 431 430 406 383 279 147 114 431 | 430 lac 693 587 470 440 439 438 437 436 435 434 433 432 431 429 432 | 431 lad 839 751 694 647 588 471 453 442 440 439 438 437 436 435 434 433 432 430 429 321 280 233 148 115 68 433 | 432 lag 899 841 753 696 648 515 473 466 460 444 440 439 438 437 436 435 434 433 431 430 429 384 323 282 234 149 69 434 | 433 lam 877 755 651 591 467 440 439 438 437 436 435 434 432 431 430 429 385 326 284 152 116 435 | 434 lap 900 878 843 758 698 653 593 516 475 462 456 440 439 438 437 436 435 433 432 431 430 429 327 286 153 118 436 | 435 lar 879 844 759 594 545 476 440 439 438 437 436 434 433 432 431 430 429 386 287 236 195 119 73 437 | 436 las 845 819 760 654 595 477 457 440 439 438 437 435 434 433 432 431 430 429 408 328 288 237 74 2 438 | 437 lat 846 820 761 699 655 596 546 478 463 458 447 440 439 438 436 435 434 433 432 431 430 429 409 329 289 238 196 120 75 439 | 438 law 880 847 823 764 701 656 597 479 464 440 439 437 436 435 434 433 432 431 430 429 387 330 154 121 440 | 439 lax 901 848 765 702 657 598 468 465 450 440 438 437 436 435 434 433 432 431 430 429 239 441 | 440 lay 881 849 703 658 599 517 480 451 439 438 437 436 435 434 433 432 431 430 429 410 388 331 290 240 155 122 76 442 | 441 lea 882 766 704 600 451 450 449 448 447 446 445 444 443 442 411 443 | 442 led 902 851 767 661 601 453 451 450 449 448 447 446 445 444 443 441 431 291 241 77 444 | 443 lee 903 852 824 768 706 662 602 519 469 454 451 450 449 448 447 446 445 444 442 441 389 292 242 157 123 78 445 | 444 leg 825 769 603 466 460 451 450 449 448 447 446 445 443 442 441 432 413 79 446 | 445 lei 707 664 451 450 449 448 447 446 444 443 442 441 158 447 | 446 lek 451 450 449 448 447 445 444 443 442 441 448 | 447 let 887 854 826 711 668 608 520 484 463 458 451 450 449 448 446 445 444 443 442 441 437 390 337 295 245 82 449 | 448 leu 451 450 449 447 446 445 444 443 442 441 391 246 450 | 449 lev 669 451 450 448 447 446 445 444 443 442 441 162 451 | 450 lex 827 713 670 468 465 451 449 448 447 446 445 444 443 442 441 439 416 339 164 452 | 451 ley 450 449 448 447 446 445 444 443 442 441 440 417 340 296 248 165 83 453 | 452 lib 717 672 522 487 459 458 457 456 455 454 453 429 393 298 250 166 84 454 | 453 lid 889 673 488 458 457 456 455 454 452 442 431 419 342 299 251 167 85 18 455 | 454 lie 829 776 614 469 458 457 456 455 453 452 443 343 300 252 168 456 | 455 lin 890 859 831 778 720 676 616 458 457 456 454 453 452 421 395 345 302 255 171 87 21 457 | 456 lip 905 891 779 721 677 617 525 462 458 457 455 454 453 452 434 422 346 303 172 458 | 457 lis 874 860 832 780 723 618 493 458 456 455 454 453 452 436 347 89 23 459 | 458 lit 861 807 781 724 619 526 463 457 456 455 454 453 452 447 437 423 348 304 257 173 90 24 460 | 459 lob 729 678 528 496 465 464 463 462 461 460 452 429 396 349 307 262 125 92 461 | 460 log 784 530 498 466 465 464 463 462 461 459 444 432 398 352 264 176 127 94 462 | 461 loo 907 866 787 533 502 465 464 463 462 460 459 309 130 95 463 | 462 lop 867 788 733 627 503 465 464 463 461 460 459 456 434 425 353 267 131 96 464 | 463 lot 869 790 735 682 628 568 536 505 465 464 462 461 460 459 458 447 437 399 354 311 182 133 98 465 | 464 low 896 870 835 791 737 683 629 537 506 465 463 462 461 460 459 438 400 355 183 134 99 466 | 465 lox 836 738 630 468 464 463 462 461 460 459 450 439 312 270 135 100 467 | 466 lug 837 796 686 636 508 468 467 460 444 432 402 359 276 189 105 468 | 467 lum 746 687 509 468 466 433 361 315 142 106 469 | 468 lux 801 467 466 465 450 439 470 | 469 lye 873 804 691 644 454 443 232 194 112 64 471 | 470 mac 693 587 480 479 478 477 476 475 474 473 472 471 430 472 | 471 mad 839 751 694 647 588 507 497 488 480 479 478 477 476 475 474 473 472 470 431 321 280 233 148 115 68 473 | 472 mae 840 752 695 514 480 479 478 477 476 475 474 473 471 470 407 322 281 474 | 473 mag 899 841 753 696 648 515 508 498 489 480 479 478 477 476 475 474 472 471 470 432 384 323 282 234 149 69 475 | 474 man 842 818 756 652 592 510 501 483 480 479 478 477 476 475 473 472 471 470 285 235 117 72 476 | 475 map 900 878 843 758 698 653 593 516 503 480 479 478 477 476 474 473 472 471 470 434 327 286 153 118 477 | 476 mar 879 844 759 594 545 504 492 480 479 478 477 475 474 473 472 471 470 435 386 287 236 195 119 73 478 | 477 mas 845 819 760 654 595 511 493 480 479 478 476 475 474 473 472 471 470 436 408 328 288 237 74 2 479 | 478 mat 846 820 761 699 655 596 546 512 505 484 480 479 477 476 475 474 473 472 471 470 437 409 329 289 238 196 120 75 480 | 479 maw 880 847 823 764 701 656 597 506 485 480 478 477 476 475 474 473 472 471 470 438 387 330 154 121 481 | 480 may 881 849 703 658 599 517 479 478 477 476 475 474 473 472 471 470 440 410 388 331 290 240 155 122 76 482 | 481 mel 708 499 490 485 484 483 482 293 201 159 80 483 | 482 mem 665 509 500 491 485 484 483 481 332 294 484 | 483 men 884 853 770 709 604 510 501 485 484 482 481 474 414 333 243 160 81 485 | 484 met 887 854 826 711 668 608 520 512 505 485 483 482 481 478 447 390 337 295 245 82 486 | 485 mew 888 771 712 609 521 506 484 483 482 481 479 392 338 247 163 487 | 486 mho 856 773 671 557 502 488 | 487 mib 717 672 522 496 494 493 492 491 490 489 488 452 393 298 250 166 84 489 | 488 mid 889 673 507 497 494 493 492 491 490 489 487 471 453 419 342 299 251 167 85 18 490 | 489 mig 904 858 674 615 508 498 494 493 492 491 490 488 487 473 394 301 253 169 86 491 | 490 mil 777 559 523 499 494 493 492 491 489 488 487 481 254 19 492 | 491 mim 830 719 675 524 509 500 494 493 492 490 489 488 487 482 344 170 20 493 | 492 mir 722 504 494 493 491 490 489 488 487 476 256 22 494 | 493 mis 874 860 832 780 723 618 511 494 492 491 490 489 488 487 477 457 347 89 23 495 | 494 mix 725 621 527 493 492 491 490 489 488 487 258 496 | 495 moa 906 506 505 504 503 502 501 500 499 498 497 496 424 306 91 497 | 496 mob 729 678 528 506 505 504 503 502 501 500 499 498 497 495 487 459 396 349 307 262 125 92 498 | 497 mod 892 782 730 680 623 529 507 506 505 504 503 502 501 500 499 498 496 495 488 471 350 308 126 93 499 | 498 mog 784 530 508 506 505 504 503 502 501 500 499 497 496 495 489 473 460 398 352 264 176 127 94 500 | 499 mol 731 626 506 505 504 503 502 501 500 498 497 496 495 490 481 177 128 501 | 500 mom 893 785 532 509 506 505 504 503 502 501 499 498 497 496 495 491 482 178 502 | 501 mon 894 865 834 786 732 510 506 505 504 503 502 500 499 498 497 496 495 483 474 377 266 220 179 129 503 | 502 moo 907 866 787 533 506 505 504 503 501 500 499 498 497 496 495 486 461 309 130 95 504 | 503 mop 867 788 733 627 506 505 504 502 501 500 499 498 497 496 495 475 462 425 353 267 131 96 505 | 504 mor 789 534 506 505 503 502 501 500 499 498 497 496 495 492 476 426 310 268 180 506 | 505 mot 869 790 735 682 628 568 536 512 506 504 503 502 501 500 499 498 497 496 495 484 478 463 399 354 311 182 133 98 507 | 506 mow 896 870 835 791 737 683 629 537 505 504 503 502 501 500 499 498 497 496 495 485 479 464 400 355 183 134 99 508 | 507 mud 872 635 579 512 511 510 509 508 497 488 471 275 187 140 104 509 | 508 mug 837 796 686 636 512 511 510 509 507 498 489 473 466 402 359 276 189 105 510 | 509 mum 746 687 512 511 510 508 507 500 491 482 467 361 315 142 106 511 | 510 mun 798 747 688 638 540 512 511 509 508 507 501 483 474 403 362 316 277 191 107 512 | 511 mus 641 541 512 510 509 508 507 493 477 404 109 513 | 512 mut 800 689 642 581 542 511 510 509 508 507 505 484 478 405 364 317 145 110 514 | 513 nab 838 750 692 539 528 522 518 517 516 515 514 429 406 383 279 147 114 515 | 514 nae 840 752 695 519 517 516 515 513 472 407 322 281 516 | 515 nag 899 841 753 696 648 530 517 516 514 513 473 432 384 323 282 234 149 69 517 | 516 nap 900 878 843 758 698 653 593 525 517 515 514 513 475 434 327 286 153 118 518 | 517 nay 881 849 703 658 599 516 515 514 513 480 440 410 388 331 290 240 155 122 76 519 | 518 neb 850 659 539 528 522 521 520 519 513 156 520 | 519 nee 903 852 824 768 706 662 602 521 520 518 514 443 389 292 242 157 123 78 521 | 520 net 887 854 826 711 668 608 542 536 526 521 519 518 484 447 390 337 295 245 82 522 | 521 new 888 771 712 609 537 520 519 518 485 392 338 247 163 523 | 522 nib 717 672 539 528 527 526 525 524 523 518 513 487 452 393 298 250 166 84 524 | 523 nil 777 559 527 526 525 524 522 490 254 19 525 | 524 nim 830 719 675 532 527 526 525 523 522 491 344 170 20 526 | 525 nip 905 891 779 721 677 617 527 526 524 523 522 516 456 422 346 303 172 527 | 526 nit 861 807 781 724 619 542 536 527 525 524 523 522 520 458 423 348 304 257 173 90 24 528 | 527 nix 725 621 526 525 524 523 522 494 258 529 | 528 nob 729 678 539 537 536 535 534 533 532 531 530 529 522 518 513 496 459 396 349 307 262 125 92 530 | 529 nod 892 782 730 680 623 537 536 535 534 533 532 531 530 528 497 350 308 126 93 531 | 530 nog 784 537 536 535 534 533 532 531 529 528 515 498 460 398 352 264 176 127 94 532 | 531 noh 624 567 538 537 536 535 534 533 532 530 529 528 265 533 | 532 nom 893 785 537 536 535 534 533 531 530 529 528 524 500 178 534 | 533 noo 907 866 787 537 536 535 534 532 531 530 529 528 502 461 309 130 95 535 | 534 nor 789 537 536 535 533 532 531 530 529 528 504 426 310 268 180 536 | 535 nos 868 734 541 537 536 534 533 532 531 530 529 528 427 181 132 97 537 | 536 not 869 790 735 682 628 568 542 537 535 534 533 532 531 530 529 528 526 520 505 463 399 354 311 182 133 98 538 | 537 now 896 870 835 791 737 683 629 536 535 534 533 532 531 530 529 528 521 506 464 400 355 183 134 99 539 | 538 nth 531 229 540 | 539 nub 795 744 684 634 542 541 540 528 522 518 513 357 274 185 139 103 541 | 540 nun 798 747 688 638 542 541 539 510 403 362 316 277 191 107 542 | 541 nus 641 542 540 539 535 511 404 109 543 | 542 nut 800 689 642 581 541 540 539 536 526 520 512 405 364 317 145 110 544 | 543 oaf 554 546 545 544 545 | 544 oak 876 546 545 543 151 546 | 545 oar 879 844 759 594 580 546 544 543 476 435 386 287 236 195 119 73 547 | 546 oat 846 820 761 699 655 596 581 577 571 568 555 545 544 543 478 437 409 329 289 238 196 120 75 548 | 547 obe 583 578 575 569 565 563 561 551 548 549 | 548 obi 547 550 | 549 oca 582 572 560 551 | 550 odd 579 562 552 551 8 552 | 551 ode 583 578 575 569 565 563 561 552 550 547 553 | 552 ods 576 570 566 564 558 553 551 550 369 10 554 | 553 oes 886 667 607 576 570 566 564 558 552 336 161 555 | 554 off 555 543 202 12 556 | 555 oft 581 577 571 568 554 546 204 13 557 | 556 ohm 558 557 558 | 557 oho 856 773 671 558 556 486 559 | 558 ohs 576 570 566 564 557 556 553 552 560 | 559 oil 777 584 523 490 254 19 561 | 560 oka 582 572 561 549 562 | 561 oke 808 583 578 575 569 565 563 560 551 547 207 563 | 562 old 579 563 550 208 564 | 563 ole 583 578 575 569 565 562 561 551 547 27 565 | 564 oms 576 570 566 558 553 552 215 566 | 565 one 583 578 575 569 566 563 561 551 547 37 567 | 566 ons 810 576 570 565 564 558 553 552 376 219 568 | 567 ooh 624 568 531 265 569 | 568 oot 869 790 735 682 628 581 577 571 567 555 546 536 505 463 399 354 311 182 133 98 570 | 569 ope 583 578 575 571 570 565 563 561 551 547 41 571 | 570 ops 812 576 571 569 566 564 558 553 552 572 | 571 opt 581 577 570 569 568 555 546 42 573 | 572 ora 582 577 576 575 574 573 560 549 221 102 574 | 573 orb 577 576 575 574 572 575 | 574 orc 577 576 575 573 572 43 576 | 575 ore 583 578 577 576 574 573 572 569 565 563 561 551 547 378 222 44 577 | 576 ors 577 575 574 573 572 570 566 564 558 553 552 226 48 578 | 577 ort 581 576 575 574 573 572 571 568 555 546 49 579 | 578 ose 815 583 575 569 565 563 561 551 547 580 | 579 oud 872 635 581 580 562 550 507 275 187 140 104 581 | 580 our 640 581 579 545 278 144 108 582 | 581 out 800 689 642 580 579 577 571 568 555 546 542 512 405 364 317 145 110 583 | 582 ova 572 560 549 56 584 | 583 owe 585 584 578 575 569 565 563 561 551 547 231 60 585 | 584 owl 585 583 559 61 586 | 585 own 584 583 62 587 | 586 oxy 588 | 587 pac 693 613 599 598 597 596 595 594 593 592 591 590 589 588 470 430 589 | 588 pad 839 751 694 647 635 623 601 599 598 597 596 595 594 593 592 591 590 589 587 471 431 321 280 233 148 115 68 590 | 589 pah 875 649 624 599 598 597 596 595 594 593 592 591 590 588 587 324 150 70 0 591 | 590 pal 697 637 626 599 598 597 596 595 594 593 592 591 589 588 587 283 71 1 592 | 591 pam 877 755 651 599 598 597 596 595 594 593 592 590 589 588 587 433 385 326 284 152 116 593 | 592 pan 842 818 756 652 638 616 604 599 598 597 596 595 594 593 591 590 589 588 587 474 285 235 117 72 594 | 593 pap 900 878 843 758 698 653 639 627 617 605 599 598 597 596 595 594 592 591 590 589 588 587 516 475 434 327 286 153 118 595 | 594 par 879 844 759 640 606 599 598 597 596 595 593 592 591 590 589 588 587 545 476 435 386 287 236 195 119 73 596 | 595 pas 845 819 760 654 641 618 607 599 598 597 596 594 593 592 591 590 589 588 587 477 436 408 328 288 237 74 2 597 | 596 pat 846 820 761 699 655 642 628 619 611 608 599 598 597 595 594 593 592 591 590 589 588 587 546 478 437 409 329 289 238 196 120 75 598 | 597 paw 880 847 823 764 701 656 629 609 599 598 596 595 594 593 592 591 590 589 588 587 479 438 387 330 154 121 599 | 598 pax 901 848 765 702 657 645 630 621 599 597 596 595 594 593 592 591 590 589 588 587 439 239 600 | 599 pay 881 849 703 658 632 622 598 597 596 595 594 593 592 591 590 589 588 587 517 480 440 410 388 331 290 240 155 122 76 601 | 600 pea 882 766 704 643 612 609 608 607 606 605 604 603 602 601 441 411 602 | 601 ped 902 851 767 661 635 623 609 608 607 606 605 604 603 602 600 588 442 291 241 77 603 | 602 pee 903 852 824 768 706 662 644 614 609 608 607 606 605 604 603 601 600 519 443 389 292 242 157 123 78 604 | 603 peg 825 769 636 615 609 608 607 606 605 604 602 601 600 444 413 79 605 | 604 pen 884 853 770 709 638 616 609 608 607 606 605 603 602 601 600 592 483 414 333 243 160 81 606 | 605 pep 885 666 639 627 617 609 608 607 606 604 603 602 601 600 593 415 334 607 | 606 per 710 640 609 608 607 605 604 603 602 601 600 594 335 244 608 | 607 pes 886 667 641 618 609 608 606 605 604 603 602 601 600 595 553 336 161 609 | 608 pet 887 854 826 711 668 642 628 619 611 609 607 606 605 604 603 602 601 600 596 520 484 447 390 337 295 245 82 610 | 609 pew 888 771 712 629 608 607 606 605 604 603 602 601 600 597 521 485 392 338 247 163 611 | 610 phi 633 625 611 418 297 124 612 | 611 pht 642 628 619 610 608 596 613 | 612 pia 828 643 621 620 619 618 617 616 615 614 613 600 614 | 613 pic 775 718 621 620 619 618 617 616 615 614 612 587 341 615 | 614 pie 829 776 644 621 620 619 618 617 616 615 613 612 602 454 343 300 252 168 616 | 615 pig 904 858 674 636 621 620 619 618 617 616 614 613 612 603 489 394 301 253 169 86 617 | 616 pin 890 859 831 778 720 676 638 621 620 619 618 617 615 614 613 612 604 592 455 421 395 345 302 255 171 87 21 618 | 617 pip 905 891 779 721 677 639 627 621 620 619 618 616 615 614 613 612 605 593 525 456 422 346 303 172 619 | 618 pis 874 860 832 780 723 641 621 620 619 617 616 615 614 613 612 607 595 493 457 347 89 23 620 | 619 pit 861 807 781 724 642 628 621 620 618 617 616 615 614 613 612 611 608 596 526 458 423 348 304 257 173 90 24 621 | 620 piu 621 619 618 617 616 615 614 613 612 622 | 621 pix 725 645 630 620 619 618 617 616 615 614 613 612 598 527 494 258 623 | 622 ply 728 632 599 261 624 | 623 pod 892 782 730 680 635 630 629 628 627 626 625 624 601 588 529 497 350 308 126 93 625 | 624 poh 630 629 628 627 626 625 623 589 567 531 265 626 | 625 poi 633 630 629 628 627 626 624 623 610 627 | 626 pol 731 637 630 629 628 627 625 624 623 590 499 177 128 628 | 627 pop 867 788 733 639 630 629 628 626 625 624 623 617 605 593 503 462 425 353 267 131 96 629 | 628 pot 869 790 735 682 642 630 629 627 626 625 624 623 619 611 608 596 568 536 505 463 399 354 311 182 133 98 630 | 629 pow 896 870 835 791 737 683 630 628 627 626 625 624 623 609 597 537 506 464 400 355 183 134 99 631 | 630 pox 836 738 645 629 628 627 626 625 624 623 621 598 465 312 270 135 100 632 | 631 pro 632 272 633 | 632 pry 871 793 631 622 599 273 184 138 634 | 633 psi 625 610 635 | 634 pub 795 744 684 642 641 640 639 638 637 636 635 539 357 274 185 139 103 636 | 635 pud 872 642 641 640 639 638 637 636 634 623 601 588 579 507 275 187 140 104 637 | 636 pug 837 796 686 642 641 640 639 638 637 635 634 615 603 508 466 402 359 276 189 105 638 | 637 pul 642 641 640 639 638 636 635 634 626 590 314 639 | 638 pun 798 747 688 642 641 640 639 637 636 635 634 616 604 592 540 510 403 362 316 277 191 107 640 | 639 pup 898 799 748 642 641 640 638 637 636 635 634 627 617 605 593 363 193 143 641 | 640 pur 642 641 639 638 637 636 635 634 606 594 580 278 144 108 642 | 641 pus 642 640 639 638 637 636 635 634 618 607 595 541 511 404 109 643 | 642 put 800 689 641 640 639 638 637 636 635 634 628 619 611 608 596 581 542 512 405 364 317 145 110 644 | 643 pya 690 645 644 612 600 645 | 644 pye 873 804 691 645 643 614 602 469 232 194 112 64 646 | 645 pyx 644 643 630 621 598 647 | 646 qua 648 | 647 rad 839 751 694 680 673 661 658 657 656 655 654 653 652 651 650 649 648 588 471 431 321 280 233 148 115 68 649 | 648 rag 899 841 753 696 686 674 658 657 656 655 654 653 652 651 650 649 647 515 473 432 384 323 282 234 149 69 650 | 649 rah 875 658 657 656 655 654 653 652 651 650 648 647 589 324 150 70 0 651 | 650 raj 754 658 657 656 655 654 653 652 651 649 648 647 325 652 | 651 ram 877 755 687 675 665 658 657 656 655 654 653 652 650 649 648 647 591 433 385 326 284 152 116 653 | 652 ran 842 818 756 688 676 658 657 656 655 654 653 651 650 649 648 647 592 474 285 235 117 72 654 | 653 rap 900 878 843 758 698 677 666 658 657 656 655 654 652 651 650 649 648 647 593 516 475 434 327 286 153 118 655 | 654 ras 845 819 760 667 658 657 656 655 653 652 651 650 649 648 647 595 477 436 408 328 288 237 74 2 656 | 655 rat 846 820 761 699 689 682 668 658 657 656 654 653 652 651 650 649 648 647 596 546 478 437 409 329 289 238 196 120 75 657 | 656 raw 880 847 823 764 701 683 658 657 655 654 653 652 651 650 649 648 647 597 479 438 387 330 154 121 658 | 657 rax 901 848 765 702 670 658 656 655 654 653 652 651 650 649 648 647 598 439 239 659 | 658 ray 881 849 703 657 656 655 654 653 652 651 650 649 648 647 599 517 480 440 410 388 331 290 240 155 122 76 660 | 659 reb 850 684 678 672 670 669 668 667 666 665 664 663 662 661 660 518 156 661 | 660 rec 705 679 670 669 668 667 666 665 664 663 662 661 659 662 | 661 red 902 851 767 680 673 670 669 668 667 666 665 664 663 662 660 659 647 601 442 291 241 77 663 | 662 ree 903 852 824 768 706 691 685 681 670 669 668 667 666 665 664 663 661 660 659 602 519 443 389 292 242 157 123 78 664 | 663 ref 670 669 668 667 666 665 664 662 661 660 659 412 665 | 664 rei 707 670 669 668 667 666 665 663 662 661 660 659 445 158 666 | 665 rem 687 675 670 669 668 667 666 664 663 662 661 660 659 651 482 332 294 667 | 666 rep 885 677 670 669 668 667 665 664 663 662 661 660 659 653 605 415 334 668 | 667 res 886 670 669 668 666 665 664 663 662 661 660 659 654 607 553 336 161 669 | 668 ret 887 854 826 711 689 682 670 669 667 666 665 664 663 662 661 660 659 655 608 520 484 447 390 337 295 245 82 670 | 669 rev 670 668 667 666 665 664 663 662 661 660 659 449 162 671 | 670 rex 827 713 669 668 667 666 665 664 663 662 661 660 659 657 450 416 339 164 672 | 671 rho 856 773 557 486 673 | 672 rib 717 684 678 677 676 675 674 673 659 522 487 452 393 298 250 166 84 674 | 673 rid 889 680 677 676 675 674 672 661 647 488 453 419 342 299 251 167 85 18 675 | 674 rig 904 858 686 677 676 675 673 672 648 615 489 394 301 253 169 86 676 | 675 rim 830 719 687 677 676 674 673 672 665 651 524 491 344 170 20 677 | 676 rin 890 859 831 778 720 688 677 675 674 673 672 652 616 455 421 395 345 302 255 171 87 21 678 | 677 rip 905 891 779 721 676 675 674 673 672 666 653 617 525 456 422 346 303 172 679 | 678 rob 729 684 683 682 681 680 679 672 659 528 496 459 396 349 307 262 125 92 680 | 679 roc 683 682 681 680 678 660 174 681 | 680 rod 892 782 730 683 682 681 679 678 673 661 647 623 529 497 350 308 126 93 682 | 681 roe 863 833 783 691 685 683 682 680 679 678 662 397 351 263 175 683 | 682 rot 869 790 735 689 683 681 680 679 678 668 655 628 568 536 505 463 399 354 311 182 133 98 684 | 683 row 896 870 835 791 737 682 681 680 679 678 656 629 537 506 464 400 355 183 134 99 685 | 684 rub 795 744 689 688 687 686 685 678 672 659 634 539 357 274 185 139 103 686 | 685 rue 745 691 689 688 687 686 684 681 662 428 358 188 141 687 | 686 rug 837 796 689 688 687 685 684 674 648 636 508 466 402 359 276 189 105 688 | 687 rum 746 689 688 686 685 684 675 665 651 509 467 361 315 142 106 689 | 688 run 798 747 689 687 686 685 684 676 652 638 540 510 403 362 316 277 191 107 690 | 689 rut 800 688 687 686 685 684 682 668 655 642 581 542 512 405 364 317 145 110 691 | 690 rya 691 643 692 | 691 rye 873 804 690 685 681 662 644 469 232 194 112 64 693 | 692 sab 838 750 744 729 717 703 702 701 700 699 698 697 696 695 694 693 513 429 406 383 279 147 114 694 | 693 sac 718 705 703 702 701 700 699 698 697 696 695 694 692 587 470 430 695 | 694 sad 839 751 730 703 702 701 700 699 698 697 696 695 693 692 647 588 471 431 321 280 233 148 115 68 696 | 695 sae 840 752 745 714 706 703 702 701 700 699 698 697 696 694 693 692 514 472 407 322 281 697 | 696 sag 899 841 753 703 702 701 700 699 698 697 695 694 693 692 648 515 473 432 384 323 282 234 149 69 698 | 697 sal 731 708 703 702 701 700 699 698 696 695 694 693 692 590 283 71 1 699 | 698 sap 900 878 843 758 748 733 721 703 702 701 700 699 697 696 695 694 693 692 653 593 516 475 434 327 286 153 118 700 | 699 sat 846 820 761 735 724 711 703 702 701 700 698 697 696 695 694 693 692 655 596 546 478 437 409 329 289 238 196 120 75 701 | 700 sau 821 762 736 703 702 701 699 698 697 696 695 694 693 692 197 702 | 701 saw 880 847 823 764 737 712 703 702 700 699 698 697 696 695 694 693 692 656 597 479 438 387 330 154 121 703 | 702 sax 901 848 765 738 725 713 703 701 700 699 698 697 696 695 694 693 692 657 598 439 239 704 | 703 say 881 849 743 741 739 728 727 716 702 701 700 699 698 697 696 695 694 693 692 658 599 517 480 440 410 388 331 290 240 155 122 76 705 | 704 sea 882 766 740 713 712 711 710 709 708 707 706 705 600 441 411 706 | 705 sec 718 713 712 711 710 709 708 707 706 704 693 660 707 | 706 see 903 852 824 768 745 714 713 712 711 710 709 708 707 705 704 695 662 602 519 443 389 292 242 157 123 78 708 | 707 sei 742 726 713 712 711 710 709 708 706 705 704 664 445 158 709 | 708 sel 731 713 712 711 710 709 707 706 705 704 697 481 293 201 159 80 710 | 709 sen 884 853 770 749 747 732 720 713 712 711 710 708 707 706 705 704 604 483 414 333 243 160 81 711 | 710 ser 722 713 712 711 709 708 707 706 705 704 606 335 244 712 | 711 set 887 854 826 735 724 713 712 710 709 708 707 706 705 704 699 668 608 520 484 447 390 337 295 245 82 713 | 712 sew 888 771 737 713 711 710 709 708 707 706 705 704 701 609 521 485 392 338 247 163 714 | 713 sex 827 738 725 712 711 710 709 708 707 706 705 704 702 670 450 416 339 164 715 | 714 she 772 745 716 715 706 695 716 | 715 shh 716 714 717 | 716 shy 857 774 743 741 739 728 727 715 714 703 718 | 717 sib 744 729 725 724 723 722 721 720 719 718 692 672 522 487 452 393 298 250 166 84 719 | 718 sic 775 725 724 723 722 721 720 719 717 705 693 613 341 720 | 719 sim 830 746 725 724 723 722 721 720 718 717 675 524 491 344 170 20 721 | 720 sin 890 859 831 778 749 747 732 725 724 723 722 721 719 718 717 709 676 616 455 421 395 345 302 255 171 87 21 722 | 721 sip 905 891 779 748 733 725 724 723 722 720 719 718 717 698 677 617 525 456 422 346 303 172 723 | 722 sir 725 724 723 721 720 719 718 717 710 492 256 22 724 | 723 sis 874 860 832 780 734 725 724 722 721 720 719 718 717 618 493 457 347 89 23 725 | 724 sit 861 807 781 735 725 723 722 721 720 719 718 717 711 699 619 526 458 423 348 304 257 173 90 24 726 | 725 six 738 724 723 722 721 720 719 718 717 713 702 621 527 494 258 727 | 726 ski 742 727 707 728 | 727 sky 743 741 739 728 726 716 703 729 | 728 sly 743 741 739 727 716 703 622 261 730 | 729 sob 744 739 738 737 736 735 734 733 732 731 730 717 692 678 528 496 459 396 349 307 262 125 92 731 | 730 sod 892 782 739 738 737 736 735 734 733 732 731 729 694 680 623 529 497 350 308 126 93 732 | 731 sol 739 738 737 736 735 734 733 732 730 729 708 697 626 499 177 128 733 | 732 son 894 865 834 786 749 747 739 738 737 736 735 734 733 731 730 729 720 709 501 377 266 220 179 129 734 | 733 sop 867 788 748 739 738 737 736 735 734 732 731 730 729 721 698 627 503 462 425 353 267 131 96 735 | 734 sos 868 739 738 737 736 735 733 732 731 730 729 723 535 427 181 132 97 736 | 735 sot 869 790 739 738 737 736 734 733 732 731 730 729 724 711 699 682 628 568 536 505 463 399 354 311 182 133 98 737 | 736 sou 895 739 738 737 735 734 733 732 731 730 729 700 269 738 | 737 sow 896 870 835 791 739 738 736 735 734 733 732 731 730 729 712 701 683 629 537 506 464 400 355 183 134 99 739 | 738 sox 836 739 737 736 735 734 733 732 731 730 729 725 713 702 630 465 312 270 135 100 740 | 739 soy 792 743 741 738 737 736 735 734 733 732 731 730 729 728 727 716 703 401 356 313 271 136 101 741 | 740 spa 741 704 742 | 741 spy 743 740 739 728 727 716 703 743 | 742 sri 726 707 744 | 743 sty 741 739 728 727 716 703 745 | 744 sub 795 748 747 746 745 729 717 692 684 634 539 357 274 185 139 103 746 | 745 sue 748 747 746 744 714 706 695 685 428 358 188 141 747 | 746 sum 748 747 745 744 719 687 509 467 361 315 142 106 748 | 747 sun 798 749 748 746 745 744 732 720 709 688 638 540 510 403 362 316 277 191 107 749 | 748 sup 898 799 747 746 745 744 733 721 698 639 363 193 143 750 | 749 syn 747 732 720 709 751 | 750 tab 838 795 765 764 763 762 761 760 759 758 757 756 755 754 753 752 751 692 513 429 406 383 279 147 114 752 | 751 tad 839 782 767 765 764 763 762 761 760 759 758 757 756 755 754 753 752 750 694 647 588 471 431 321 280 233 148 115 68 753 | 752 tae 840 804 783 776 772 768 765 764 763 762 761 760 759 758 757 756 755 754 753 751 750 695 514 472 407 322 281 754 | 753 tag 899 841 796 784 769 765 764 763 762 761 760 759 758 757 756 755 754 752 751 750 696 648 515 473 432 384 323 282 234 149 69 755 | 754 taj 765 764 763 762 761 760 759 758 757 756 755 753 752 751 750 650 325 756 | 755 tam 877 785 765 764 763 762 761 760 759 758 757 756 754 753 752 751 750 651 591 433 385 326 284 152 116 757 | 756 tan 842 818 798 786 778 770 765 764 763 762 761 760 759 758 757 755 754 753 752 751 750 652 592 474 285 235 117 72 758 | 757 tao 803 787 773 765 764 763 762 761 760 759 758 756 755 754 753 752 751 750 759 | 758 tap 900 878 843 799 788 779 765 764 763 762 761 760 759 757 756 755 754 753 752 751 750 698 653 593 516 475 434 327 286 153 118 760 | 759 tar 879 844 789 765 764 763 762 761 760 758 757 756 755 754 753 752 751 750 594 545 476 435 386 287 236 195 119 73 761 | 760 tas 845 819 780 765 764 763 762 761 759 758 757 756 755 754 753 752 751 750 654 595 477 436 408 328 288 237 74 2 762 | 761 tat 846 820 800 790 781 765 764 763 762 760 759 758 757 756 755 754 753 752 751 750 699 655 596 546 478 437 409 329 289 238 196 120 75 763 | 762 tau 821 765 764 763 761 760 759 758 757 756 755 754 753 752 751 750 700 197 764 | 763 tav 822 765 764 762 761 760 759 758 757 756 755 754 753 752 751 750 765 | 764 taw 880 847 823 791 771 765 763 762 761 760 759 758 757 756 755 754 753 752 751 750 701 656 597 479 438 387 330 154 121 766 | 765 tax 901 848 801 764 763 762 761 760 759 758 757 756 755 754 753 752 751 750 702 657 598 439 239 767 | 766 tea 882 802 771 770 769 768 767 704 600 441 411 768 | 767 ted 902 851 782 771 770 769 768 766 751 661 601 442 291 241 77 769 | 768 tee 903 852 824 804 783 776 772 771 770 769 767 766 752 706 662 602 519 443 389 292 242 157 123 78 770 | 769 teg 825 796 784 771 770 768 767 766 753 603 444 413 79 771 | 770 ten 884 853 798 786 778 771 769 768 767 766 756 709 604 483 414 333 243 160 81 772 | 771 tew 888 791 770 769 768 767 766 764 712 609 521 485 392 338 247 163 773 | 772 the 804 783 776 774 773 768 752 714 774 | 773 tho 856 803 787 774 772 757 671 557 486 775 | 774 thy 857 793 792 773 772 716 776 | 775 tic 781 780 779 778 777 776 718 613 341 777 | 776 tie 829 804 783 781 780 779 778 777 775 772 768 752 614 454 343 300 252 168 778 | 777 til 781 780 779 778 776 775 559 523 490 254 19 779 | 778 tin 890 859 831 798 786 781 780 779 777 776 775 770 756 720 676 616 455 421 395 345 302 255 171 87 21 780 | 779 tip 905 891 799 788 781 780 778 777 776 775 758 721 677 617 525 456 422 346 303 172 781 | 780 tis 874 860 832 781 779 778 777 776 775 760 723 618 493 457 347 89 23 782 | 781 tit 861 807 800 790 780 779 778 777 776 775 761 724 619 526 458 423 348 304 257 173 90 24 783 | 782 tod 892 792 791 790 789 788 787 786 785 784 783 767 751 730 680 623 529 497 350 308 126 93 784 | 783 toe 863 833 804 792 791 790 789 788 787 786 785 784 782 776 772 768 752 681 397 351 263 175 785 | 784 tog 796 792 791 790 789 788 787 786 785 783 782 769 753 530 498 460 398 352 264 176 127 94 786 | 785 tom 893 792 791 790 789 788 787 786 784 783 782 755 532 500 178 787 | 786 ton 894 865 834 798 792 791 790 789 788 787 785 784 783 782 778 770 756 732 501 377 266 220 179 129 788 | 787 too 907 866 803 792 791 790 789 788 786 785 784 783 782 773 757 533 502 461 309 130 95 789 | 788 top 867 799 792 791 790 789 787 786 785 784 783 782 779 758 733 627 503 462 425 353 267 131 96 790 | 789 tor 792 791 790 788 787 786 785 784 783 782 759 534 504 426 310 268 180 791 | 790 tot 869 800 792 791 789 788 787 786 785 784 783 782 781 761 735 682 628 568 536 505 463 399 354 311 182 133 98 792 | 791 tow 896 870 835 792 790 789 788 787 786 785 784 783 782 771 764 737 683 629 537 506 464 400 355 183 134 99 793 | 792 toy 793 791 790 789 788 787 786 785 784 783 782 774 739 401 356 313 271 136 101 794 | 793 try 871 792 774 632 273 184 138 795 | 794 tsk 51 796 | 795 tub 801 800 799 798 797 796 750 744 684 634 539 357 274 185 139 103 797 | 796 tug 837 801 800 799 798 797 795 784 769 753 686 636 508 466 402 359 276 189 105 798 | 797 tui 801 800 799 798 796 795 190 799 | 798 tun 801 800 799 797 796 795 786 778 770 756 747 688 638 540 510 403 362 316 277 191 107 800 | 799 tup 898 801 800 798 797 796 795 788 779 758 748 639 363 193 143 801 | 800 tut 801 799 798 797 796 795 790 781 761 689 642 581 542 512 405 364 317 145 110 802 | 801 tux 800 799 798 797 796 795 765 468 803 | 802 twa 803 766 59 804 | 803 two 802 787 773 757 805 | 804 tye 873 783 776 772 768 752 691 644 469 232 194 112 64 806 | 805 udo 811 9 807 | 806 ugh 808 | 807 uit 861 781 724 619 526 458 423 348 304 257 173 90 24 809 | 808 uke 815 561 207 810 | 809 ump 373 33 811 | 810 uns 817 812 566 376 219 812 | 811 upo 812 805 813 | 812 ups 817 811 810 570 814 | 813 urd 814 815 | 814 urn 813 224 816 | 815 use 808 578 817 | 816 uta 817 228 818 | 817 uts 816 812 810 381 819 | 818 van 842 834 831 823 822 821 820 819 756 652 592 474 285 235 117 72 820 | 819 vas 845 832 823 822 821 820 818 760 654 595 477 436 408 328 288 237 74 2 821 | 820 vat 846 826 823 822 821 819 818 761 699 655 596 546 478 437 409 329 289 238 196 120 75 822 | 821 vau 823 822 820 819 818 762 700 197 823 | 822 vav 823 821 820 819 818 763 824 | 823 vaw 880 847 835 822 821 820 819 818 764 701 656 597 479 438 387 330 154 121 825 | 824 vee 903 852 833 829 827 826 825 768 706 662 602 519 443 389 292 242 157 123 78 826 | 825 veg 837 827 826 824 769 603 444 413 79 827 | 826 vet 887 854 827 825 824 820 711 668 608 520 484 447 390 337 295 245 82 828 | 827 vex 836 826 825 824 713 670 450 416 339 164 829 | 828 via 832 831 830 829 612 830 | 829 vie 833 832 831 830 828 824 776 614 454 343 300 252 168 831 | 830 vim 832 831 829 828 719 675 524 491 344 170 20 832 | 831 vin 890 859 834 832 830 829 828 818 778 720 676 616 455 421 395 345 302 255 171 87 21 833 | 832 vis 874 860 831 830 829 828 819 780 723 618 493 457 347 89 23 834 | 833 voe 863 836 835 834 829 824 783 681 397 351 263 175 835 | 834 von 894 865 836 835 833 831 818 786 732 501 377 266 220 179 129 836 | 835 vow 896 870 836 834 833 823 791 737 683 629 537 506 464 400 355 183 134 99 837 | 836 vox 835 834 833 827 738 630 465 312 270 135 100 838 | 837 vug 825 796 686 636 508 466 402 359 276 189 105 839 | 838 wab 850 849 848 847 846 845 844 843 842 841 840 839 750 692 513 429 406 383 279 147 114 840 | 839 wad 872 851 849 848 847 846 845 844 843 842 841 840 838 751 694 647 588 471 431 321 280 233 148 115 68 841 | 840 wae 873 863 852 849 848 847 846 845 844 843 842 841 839 838 752 695 514 472 407 322 281 842 | 841 wag 899 858 849 848 847 846 845 844 843 842 840 839 838 753 696 648 515 473 432 384 323 282 234 149 69 843 | 842 wan 865 859 853 849 848 847 846 845 844 843 841 840 839 838 818 756 652 592 474 285 235 117 72 844 | 843 wap 900 878 867 849 848 847 846 845 844 842 841 840 839 838 758 698 653 593 516 475 434 327 286 153 118 845 | 844 war 879 849 848 847 846 845 843 842 841 840 839 838 759 594 545 476 435 386 287 236 195 119 73 846 | 845 was 868 860 849 848 847 846 844 843 842 841 840 839 838 819 760 654 595 477 436 408 328 288 237 74 2 847 | 846 wat 869 861 854 849 848 847 845 844 843 842 841 840 839 838 820 761 699 655 596 546 478 437 409 329 289 238 196 120 75 848 | 847 waw 880 870 849 848 846 845 844 843 842 841 840 839 838 823 764 701 656 597 479 438 387 330 154 121 849 | 848 wax 901 849 847 846 845 844 843 842 841 840 839 838 765 702 657 598 439 239 850 | 849 way 881 871 857 848 847 846 845 844 843 842 841 840 839 838 703 658 599 517 480 440 410 388 331 290 240 155 122 76 851 | 850 web 854 853 852 851 838 659 518 156 852 | 851 wed 902 872 854 853 852 850 839 767 661 601 442 291 241 77 853 | 852 wee 903 873 863 854 853 851 850 840 824 768 706 662 602 519 443 389 292 242 157 123 78 854 | 853 wen 884 865 859 854 852 851 850 842 770 709 604 483 414 333 243 160 81 855 | 854 wet 887 869 861 853 852 851 850 846 826 711 668 608 520 484 447 390 337 295 245 82 856 | 855 wha 857 856 17 857 | 856 who 866 857 855 773 671 557 486 858 | 857 why 871 856 855 849 774 716 859 | 858 wig 904 862 861 860 859 841 674 615 489 394 301 253 169 86 860 | 859 win 890 865 862 861 860 858 853 842 831 778 720 676 616 455 421 395 345 302 255 171 87 21 861 | 860 wis 874 868 862 861 859 858 845 832 780 723 618 493 457 347 89 23 862 | 861 wit 869 862 860 859 858 854 846 807 781 724 619 526 458 423 348 304 257 173 90 24 863 | 862 wiz 861 860 859 858 259 864 | 863 woe 873 870 869 868 867 866 865 864 852 840 833 783 681 397 351 263 175 865 | 864 wok 870 869 868 867 866 865 863 866 | 865 won 894 870 869 868 867 866 864 863 859 853 842 834 786 732 501 377 266 220 179 129 867 | 866 woo 907 870 869 868 867 865 864 863 856 787 533 502 461 309 130 95 868 | 867 wop 870 869 868 866 865 864 863 843 788 733 627 503 462 425 353 267 131 96 869 | 868 wos 870 869 867 866 865 864 863 860 845 734 535 427 181 132 97 870 | 869 wot 870 868 867 866 865 864 863 861 854 846 790 735 682 628 568 536 505 463 399 354 311 182 133 98 871 | 870 wow 896 869 868 867 866 865 864 863 847 835 791 737 683 629 537 506 464 400 355 183 134 99 872 | 871 wry 857 849 793 632 273 184 138 873 | 872 wud 851 839 635 579 507 275 187 140 104 874 | 873 wye 863 852 840 804 691 644 469 232 194 112 64 875 | 874 xis 860 832 780 723 618 493 457 347 89 23 876 | 875 yah 883 881 880 879 878 877 876 649 589 324 150 70 0 877 | 876 yak 897 881 880 879 878 877 875 544 151 878 | 877 yam 893 881 880 879 878 876 875 755 651 591 433 385 326 284 152 116 879 | 878 yap 900 898 891 885 881 880 879 877 876 875 843 758 698 653 593 516 475 434 327 286 153 118 880 | 879 yar 881 880 878 877 876 875 844 759 594 545 476 435 386 287 236 195 119 73 881 | 880 yaw 896 888 881 879 878 877 876 875 847 823 764 701 656 597 479 438 387 330 154 121 882 | 881 yay 880 879 878 877 876 875 849 703 658 599 517 480 440 410 388 331 290 240 155 122 76 883 | 882 yea 888 887 886 885 884 883 766 704 600 441 411 884 | 883 yeh 888 887 886 885 884 882 875 885 | 884 yen 894 890 888 887 886 885 883 882 853 770 709 604 483 414 333 243 160 81 886 | 885 yep 898 891 888 887 886 884 883 882 878 666 605 415 334 887 | 886 yes 888 887 885 884 883 882 667 607 553 336 161 888 | 887 yet 888 886 885 884 883 882 854 826 711 668 608 520 484 447 390 337 295 245 82 889 | 888 yew 896 887 886 885 884 883 882 880 771 712 609 521 485 392 338 247 163 890 | 889 yid 892 891 890 673 488 453 419 342 299 251 167 85 18 891 | 890 yin 894 891 889 884 859 831 778 720 676 616 455 421 395 345 302 255 171 87 21 892 | 891 yip 905 898 890 889 885 878 779 721 677 617 525 456 422 346 303 172 893 | 892 yod 896 895 894 893 889 782 730 680 623 529 497 350 308 126 93 894 | 893 yom 896 895 894 892 877 785 532 500 178 895 | 894 yon 896 895 893 892 890 884 865 834 786 732 501 377 266 220 179 129 896 | 895 you 896 894 893 892 736 269 897 | 896 yow 895 894 893 892 888 880 870 835 791 737 683 629 537 506 464 400 355 183 134 99 898 | 897 yuk 898 876 55 899 | 898 yup 897 891 885 878 799 748 639 363 193 143 900 | 899 zag 904 901 900 841 753 696 648 515 473 432 384 323 282 234 149 69 901 | 900 zap 905 901 899 878 843 758 698 653 593 516 475 434 327 286 153 118 902 | 901 zax 900 899 848 765 702 657 598 439 239 903 | 902 zed 903 851 767 661 601 442 291 241 77 904 | 903 zee 902 852 824 768 706 662 602 519 443 389 292 242 157 123 78 905 | 904 zig 905 899 858 674 615 489 394 301 253 169 86 906 | 905 zip 904 900 891 779 721 677 617 525 456 422 346 303 172 907 | 906 zoa 907 495 424 306 91 908 | 907 zoo 906 866 787 533 502 461 309 130 95 909 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Word Ladders Game (Graph DSA) 2 | 3 | ## Overview 4 | The Word Ladders game is a Java application that utilizes a Graph data structure to find connections between words. By entering a starting and ending word, the program calculates the shortest path (word ladder) between these two words using either Depth-First Search (DFS) or Breadth-First Search (BFS). This application supports large datasets, making it capable of processing extensive word lists efficiently. 5 | 6 | ## Features 7 | - **Flexible Word Graph Construction**: Supports construction from text files, enabling easy customization and expansion of the word database. 8 | - **User-Interactive Gameplay**: Allows users to input starting and ending words to generate word ladders. 9 | - **Search Algorithm Selection**: Users can choose between DFS and BFS to find the word ladder. 10 | - **Scalability**: Efficiently processes large word lists, including datasets with tens of thousands of words. 11 | 12 | ## Prerequisites 13 | - Java Development Kit (JDK) 11 or later installed on your machine. 14 | - A Java IDE (e.g. IntelliJ IDEA or Eclipse) is highly recommended. 15 | 16 | ## Setup 17 | 1. Ensure Java is properly installed by running `java -version` in your terminal or command prompt. 18 | 2. Download or clone this repository to your local machine. 19 | 3. Navigate to the directory containing `WordLadders.java` and any required word list files. 20 | 21 | ## Running the Program 22 | Compile and run the application using the Java compiler and runtime environment: 23 | ```bash 24 | javac WordLadders.java 25 | java WordLadders 26 | ``` 27 | Alternatively, you can simply run the file(s) directly in your IDE, if supported. 28 | 29 | Upon execution, the program prompts you to enter the filename of your desired word list. Valid filenames include `Length3WordGraph` or `LargeWordGraph`, although you can use any text file formatted according to the program's specifications. 30 | 31 | After loading the word graph, follow the on-screen instructions to input your starting and ending words, and select the search algorithm (DFS or BFS). 32 | 33 | ## Word List File Format 34 | The program expects word list files to be formatted as follows: 35 | ``` 36 | word1 neighbor1 neighbor2 ... 37 | word2 neighbor1 neighbor2 ... 38 | ... 39 | ``` 40 | Each line represents a word and its immediate neighbors (words differing by one letter). The program reads these files to construct the word graph used to find word ladders. 41 | 42 | ## Contributing 43 | Contributions to enhance the functionality or performance of the Word Ladders game are welcome. Please feel free to fork the repository, make your changes, and submit a pull request detailing your improvements. 44 | 45 | ## License 46 | This project is open-source and available under the [MIT license](https://opensource.org/licenses/MIT). 47 | 48 | ## Contact 49 | For any inquiries or contributions, please contact the repository owner, [Son Nguyen](https://github.com/hoangsonww). 50 | 51 | --- 52 | 53 | Created with ❤️ by [Son Nguyen](https://github.com/hoangsonww) in 2023. 54 | -------------------------------------------------------------------------------- /Tester.java: -------------------------------------------------------------------------------- 1 | import java.io.IOException; 2 | import java.io.ByteArrayInputStream; 3 | 4 | import java.time.LocalDate; 5 | import java.time.Month; 6 | 7 | import java.util.Scanner; 8 | import java.util.Arrays; 9 | 10 | import static org.junit.Assert.assertEquals; 11 | import static org.junit.Assert.assertTrue; 12 | import static org.junit.Assert.assertFalse; 13 | import static org.junit.Assert.assertNotNull; 14 | import static org.junit.Assert.assertArrayEquals; 15 | import static org.junit.Assert.assertNull; 16 | import static org.junit.Assert.assertNotEquals; 17 | import static org.junit.Assert.assertThrows; 18 | 19 | import org.junit.Before; 20 | import org.junit.Test; 21 | import org.junit.After; 22 | 23 | /** 24 | * A class that represents and performs the function as the JUnit 4 Tester for all the Homework 6 classes and methods. 25 | * 26 | * @author David Nguyen 27 | * @since 04/30/2023 28 | * @version 1.0 29 | */ 30 | public class Tester { 31 | 32 | // A field that represents a test graph 33 | private Graph testGraph; 34 | 35 | // A field that represents a wordLadder for testing 36 | private WordLadders wordLadders; 37 | 38 | /** 39 | * Sets up the test for Graph and WordLadder 40 | */ 41 | @Before 42 | public void setUp() { 43 | testGraph = new Graph(); 44 | wordLadders = new WordLadders(); 45 | } 46 | 47 | /** 48 | * Test the addNode() method 49 | */ 50 | @Test 51 | public void testAddNode() { 52 | assertTrue(testGraph.addNode("A", "apple")); 53 | assertFalse(testGraph.addNode("A", "apple")); // Should be false because the node already exists 54 | assertTrue(testGraph.addNode("B", "banana")); 55 | assertFalse(testGraph.addNode("B", "bruh")); // Should be false because the key already exists 56 | assertTrue(testGraph.addNode("C", "cherry")); 57 | assertFalse(testGraph.addNode(null, "null")); 58 | } 59 | 60 | /** 61 | * Test the addNodes() method 62 | */ 63 | @Test 64 | public void testAddNodes() { 65 | System.out.println("Extra testing the addNodes() method with printGraph():"); 66 | String[] names = {"A", "B", "C"}; 67 | String[] data = {"apple", "banana", "cherry"}; 68 | assertTrue(testGraph.addNodes(names, data)); 69 | String[] names1 = {"A", "C"}; 70 | String[] data1 = {"apple", "cherry"}; 71 | assertFalse(testGraph.addNodes(names1, data1)); // Should be false because the node C already exists 72 | String[] names2 = {"D", "E", "F"}; 73 | String[] data2 = {"Data", "Egg", "Fruit"}; 74 | assertTrue(testGraph.addNodes(names2, data2)); 75 | String[] names3 = {null, "G", "H"}; 76 | String[] data3 = {"null", "Guitar", "Hat"}; 77 | assertTrue(testGraph.addNodes(names3, data3)); 78 | testGraph.printGraph(); 79 | System.out.println(); 80 | } 81 | 82 | /** 83 | * Test the addNodes() method with arrays of different lengths (Edge case): 84 | */ 85 | @Test(expected = IllegalArgumentException.class) 86 | public void testAddNodesDifferentLengthArrays() { 87 | String[] names = {"A", "B"}; 88 | String[] data = {"apple", "banana", "cherry"}; 89 | testGraph.addNodes(names, data); 90 | } 91 | 92 | /** 93 | * Test the addEdge() method 94 | */ 95 | @Test 96 | public void testAddEdge() { 97 | testGraph.addNode("A", "apple"); 98 | testGraph.addNode("B", "banana"); 99 | assertTrue(testGraph.addEdge("A", "B")); 100 | assertFalse(testGraph.addEdge("C", "D")); // Should be false because no such nodes exist in the graph 101 | assertFalse(testGraph.addEdge("D", "E")); // Should be false because no such nodes exist in the graph 102 | testGraph.addNode("C", "cherry"); 103 | testGraph.addNode("D", "data"); 104 | assertTrue(testGraph.addEdge("A", "D")); 105 | assertTrue(testGraph.addEdge("B", "D")); 106 | assertTrue(testGraph.addEdge("A", "C")); 107 | assertTrue(testGraph.addEdge("C", "D")); 108 | assertFalse(testGraph.addEdge("C", "D")); // Should be false because the edges already exist 109 | assertFalse(testGraph.addEdge(null, null)); // Should be false because the key is null 110 | assertFalse(testGraph.addEdge("E", null)); // Should be false because the key is null 111 | assertFalse(testGraph.addEdge(null, "F")); // Should be false because the key is null 112 | } 113 | 114 | /** 115 | * Test the addEdges() method 116 | */ 117 | @Test 118 | public void testAddEdges() { 119 | System.out.println("Testing the addEdges() method with printGraph():"); 120 | testGraph.addNode("A", "apple"); 121 | testGraph.addNode("B", "banana"); 122 | testGraph.addNode("C", "cherry"); 123 | assertTrue(testGraph.addEdges("A", "B", "C")); 124 | assertFalse(testGraph.addEdges("B", "A", "C")); // Should be false because the edges already exist 125 | testGraph.addNode("D", "data"); 126 | testGraph.addNode("E", "eggs"); 127 | testGraph.addNode("F", "finance"); 128 | assertTrue(testGraph.addEdges("D", "E", "F")); 129 | assertFalse(testGraph.addEdges("F", "E", "D")); // Should be false because the edges already exist 130 | assertFalse(testGraph.addEdges("F", "D", "E")); // Should be false because the edges already exist 131 | assertFalse(testGraph.addEdges("G", "F", "E")); // Should be false because the nodes do not exist in the graph 132 | assertFalse(testGraph.addEdges(null, "X", "Y")); 133 | testGraph.addNode("Z", "zurich"); 134 | assertTrue(testGraph.addEdges("D", null, "Z")); 135 | testGraph.printGraph(); 136 | System.out.println(); 137 | } 138 | 139 | /** 140 | * Test the removeNode() method 141 | */ 142 | @Test 143 | public void testRemoveNode() { 144 | testGraph.addNode("A", "apple"); 145 | testGraph.addNode("B", "bruh"); 146 | testGraph.addNode("C", "cheers"); 147 | testGraph.addNode("D", "data"); 148 | assertTrue(testGraph.removeNode("A")); 149 | assertFalse(testGraph.removeNode("A")); // Should be false because node is already removed 150 | assertTrue(testGraph.removeNode("B")); 151 | assertTrue(testGraph.removeNode("C")); 152 | assertTrue(testGraph.removeNode("D")); 153 | assertFalse(testGraph.removeNode("C")); // Should be false because node is already removed 154 | assertFalse(testGraph.removeNode(null)); 155 | } 156 | 157 | /** 158 | * Test the removeNodes() method 159 | */ 160 | @Test 161 | public void testRemoveNodes() { 162 | testGraph.addNode("A", "apple"); 163 | testGraph.addNode("B", "banana"); 164 | testGraph.addNode("C", "cherry"); 165 | assertTrue(testGraph.removeNodes("A", "B")); 166 | assertFalse(testGraph.removeNode("A")); // Should be false because node is already removed 167 | assertFalse(testGraph.removeNode("B")); // Should be false because node is already removed 168 | assertFalse(testGraph.removeNodes("A")); // Should be false because node is already removed 169 | assertTrue(testGraph.removeNodes("C")); 170 | testGraph.addNode("D", "data"); 171 | testGraph.addNode("E", "eggs"); 172 | testGraph.addNode("F", "fintech"); 173 | testGraph.addEdges("D", "E", "F"); 174 | assertTrue(testGraph.removeNodes("D", "E", "F")); 175 | assertFalse(testGraph.removeNodes(null, null, null)); 176 | testGraph.addNode("G","guitar"); 177 | assertFalse(testGraph.removeNodes("G", null, null)); 178 | } 179 | 180 | /** 181 | * Test the DFS() method 182 | */ 183 | @Test 184 | public void testDFS() { 185 | testGraph.addNode("A", "apple"); 186 | testGraph.addNode("B", "banana"); 187 | testGraph.addNode("C", "cherry"); 188 | testGraph.addEdge("A", "B"); 189 | testGraph.addEdge("B", "C"); 190 | Object[] dfsPath = testGraph.DFS("A", "C"); // Test the expected path of DFS between A and C 191 | String[] castedPath = Arrays.copyOf(dfsPath, dfsPath.length, String[].class); 192 | assertNotNull(castedPath); 193 | assertEquals(3, castedPath.length); 194 | assertEquals("A", castedPath[0]); 195 | assertEquals("B", castedPath[1]); 196 | assertEquals("C", castedPath[castedPath.length - 1]); 197 | testGraph.addNode("D", "data"); 198 | testGraph.addNode("E", "egg"); 199 | Object[] dfsPath1 = testGraph.DFS("D", "E"); // Test the expected path of DFS between D and E 200 | assertEquals(0, dfsPath1.length); 201 | Object[] dfsPath2 = testGraph.DFS("F", "G"); // Test the expected path of DFS between F and G 202 | assertEquals(0, dfsPath2.length); 203 | Object[] dfsPath3 = testGraph.DFS("D", "H"); // Test the expected path of DFS between D and H 204 | assertEquals(0, dfsPath3.length); 205 | assertNotNull(dfsPath3); 206 | } 207 | 208 | /** 209 | * Test the BFS() method 210 | */ 211 | @Test 212 | public void testBFS() { 213 | testGraph.addNode("A", "apple"); 214 | testGraph.addNode("B", "banana"); 215 | testGraph.addNode("C", "cherry"); 216 | testGraph.addEdge("A", "B"); 217 | testGraph.addEdge("B", "C"); 218 | Object[] bfsPath = testGraph.BFS("A", "C"); // Test the expected path of BFS between A and C 219 | String[] castedPath = Arrays.copyOf(bfsPath, bfsPath.length, String[].class); 220 | assertNotNull(castedPath); 221 | assertEquals(3, castedPath.length); 222 | assertEquals("A", castedPath[0]); 223 | assertEquals("B", castedPath[1]); 224 | assertEquals("C", castedPath[castedPath.length - 1]); 225 | testGraph.addNode("D", "data"); 226 | testGraph.addNode("E", "egg"); 227 | Object[] bfsPath1 = testGraph.BFS("D", "E"); // Test the expected path of BFS between D and E 228 | assertEquals(0, bfsPath1.length); 229 | Object[] bfsPath2 = testGraph.BFS("F", "G"); // Test the expected path of BFS between F and G 230 | assertEquals(0, bfsPath2.length); 231 | Object[] bfsPath3 = testGraph.BFS("D", "H"); // Test the expected path of BFS between D and H 232 | assertEquals(0, bfsPath3.length); 233 | Object[] bfsPath4 = testGraph.BFS("D", "E"); // Test the expected path of BFS between D and E 234 | assertEquals(0, bfsPath4.length); 235 | Graph graph = new Graph(); 236 | graph.addNode("D", "Data"); 237 | graph.addNode("E", "Eggplant"); 238 | Object[] bfsPath5 = testGraph.BFS("D", "E"); // Test the expected path of BFS between D and E 239 | assertEquals(0, bfsPath5.length); 240 | } 241 | 242 | /** 243 | * Test the readWordGraph() method with Length3WordGraph file and a nonexistent file 244 | */ 245 | @Test 246 | public void testReadWordGraphWithLength3WordGraph() { 247 | // Case 1: Test readWordGraph() with Length3WordGraph to see if it can process it 248 | System.out.println("Test the readWordGraph() method with invalid filename:"); 249 | String filename = "Length3WordGraph"; 250 | Graph wordGraph = WordLadders.readWordGraph(filename); 251 | assertNotNull(wordGraph); 252 | // Case 2: Test readWordGraph() with an invalid file to see if it can give any error messages to System.out 253 | String fileNameInvalid = "InvalidFileName"; 254 | Graph wordGraph1 = WordLadders.readWordGraph(fileNameInvalid); 255 | assertNotNull(wordGraph1); 256 | } 257 | 258 | /** 259 | * Test the readWordGraph() method with an invalid file 260 | */ 261 | @Test 262 | public void testReadWordGraphWithInvalidGraph() { 263 | String filename = "bruh.xyz"; 264 | Graph wordGraph = WordLadders.readWordGraph(filename); 265 | assertNotNull(wordGraph); 266 | } 267 | 268 | /** 269 | * Test the printGraph() method 270 | */ 271 | @Test 272 | public void testPrintGraph() { 273 | System.out.println("Initial test of the printGraph() method:"); 274 | testGraph.printGraph(); 275 | // Be sure to monitor command outputs - This method will use System.out.print 276 | testGraph.addNode("A", "apple"); 277 | testGraph.addNode("B", "banana"); 278 | testGraph.addNode("C", "cherry"); 279 | testGraph.addEdge("A", "B"); 280 | testGraph.addEdge("B", "C"); 281 | testGraph.printGraph(); 282 | System.out.println(); 283 | } 284 | 285 | /** 286 | * Test read() method with an invalid filename, expected to print an indicative error message to a screen 287 | */ 288 | @Test 289 | public void testReadException() { 290 | System.out.println(); 291 | System.out.println("Test the read() method with invalid filename:"); 292 | Graph.read("invalid.txt"); 293 | } 294 | 295 | // -------------------------------- PERFORMING EXTRA TESTS OF ALL METHODS -------------------------------- // 296 | 297 | // A field that stores a test graph for an extra test 298 | private Graph testGraph2; 299 | 300 | /** 301 | * Sets up the extra tests 302 | */ 303 | @Before 304 | public void setUpForExtraTests() { 305 | testGraph2 = new Graph(); 306 | testGraph2.addNode("A", 1); 307 | testGraph2.addNode("B", 2); 308 | testGraph2.addNode("C", 3); 309 | testGraph2.addEdge("A", "B"); 310 | testGraph2.addEdge("A", "C"); 311 | testGraph2.addEdge("B", "C"); 312 | } 313 | 314 | /** 315 | * Extra testing the printGraph() method 316 | */ 317 | @Test 318 | public void extraTestPrintGraph() { 319 | System.out.println("Testing the printGraph() method with a graph with key and value:"); 320 | testGraph2.printGraph(); 321 | System.out.println(); 322 | } 323 | 324 | /** 325 | * Testing the read() method 326 | */ 327 | @Test 328 | public void testRead() throws Exception { 329 | System.out.println("Test the read() method with text_input.txt:"); 330 | Graph readGraph = Graph.read("text_input.txt"); 331 | readGraph.printGraph(); 332 | System.out.println(); 333 | } 334 | 335 | /** 336 | * Performs an extra test on read() method 337 | */ 338 | @Test 339 | public void extraTestRead() { 340 | System.out.println("Test the read() method with testFileForRead.txt:"); 341 | Graph readGraph = Graph.read("testFileForRead.txt"); 342 | readGraph.printGraph(); 343 | System.out.println(); 344 | } 345 | 346 | /** 347 | * Performs an extra test on addNode() method 348 | */ 349 | @Test 350 | public void extraTestAddNode() { 351 | Graph graph = new Graph(); 352 | assertTrue(graph.addNode("A", "dataA")); 353 | assertFalse(graph.addNode("A", "dataA")); // Should be false because node already exists 354 | assertTrue(graph.addNode("B", "dataB")); 355 | } 356 | 357 | /** 358 | * Performs an extra test on addNodes() method 359 | */ 360 | @Test 361 | public void extraTestAddNodes() { 362 | Graph graph = new Graph(); 363 | String[] names = {"A", "B", "C"}; 364 | String[] data = {"dataA", "dataB", "dataC"}; 365 | assertTrue(graph.addNodes(names, data)); 366 | String[] duplicatedNodes = {"A", "B", "D"}; 367 | assertFalse(graph.addNodes(duplicatedNodes, data)); // Should be false because 2 of these nodes already exist 368 | // TEST IF NULL VALUES ARE TO BE ADDED (THEY SHOULDN'T BE ADDED): 369 | String[] names1 = {"A", null, "B"}; 370 | String[] data1 = {"A", "B", null}; 371 | Graph graph1 = new Graph(); 372 | assertTrue(graph1.addNodes(names1, data1)); 373 | graph1.printGraph(); 374 | // Expected output: A(A) and B 375 | } 376 | 377 | /** 378 | * Performs an extra test on addNodes() method - with exception expected 379 | */ 380 | @Test(expected = IllegalArgumentException.class) 381 | public void extraTestAddNodesException() { 382 | Graph graph = new Graph(); 383 | String[] names = {"A", "B"}; 384 | String[] data = {"dataA", "dataB", "dataC"}; 385 | graph.addNodes(names, data); 386 | } 387 | 388 | /** 389 | * Performs an extra test on addEdge() method 390 | */ 391 | @Test 392 | public void extraTestAddEdge() { 393 | Graph graph = new Graph(); 394 | graph.addNode("A", "dataA"); 395 | graph.addNode("B", "dataB"); 396 | assertTrue(graph.addEdge("A", "B")); 397 | assertFalse(graph.addEdge("A", "C")); // Should be false because C does not exist 398 | } 399 | 400 | /** 401 | * Performs an extra test on addEdges() method 402 | */ 403 | @Test 404 | public void extraTestAddEdges() { 405 | Graph graph = new Graph(); 406 | graph.addNode("A", "dataA"); 407 | graph.addNode("B", "dataB"); 408 | graph.addNode("C", "dataC"); 409 | assertTrue(graph.addEdges("A", "B", "C")); 410 | assertFalse(graph.addEdges("A", "B", "D")); // Should be false because D does not exist 411 | } 412 | 413 | /** 414 | * Performs an extra test on removeNode() method 415 | */ 416 | @Test 417 | public void extraTestRemoveNode() { 418 | Graph graph = new Graph(); 419 | graph.addNode("A", "dataA"); 420 | graph.addNode("B", "dataB"); 421 | graph.addEdge("A", "B"); 422 | assertTrue(graph.removeNode("A")); 423 | assertFalse(graph.removeNode("A")); // Should be false because A is already removed 424 | assertFalse(graph.removeNode("C")); // Should be false because C does not exist 425 | } 426 | 427 | /** 428 | * Performs an extra test on removeNodes() method 429 | */ 430 | @Test 431 | public void extraTestRemoveNodes() { 432 | Graph graph = new Graph(); 433 | graph.addNode("A", "dataA"); 434 | graph.addNode("B", "dataB"); 435 | graph.addNode("C", "dataC"); 436 | assertTrue(graph.removeNodes("A", "B")); 437 | assertFalse(graph.removeNodes("A", "D")); // Should be false as D does not exist, A is already removed 438 | } 439 | 440 | /** 441 | * Performs an extra test on DFS() method 442 | */ 443 | @Test 444 | public void extraTestDFS() { 445 | Graph graph = new Graph(); 446 | graph.addNode("A", "dataA"); 447 | graph.addNode("B", "dataB"); 448 | graph.addNode("C", "dataC"); 449 | graph.addEdge("A", "B"); 450 | graph.addEdge("B", "C"); 451 | String[] expectedPath = {"A", "B", "C"}; 452 | assertArrayEquals(expectedPath, graph.DFS("A", "C")); 453 | String[] emptyPath = {}; 454 | assertArrayEquals(emptyPath, graph.DFS("A", "D")); // No path should be returned because D is not in the graph 455 | } 456 | 457 | /** 458 | * Performs an extra test on BFS() method 459 | */ 460 | @Test 461 | public void extraTestBFS() { 462 | Graph graph = new Graph(); 463 | graph.addNode("A", "dataA"); 464 | graph.addNode("B", "dataB"); 465 | graph.addNode("C", "dataC"); 466 | graph.addEdge("A", "B"); 467 | graph.addEdge("B", "C"); 468 | String[] expectedPath = {"A", "B", "C"}; 469 | assertArrayEquals(expectedPath, graph.BFS("A", "C")); 470 | String[] emptyPath = {}; 471 | assertArrayEquals(emptyPath, graph.BFS("A", "D")); // No path should be returned because D is not in the graph 472 | } 473 | 474 | /** 475 | * Performs an extra test on readWordGraph() method 476 | * @throws IOException Throw if the file with given name is not found 477 | */ 478 | @Test 479 | public void extraTestReadWordGraph() throws IOException { 480 | System.out.println("Test the readWordGraph() with testWordGraph.txt:"); 481 | Graph graph = WordLadders.readWordGraph("testWordGraph.txt"); 482 | assertNotNull(graph); 483 | assertFalse(graph.addNode(1, "apple")); // Should be false because this node already exists 484 | assertFalse(graph.addNode(2, "banana")); // Should be false because this node already exists 485 | assertFalse(graph.addNode(3, "orange")); // Should be false because this node already exists 486 | assertFalse(graph.addEdge(1, 2)); // Should be false because this edge already exists 487 | assertFalse(graph.addEdge(1, 3)); // Should be false because this edge already exists 488 | assertFalse(graph.addEdge(2, 3)); // Should be false because this edge already exists 489 | System.out.println(); 490 | } 491 | 492 | /** 493 | * Performs an extra test on readWordGraph() method 494 | * @throws IOException Throw if the file with given name is not found 495 | */ 496 | @Test 497 | public void extraTestReadWordGraph_2() throws IOException { 498 | Graph graph = WordLadders.readWordGraph("testWordGraph2.txt"); 499 | assertNotNull(graph); 500 | assertFalse(graph.addNode(1, "apple")); // Should be false because this node already exists 501 | assertFalse(graph.addNode(2, "banana")); // Should be false because this node already exists 502 | assertFalse(graph.addNode(3, "orange")); // Should be false because this node already exists 503 | assertFalse(graph.addNode(4, "cherry")); // Should be false because this node already exists 504 | assertFalse(graph.addEdge(1, 2)); // Should be false because this edge already exists 505 | assertFalse(graph.addEdge(1, 3)); // Should be false because this edge already exists 506 | assertFalse(graph.addEdge(2, 3)); // Should be false because this edge already exists 507 | assertTrue(graph.addEdge(1, 4)); // Should be true because this edge does not already exist 508 | assertTrue(graph.addEdge(2, 4)); // Should be true because this edge does not already exist 509 | assertTrue(graph.addEdge(3, 4)); // Should be true because this edge does not already exist 510 | } 511 | 512 | /** 513 | * Testing the WordLadders class's Main method using Java's ByteArrayInputStream (with the file "Length3WordGraph" 514 | * and start word "duo" and end word "eke" as well as when the user does not enter any words to test if the program 515 | * will correctly halt; Also test when the user enters an invalid search type as well as when the user enters words 516 | * that do not exist in the file.) BE SURE TO MONITOR THE OUTPUTS OF THE PROGRAM WHEN RUNNING THIS TEST METHOD! 517 | */ 518 | @Test 519 | public void testWordLaddersMainMethod() { 520 | System.out.println(); 521 | System.out.println("TESTING THE MAIN METHOD OF WORDLADDERS:"); 522 | // Case 1: Test when the user enters valid words and the program should return a valid path: 523 | System.out.println("First, test with valid starting and ending words:"); 524 | System.out.println(); 525 | String input = "Length3WordGraph\n" + 526 | "duo\n" + 527 | "eke\n" + 528 | "BFS\n"; 529 | System.setIn(new ByteArrayInputStream(input.getBytes())); 530 | Scanner scanner = new Scanner(System.in); 531 | WordLadders.main(new String[]{}); 532 | scanner.close(); 533 | System.out.println(); 534 | System.out.println(); 535 | // Case 2: Test when the user enters no words and the program should stop: 536 | System.out.println("Second, test if the program will end when the user stops entering words:"); 537 | System.out.println(); 538 | String input2 = "Length3WordGraph\n" + 539 | "\n" + 540 | "\n"; 541 | System.setIn(new ByteArrayInputStream(input2.getBytes())); 542 | Scanner scanner2 = new Scanner(System.in); 543 | WordLadders.main(new String[]{}); 544 | scanner2.close(); 545 | System.out.println(); 546 | // Case 3: Test when the user enters invalid words and the program should return a blank path 547 | System.out.println("Third, test with invalid starting and ending words:"); 548 | System.out.println(); 549 | String input3 = "Length3WordGraph\n" + 550 | "bruh\n" + 551 | "xxyz\n"; 552 | System.setIn(new ByteArrayInputStream(input3.getBytes())); 553 | Scanner scanner3 = new Scanner(System.in); 554 | WordLadders.main(new String[]{}); 555 | scanner3.close(); 556 | System.out.println(); 557 | System.out.println(); 558 | // Case 4: Test when the user enters invalid search type 559 | System.out.println("Fourth, test when the user enters invalid search type:"); 560 | System.out.println(); 561 | String input4 = "Length3WordGraph\n" + 562 | "duo\n" + 563 | "eke\n" + 564 | "XYZ\n"; 565 | System.setIn(new ByteArrayInputStream(input4.getBytes())); 566 | Scanner scanner4 = new Scanner(System.in); 567 | WordLadders.main(new String[]{}); 568 | scanner4.close(); 569 | System.out.println(); 570 | System.out.println(); 571 | // Case 5: Test when the user enters invalid filename 572 | System.out.println("Fifth, test when the user enters an invalid filename:"); 573 | System.out.println(); 574 | String input5 = "InvalidFilename\n" + 575 | "duo\n" + 576 | "eke\n" + 577 | "XYZ\n"; 578 | System.setIn(new ByteArrayInputStream(input5.getBytes())); 579 | Scanner scanner5 = new Scanner(System.in); 580 | WordLadders.main(new String[]{}); 581 | scanner5.close(); 582 | System.out.println(); 583 | System.out.println(); 584 | System.out.println("Testing the WordLadders.Main() method is complete."); 585 | // Case 6: Test when the user enters chooses DFS as search type 586 | System.out.println("Sixth, test when the user chooses DFS as search type:"); 587 | System.out.println(); 588 | String input6 = "Length3WordGraph\n" + 589 | "due\n" + 590 | "due\n" + 591 | "DFS\n"; 592 | System.setIn(new ByteArrayInputStream(input6.getBytes())); 593 | Scanner scanner6 = new Scanner(System.in); 594 | WordLadders.main(new String[]{}); 595 | scanner6.close(); 596 | System.out.println(); 597 | System.out.println(); 598 | } 599 | 600 | /** 601 | * Test the readWordGraph() method with LargeWordGraph_SmallerFileForExtraTest file with 10,000 lines of data 602 | */ 603 | @Test 604 | public void extraTestReadWordGraphWithVeryLargeWordGraph() { 605 | System.out.println(); // Test if readWordGraph() can process the given file 606 | System.out.println("Test the readWordGraph() method with LargeWordGraph_SmallerFileForExtraTest file:"); 607 | String filename = "LargeWordGraph_SmallerFileForExtraTest"; 608 | Graph wordGraph = WordLadders.readWordGraph(filename); 609 | assertNotNull(wordGraph); 610 | System.out.println(); 611 | } 612 | 613 | /** 614 | * Extra Test on printGraph() method with Integer data types 615 | */ 616 | @Test 617 | public void extraTestPrintGraph2() { 618 | System.out.println("Test the printGraph() method with Integer data types:"); 619 | Graph graph = new Graph(); 620 | graph.addNode(1, null); 621 | graph.addNode(2, null); 622 | graph.addNode(3, null); 623 | graph.addNode(4, null); 624 | graph.addEdge(1, 2); 625 | graph.addEdge(1, 3); 626 | graph.addEdge(1, 4); 627 | graph.addEdge(2, 3); 628 | graph.addEdge(2, 4); 629 | graph.addEdge(3, 4); 630 | graph.printGraph(); 631 | System.out.println(); 632 | } 633 | 634 | /** 635 | * Extra Test on printGraph() method with Character and Double data types 636 | */ 637 | @Test 638 | public void extraTestPrintGraph3() { 639 | System.out.println("Test the printGraph() method with Character and Double data types:"); 640 | Graph charGraph = new Graph(); 641 | charGraph.addNode('A', 1.1); 642 | charGraph.addNode('D', 4.4); 643 | charGraph.addNode('C', 3.3); 644 | charGraph.addNode('B', 2.2); 645 | charGraph.addEdge('A', 'B'); 646 | charGraph.addEdge('A', 'C'); 647 | charGraph.addEdge('B', 'C'); 648 | charGraph.addEdge('C', 'D'); 649 | charGraph.printGraph(); 650 | System.out.println(); 651 | } 652 | 653 | /** 654 | * A class that helps test the printGraph() method 655 | * 656 | * @author David Nguyen 657 | * @since 04/30/2023 658 | * @version 1.0 659 | */ 660 | public class CustomKeyClass { 661 | 662 | // A field that stores the name of the customKeyClass 663 | private String name; 664 | 665 | /** 666 | * Constructor for CustomKeyClass class 667 | * @param name Name for CustomKeyClass object 668 | */ 669 | public CustomKeyClass(String name) { 670 | this.name = name; 671 | } 672 | 673 | /** 674 | * A method that converts this object to its String representation 675 | * @return This CustomKeyClass object's String representation 676 | */ 677 | @Override 678 | public String toString() { 679 | return name; 680 | } 681 | 682 | } 683 | 684 | /** 685 | * Extra Test on printGraph() method with CustomKeyClass and String data types 686 | */ 687 | @Test 688 | public void extraTestPrintGraph4() { 689 | System.out.println("Test the printGraph() method with CustomKeyClass and String data types:"); 690 | Graph customGraph = new Graph(); 691 | CustomKeyClass node1 = new CustomKeyClass("X"); 692 | CustomKeyClass node2 = new CustomKeyClass("Y"); 693 | CustomKeyClass node3 = new CustomKeyClass("Z"); 694 | CustomKeyClass node4 = new CustomKeyClass("W"); 695 | customGraph.addNode(node1, "Data1"); 696 | customGraph.addNode(node2, "Data2"); 697 | customGraph.addNode(node3, "Data3"); 698 | customGraph.addNode(node4, "Data4"); 699 | customGraph.addEdge(node1, node2); 700 | customGraph.addEdge(node1, node3); 701 | customGraph.addEdge(node2, node3); 702 | customGraph.addEdge(node3, node4); 703 | customGraph.printGraph(); 704 | System.out.println(); 705 | } 706 | 707 | /** 708 | * Extra Test on printGraph() method with LocalDate and Double data types 709 | */ 710 | @Test 711 | public void extraTestPrintGraph5() { 712 | System.out.println("Test the printGraph() method with LocalDate and Double data types:"); 713 | Graph dateGraph = new Graph(); 714 | LocalDate date1 = LocalDate.of(2020, Month.JANUARY, 1); 715 | LocalDate date2 = LocalDate.of(2020, Month.FEBRUARY, 1); 716 | LocalDate date3 = LocalDate.of(2020, Month.MARCH, 1); 717 | LocalDate date4 = LocalDate.of(2020, Month.APRIL, 1); 718 | dateGraph.addNode(date1, 1.1); 719 | dateGraph.addNode(date2, 2.2); 720 | dateGraph.addNode(date3, 3.3); 721 | dateGraph.addNode(date4, 4.4); 722 | dateGraph.addEdge(date1, date2); 723 | dateGraph.addEdge(date1, date3); 724 | dateGraph.addEdge(date2, date3); 725 | dateGraph.addEdge(date3, date4); 726 | dateGraph.printGraph(); 727 | System.out.println(); 728 | } 729 | 730 | /** 731 | * Extra Test on printGraph() method with Boolean and String data types 732 | */ 733 | @Test 734 | public void extraTestPrintGraph6() { 735 | System.out.println("Test the printGraph() method with Boolean and String data types:"); 736 | Graph booleanGraph = new Graph(); 737 | booleanGraph.addNode(true, "TrueNode"); 738 | booleanGraph.addNode(false, "FalseNode"); 739 | booleanGraph.addEdge(true, false); 740 | booleanGraph.printGraph(); 741 | System.out.println(); 742 | } 743 | 744 | /** 745 | * Extra test for DFS() and BFS() methods 746 | */ 747 | @Test 748 | public void extraTestDFSandBFS() { 749 | Graph graph = new Graph(); 750 | // Add nodes to the graph 751 | graph.addNode("A", null); 752 | graph.addNode("B", null); 753 | graph.addNode("C", null); 754 | graph.addNode("D", null); 755 | graph.addNode("E", null); 756 | // Add edges between nodes 757 | graph.addEdge("A", "B"); 758 | graph.addEdge("A", "C"); 759 | graph.addEdge("B", "D"); 760 | graph.addEdge("B", "E"); 761 | graph.addEdge("C", "E"); 762 | // Test cases: 763 | // 1. DFS with Valid path: 764 | Object[] expectedPath1 = new Object[]{"A", "B", "D"}; 765 | assertArrayEquals(expectedPath1, graph.DFS("A", "D")); 766 | // 2. DFS with Valid path with multiple branches: 767 | Object[] expectedPath2 = new Object[]{"A", "B", "E"}; 768 | assertArrayEquals(expectedPath2, graph.DFS("A", "E")); 769 | // 3. DFS with Non-existent path: 770 | Object[] expectedPath3 = new Object[]{"D", "B", "A", "C"}; 771 | assertArrayEquals(expectedPath3, graph.DFS("D", "C")); 772 | // 4. DFS with Non-existent node: 773 | Object[] expectedPath4 = new Object[]{}; 774 | assertArrayEquals(expectedPath4, graph.DFS("A", "F")); 775 | // 5. DFS with Null node: 776 | assertArrayEquals(expectedPath4, graph.DFS("A", null)); 777 | assertArrayEquals(expectedPath4, graph.DFS(null, "D")); 778 | assertArrayEquals(expectedPath4, graph.DFS(null, null)); 779 | // 6. BFS with Valid path: 780 | Object[] expectedPath5 = new Object[]{"D", "B", "A", "C", "E"}; 781 | assertArrayEquals(expectedPath5, graph.DFS("D", "E")); 782 | // 7. BFS with Valid path: 783 | Object[] expectedPath6 = new Object[]{"D", "B", "E"}; 784 | assertArrayEquals(expectedPath6, graph.BFS("D", "E")); 785 | // 8. BFS with Valid path: 786 | Object[] expectedPath7 = new Object[]{"A", "B", "E"}; 787 | assertArrayEquals(expectedPath7, graph.BFS("A", "E")); 788 | // 9. BFS with Invalid path: 789 | Object[] expectedPath8 = new Object[]{}; 790 | assertArrayEquals(expectedPath8, graph.BFS("A", "F")); 791 | // 10. BFS with NULL path: 792 | Object[] expectedPath9 = new Object[]{}; 793 | assertArrayEquals(expectedPath9, graph.BFS("A", null)); 794 | assertArrayEquals(expectedPath9, graph.BFS(null, "E")); 795 | assertArrayEquals(expectedPath9, graph.DFS(null, null)); 796 | } 797 | 798 | } -------------------------------------------------------------------------------- /WordLadders.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.FileReader; 3 | import java.io.IOException; 4 | 5 | import java.util.NoSuchElementException; 6 | import java.util.Scanner; 7 | import java.util.Hashtable; 8 | 9 | /** 10 | * A class that represents a Word Ladders game that is also runnable and playable by running the main method. 11 | * 12 | * @author David Nguyen 13 | * @since 04/30/2023 14 | * @version 1.0 15 | */ 16 | public class WordLadders { 17 | 18 | // A field that stores a hash table that keeps the node names as its keys 19 | private static Hashtable hashTableForWordGraph = new Hashtable(); 20 | 21 | /** 22 | * A Main Method that runs the Word Ladders game/program. This program will work with both the Length3WordGraph and 23 | * LargeWordGraph files. Note that if the user stops entering words (if both starting and ending words are empty), 24 | * the program will stop, per the requirement of the assignment prompt. 25 | * Note that when the LargeWordGraph file is chosen, it will take a while to process all 48,000 lines in it. 26 | * Normally it will take approximately 20-40 seconds to complete processing the graph, depending on the computer's 27 | * processing power. 28 | * 29 | * @param args Any parameter to run the game/program with. 30 | */ 31 | public static void main(String[] args) { 32 | // A Scanner instance that is used to get the user's inputs (typed) 33 | Scanner userInputsGetter = new Scanner(System.in); 34 | try { 35 | // Prompts the user to enter the filename of their desired file 36 | System.out.print("Please enter the filename you wish to use: "); 37 | // Gets the user's input 38 | String fileNameFromUser = userInputsGetter.nextLine(); 39 | // Checks if the user has entered a valid filename 40 | boolean isValidFileName = checkFileName(fileNameFromUser); 41 | // Now, if the user has entered a valid filename: 42 | if (isValidFileName == true) { 43 | // Prompts the user that the program is now reading the file with the given name and asks them to wait 44 | System.out.println("We're now reading the file and constructing the word graph. Please wait..."); 45 | // A graph that reads the words from the given input file and will construct a word ladder from it 46 | Graph graphForWordLadder = readWordGraph(fileNameFromUser); 47 | // Prompts the user that the program has now finished constructing the word graph based on the given file 48 | System.out.println("Your word graph has been constructed!"); 49 | // A variable that stores whether the program will be continued or not 50 | boolean continueProgram = true; 51 | // A loop that technically runs for forever unless ended by the user and performs the following tasks: 52 | while (continueProgram == true) { 53 | // Prompts the user to enter their starting word from which a path will be found 54 | System.out.print("Please enter the STARTING word: "); 55 | // Stores the starting word that user typed in 56 | String startingWord = userInputsGetter.nextLine(); 57 | // Prompts the user to enter their starting word to which a path will be found 58 | System.out.print("Please enter the ENDING word: "); 59 | // Stores the starting word that user typed in 60 | String endingWord = userInputsGetter.nextLine(); 61 | /* 62 | * If the entered words are empty (no character entered), break the loop and end the program as they are 63 | * invalid inputs and the program is required to stop when the user stops entering words 64 | */ 65 | if ((startingWord.isEmpty() == true && endingWord.isEmpty() == true)) { 66 | // Also prompts the user that the program will halt and breaks it 67 | System.out.println("You have not entered any words, so the program will be stopped. Feel free to " + 68 | "re-run it anytime!"); 69 | break; 70 | } 71 | // Otherwise, let the program continue as normal 72 | else { 73 | ; 74 | } 75 | // If the entered words are null, break the loop and end the program as they are invalid inputs 76 | if ((startingWord == null && endingWord == null)) { 77 | // Also prompts the user that the program will halt and breaks it 78 | System.out.println("You have not entered any words, so the program will be stopped. Feel free to " + 79 | "re-run it anytime!"); 80 | break; 81 | } 82 | // Otherwise, let the program continue as normal 83 | else { 84 | ; 85 | } 86 | // A variable that stores the Integer value of the starting node 87 | Integer valueOfStartingNode = hashTableForWordGraph.get(startingWord); 88 | // A variable that stores the Integer value of the ending node 89 | Integer valueOfEndingNode = hashTableForWordGraph.get(endingWord); 90 | // Prompts the user to enter the search type - BFS or DFS 91 | System.out.print("Enter search type (DFS or BFS): "); 92 | // Gets the user's input for the search type - BFS or DFS 93 | String searchType = userInputsGetter.nextLine(); 94 | // Prompts that the program will now perform their requested search 95 | System.out.println("Now we will perform " + searchType + " to get your desired word ladder!"); 96 | // Adds a whitespace for aesthetics 97 | System.out.println(); 98 | // A variable array that stores the path from the starting to the ending word 99 | Object[] pathFromStartingToEndingWord = new Object[]{}; 100 | // Now, if the user requests DFS search type, perform DFS between their requested words 101 | if (searchType.equalsIgnoreCase("DFS")) { 102 | pathFromStartingToEndingWord = graphForWordLadder.DFS(valueOfStartingNode, valueOfEndingNode); 103 | } 104 | // Else, if the user requests BFS search type, perform BFS between their requested words 105 | else if (searchType.equalsIgnoreCase("BFS")) { 106 | pathFromStartingToEndingWord = graphForWordLadder.BFS(valueOfStartingNode, valueOfEndingNode); 107 | } 108 | // Otherwise, the user has likely entered an invalid search type. Prompt them to use only DFS or BFS. 109 | else { 110 | System.out.println("You have entered a NON-VALID search technique. Please use only DFS or BFS!"); 111 | // Skips this iteration of the above while-loop 112 | continue; 113 | } 114 | // First, if no path can be found, prompts the user that no paths can be found between their two given words 115 | if (pathFromStartingToEndingWord == null || pathFromStartingToEndingWord.length <= 0) { 116 | System.out.println("No path can be found between your two specified words! Try again with other " + 117 | "pair of words."); 118 | System.out.println(); 119 | } 120 | /* 121 | * Otherwise, if there is a path between the starting and ending words and the path's length is greater than 122 | * 0, print it to the screen and do the following: 123 | */ 124 | else { 125 | // Prompts the user that their word ladder is now ready 126 | System.out.println("The Word Ladder Is Below: "); 127 | // Prints a whitespace for aesthetic purposes and to easily distinguish the word ladder later on 128 | System.out.println(); 129 | // Prints the word ladder to the screen (i.e. the path between two words the user enters) 130 | for (int index = 0; index < pathFromStartingToEndingWord.length; index = index + 1) { 131 | // A variable that stores the key of the current node to be printed 132 | Integer currentNode = (Integer) pathFromStartingToEndingWord[index]; 133 | /* 134 | * A variable that stores the value of the current node to be printed (this will be printed to 135 | * the screen): 136 | */ 137 | String singleWordInWordLadder = lookUpWordFromHashTable(currentNode); 138 | // Print the words to the screen in a vertical format (to make it look like a LADDER!): 139 | System.out.print(singleWordInWordLadder); 140 | System.out.println(); 141 | } 142 | /* 143 | * Prompts the user that they can play this game again and repeatedly. Also adds some spaces for extra 144 | * aesthetics so that the program display can be easier for the user to look at! 145 | */ 146 | System.out.println(); 147 | System.out.println("You can also play with this Word Ladder game again!"); 148 | System.out.println(); 149 | } 150 | } 151 | } 152 | // Otherwise, if the user has entered an invalid filename: 153 | else { 154 | // We will halt the program and prompt the user to try running it again with another filename 155 | System.out.println("You have entered an invalid filename! Try running the program again with " + 156 | "Length3WordGraph or LargeWordGraph only!"); 157 | } 158 | } 159 | // If a NoSuchElementException is caught, close the userInputsGetter and to stop getting the user's input 160 | catch (NoSuchElementException exception) { 161 | // Stops the program here 162 | userInputsGetter.close(); 163 | } 164 | /* 165 | * Even if no exception is caught, if no input is got from the user, still close the userInputsGetter 166 | * and stop getting the user's input: 167 | */ 168 | finally { 169 | // Stops the program here 170 | userInputsGetter.close(); 171 | } 172 | } 173 | 174 | /** 175 | * A method that constructs a graph from a text file using the following format: (nodename1) (nodedata1) (neighbor1) 176 | * (neighbor2) (neighbor3) and (nodenade2) (nodedata2) (neighbor2) (neighbor2) (neighbor3) ... with each node name 177 | * is of type Integer and each node data is of type String. 178 | * 179 | * @param filename The specified name of file from which a new graph will be constructed. 180 | * @return A new graph that has its value of type String and its key of type Integer that is constructed from the 181 | * given file. 182 | */ 183 | public static Graph readWordGraph(String filename) { 184 | // A variable that stores a graph that will be constructed and returned after reading in the file with given filename 185 | Graph graphConstructedForGivenFile = new Graph(); 186 | // A variable that keeps track of the number of lines from the word graph that have been processed by the program 187 | int numberOfLinesProcessed = 0; 188 | /* 189 | * A variable that helps the program display notification messages to System.out to notify the user of the 190 | * progress of the reading process 191 | */ 192 | int notificationForEvery1000LinesProcessed = 1000; 193 | // Try-catch block to detect possible IOException from invalid file or filename 194 | try { 195 | // A variable of type FileReader to open the file and read it to the program with the given filename 196 | FileReader fileReaderForGivenFileName = new FileReader(filename); 197 | // A variable of type BufferedReader to create a buffered reader to read the file line by line 198 | BufferedReader bufferedReaderForGivenFileName = new BufferedReader(fileReaderForGivenFileName); 199 | // A variable that stores the index for adding the neighbors to the graph 200 | int indexForAddingNeighborsToGraph = 1; 201 | // A variable to store each line in the file 202 | String everySingleLineInFile = new String(); 203 | // A loop that loops through all lines in the file to read them and construct nodes in the graph from them 204 | while ((everySingleLineInFile = bufferedReaderForGivenFileName.readLine()) != null) { 205 | // Increment the numLinesProcessed variable by 1 for every line processed 206 | numberOfLinesProcessed = numberOfLinesProcessed + 1; 207 | // Provide the user with a notification update of the process for each 1,000 lines processed 208 | if ((numberOfLinesProcessed % notificationForEvery1000LinesProcessed) == 0) { 209 | // Updates the user by printing to System.out with the number of lines processed 210 | System.out.println("We've processed " + numberOfLinesProcessed + " lines. Please wait..."); 211 | } 212 | // Otherwise, let the method continue as normal 213 | else { 214 | ; 215 | } 216 | /* 217 | * For each 20,000 lines processed, notify them that the program is still processing their request and 218 | * ask them to wait for a bit more~ 219 | */ 220 | if ((numberOfLinesProcessed % 10000) == 0) { 221 | System.out.println("This file is a fairly large one. Please hold on and we'll get it ready soon!"); 222 | } 223 | // Otherwise, let the method continue as normal 224 | else { 225 | ; 226 | } 227 | /* 228 | * Now, split the line into an array of strings using whitespace as the delimiter and store it in a variable 229 | * of type String. For example, the resulting String[] array will now contain: [nodename1, nodedata1, 230 | * neighbor1, neighbor2, neighbor3, and so on]: 231 | */ 232 | String[] splitLinesInFile = everySingleLineInFile.split(" "); 233 | /* 234 | * If the split line's length is smaller than the index variable above, skip this iteration and goes 235 | * onto the next 236 | */ 237 | if (splitLinesInFile.length < indexForAddingNeighborsToGraph) { 238 | continue; 239 | } 240 | // Otherwise, let the method continue as normal 241 | else { 242 | ; 243 | } 244 | // A variable that reads the current split line in the file 245 | String currentSplitLineInFile = splitLinesInFile[0]; 246 | // A variable that represents and stores the key of the current split line and its associated node 247 | Integer keyOfCurrentNode = Integer.parseInt(currentSplitLineInFile); 248 | // A variable that represents and stores the value of the current node 249 | String valueOfCurrentNode = splitLinesInFile[1]; 250 | // Add the above pair of key and value to the graph to be constructed 251 | graphConstructedForGivenFile.addNode(keyOfCurrentNode, valueOfCurrentNode); 252 | // Add the above pair of key and value to the hashtable for the word graph to be constructed 253 | hashTableForWordGraph.put(valueOfCurrentNode, keyOfCurrentNode); 254 | // A loop that iterates through the split lines read from the file and add the neighbors of the current nodes 255 | for (int index = (indexForAddingNeighborsToGraph) + 1; index < splitLinesInFile.length; index = index + 1) { 256 | // A variable that stores the current line being read from the file 257 | String currentLineInFile = splitLinesInFile[index]; 258 | // A variable that stores the values of the neighbor nodes of the current node 259 | Integer valueOfNeighborNodeOfCurrentNode = Integer.parseInt(currentLineInFile); 260 | // Add the edges between them to the graph above 261 | graphConstructedForGivenFile.addEdge(keyOfCurrentNode, valueOfNeighborNodeOfCurrentNode); 262 | } 263 | } 264 | // Stops and closes the reader for the file as the reading operation is now complete 265 | bufferedReaderForGivenFileName.close(); 266 | } 267 | // If an IOException is caught, prompts the user that the given file is invalid 268 | catch (IOException exception) { 269 | System.out.println("The given filename is INVALID and the file cannot be read!"); 270 | } 271 | // Return the constructed graph from the given file 272 | return graphConstructedForGivenFile; 273 | } 274 | 275 | /** 276 | * A helper method that lookups words from the hash table given an Integer value. The hashtable field was set up in 277 | * a way that allows for the quick look up of word nodes by their keys. This method is, therefore, quick & efficient. 278 | * 279 | * @param valueToLookUpWordWith Any Integer value to look up its associated String key with. 280 | * @return The String key associated with the given Integer value. Return null if no key in the table matches the 281 | * given Integer value. 282 | */ 283 | private static String lookUpWordFromHashTable(Integer valueToLookUpWordWith) { 284 | // A loop that iterates through the hash table's keys to find the matching value and return the associated key 285 | for (String tempWordInHashTable : hashTableForWordGraph.keySet()) { 286 | // A variable that stores a temporary value from the hash table during the execution of the loop 287 | Integer valueOfWordInHashTable = hashTableForWordGraph.get(tempWordInHashTable); 288 | // If a matching value in the hash table is found, return its associated String key 289 | if (valueOfWordInHashTable.equals(valueToLookUpWordWith)) { 290 | return tempWordInHashTable; 291 | } 292 | // Otherwise, let the method continue as normal 293 | else { 294 | ; 295 | } 296 | } 297 | // Return null if no key in the table matches the given Integer value. 298 | return null; 299 | } 300 | 301 | /** 302 | * A helper that checks if the user has entered a valid filename. 303 | * 304 | * @param fileName The filename that the user enters. 305 | * @return True or false depending on the validity of the given filename. 306 | */ 307 | private static boolean checkFileName(String fileName) { 308 | // Try-catch block to determine if the user has entered a valid filename 309 | try { 310 | // A variable to stores the FileReader to read the file 311 | FileReader fileReader = new FileReader(fileName); 312 | // Close the file reader if the user has entered a valid filename 313 | fileReader.close(); 314 | // Return true in this case 315 | return true; 316 | } 317 | // If an IOException is caught, the user has entered an invalid filename 318 | catch (IOException e) { 319 | // Return false in this case 320 | return false; 321 | } 322 | } 323 | 324 | } 325 | -------------------------------------------------------------------------------- /out/production/Graph-Data-Structure/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /out/production/Graph-Data-Structure/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /out/production/Graph-Data-Structure/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /out/production/Graph-Data-Structure/.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /out/production/Graph-Data-Structure/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /out/production/Graph-Data-Structure/Graph$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Graph-Data-Structure/e1b524e4e913bd21f3824fefcb2fb4188935e32c/out/production/Graph-Data-Structure/Graph$1.class -------------------------------------------------------------------------------- /out/production/Graph-Data-Structure/Graph$2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Graph-Data-Structure/e1b524e4e913bd21f3824fefcb2fb4188935e32c/out/production/Graph-Data-Structure/Graph$2.class -------------------------------------------------------------------------------- /out/production/Graph-Data-Structure/Graph$GraphNode.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Graph-Data-Structure/e1b524e4e913bd21f3824fefcb2fb4188935e32c/out/production/Graph-Data-Structure/Graph$GraphNode.class -------------------------------------------------------------------------------- /out/production/Graph-Data-Structure/Graph-Data-Structure.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /out/production/Graph-Data-Structure/Graph.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Graph-Data-Structure/e1b524e4e913bd21f3824fefcb2fb4188935e32c/out/production/Graph-Data-Structure/Graph.class -------------------------------------------------------------------------------- /out/production/Graph-Data-Structure/Tester$CustomKeyClass.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Graph-Data-Structure/e1b524e4e913bd21f3824fefcb2fb4188935e32c/out/production/Graph-Data-Structure/Tester$CustomKeyClass.class -------------------------------------------------------------------------------- /out/production/Graph-Data-Structure/Tester.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Graph-Data-Structure/e1b524e4e913bd21f3824fefcb2fb4188935e32c/out/production/Graph-Data-Structure/Tester.class -------------------------------------------------------------------------------- /out/production/Graph-Data-Structure/WordLadders.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoangsonww/Graph-Data-Structure/e1b524e4e913bd21f3824fefcb2fb4188935e32c/out/production/Graph-Data-Structure/WordLadders.class -------------------------------------------------------------------------------- /out/production/Graph-Data-Structure/testFileForRead.txt: -------------------------------------------------------------------------------- 1 | A B C D 2 | B A C 3 | C A B 4 | D A -------------------------------------------------------------------------------- /out/production/Graph-Data-Structure/testWordGraph.txt: -------------------------------------------------------------------------------- 1 | 1 apple 2 3 2 | 2 banana 1 3 3 | 3 orange 1 2 4 | -------------------------------------------------------------------------------- /out/production/Graph-Data-Structure/testWordGraph2.txt: -------------------------------------------------------------------------------- 1 | 1 apple 2 3 2 | 2 banana 1 3 3 | 3 orange 1 2 4 | 4 cherry -------------------------------------------------------------------------------- /out/production/Graph-Data-Structure/text_input.txt: -------------------------------------------------------------------------------- 1 | A B C 2 | B A C 3 | C A B -------------------------------------------------------------------------------- /testFileForRead.txt: -------------------------------------------------------------------------------- 1 | A B C D 2 | B A C 3 | C A B 4 | D A -------------------------------------------------------------------------------- /testWordGraph.txt: -------------------------------------------------------------------------------- 1 | 1 apple 2 3 2 | 2 banana 1 3 3 | 3 orange 1 2 4 | -------------------------------------------------------------------------------- /testWordGraph2.txt: -------------------------------------------------------------------------------- 1 | 1 apple 2 3 2 | 2 banana 1 3 3 | 3 orange 1 2 4 | 4 cherry -------------------------------------------------------------------------------- /text_input.txt: -------------------------------------------------------------------------------- 1 | A B C 2 | B A C 3 | C A B --------------------------------------------------------------------------------