Word Ladder
Given a start word and a goal word, convert the start word to the goal word by changing one letter at a time. Each step must also be a valid word.
Is my code modular? I mean are functions are concise, class design etc.? Could someone please review the code and let me know if code is good and if it has some design issues. Any tips on improving the design, and making the code cleaner, change variable names?
Used dictionary at this URL.
package test1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class WordLadder {
private final HashSet<String> dic= new HashSet<>();
private final List<Node> nodeQ= new LinkedList<>();
private final HashSet<Node> visitedNodes= new HashSet<>();
private final String in;
private final String target;
public WordLadder(String i, String t){
in=i;
target= t;
}
public static void main(String[] args) throws IOException {
WordLadder wl= new WordLadder("stone","money");
//WordLadder wl= new WordLadder("stone","chore");
//WordLadder wl= new WordLadder("stone","choky");
//WordLadder wl= new WordLadder("charge","comedo"); //takes time ~ 3 mins- seems hardest
wl.loadDictionary();
if(!wl.dic.contains(wl.in)||!wl.dic.contains(wl.target)){
System.out.println("error words not in dic");
}
wl.nodeQ.add(new Node(wl.in));
wl.getPaths();
}
private void getPaths(){
long st= System.currentTimeMillis();
while(!isMatchFound()){
Node n= selectNext();
nodeQ.remove(n);
addNextWordsToQ(n);
visitedNodes.add(n);
}
System.out.println("nodeQ- \n"+nodeQ);
System.out.println("visitedNodes- \n"+visitedNodes);
long end= System.currentTimeMillis();
System.out.println("time taken in sec~ "+ (end-st)/1000);
System.out.println("time taken in min~ "+ (end-st)/60000);
}
private Node selectNext(){
Node sel= null;
int minMatch=-1;
int match;
for(Node n: nodeQ){
match=0;
for(int i=0; i<target.length(); i++){
if(n.str.charAt(i)== target.charAt(i)) {
match++;
}
}
if(match>minMatch){
sel=n;
minMatch=match;
}
}
// System.out.println(sel.str+" "+minMatch);
return sel;
}
//Add next possible combinations to the nodeQ
private void addNextWordsToQ(Node n){
String s= n.str;
for(int i=0;i<s.length();i++){
String regex= s.substring(0,i)+"."+s.substring(i+1);
Pattern p= Pattern.compile(regex);
for(String d: dic){
Matcher m= p.matcher(d);
if(!d.equals(s) && s.length()==d.length()
&& m.find() && !isNodeVisited(d)){
nodeQ.add(new Node(d,n));
}
}
}
}
//Check nodeQ to see if word ladder is solved
private boolean isMatchFound(){
for(Node n: nodeQ){
if(target.equals(n.str)){
System.out.println(n);
return true;
}
}
return false;
}
private boolean isNodeVisited(String add){
for(Node n: visitedNodes){
if(n.str.equals(add)){
return true;
}
}
return false;
}
private void loadDictionary() throws IOException{
InputStream is= WordLadder.class.getClassLoader().getResourceAsStream("dictionary.txt");
BufferedReader br= new BufferedReader(new InputStreamReader(is));
String s= br.readLine();
while(s!=null){
dic.add(s);
s= br.readLine();
}
}
}
class Node{
String str;
final List<String> path= new ArrayList<>();
public Node(String str){
this.str=str;
}
public Node(String str, Node parent){
this.str=str;
path.addAll(parent.path);
path.add(parent.str);
}
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((str == null) ? 0 : str.hashCode());
return result;
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Node other = (Node) obj;
if (str == null) {
if (other.str != null)
return false;
} else if (!str.equals(other.str))
return false;
return true;
}
public String toString() {
return "\n" + str + ", " + path+ "";
}
}