Permalink
Browse files

initial 2003 release

  • Loading branch information...
0 parents commit 7f2ac37ab2a89241c54a2ca7c4ba8bdbbe7fe044 @kylecordes committed Jun 3, 2010
Showing with 255 additions and 0 deletions.
  1. +7 −0 .classpath
  2. +2 −0 .gitignore
  3. +17 −0 .project
  4. +16 −0 README.txt
  5. +125 −0 src/wordchain/ChainFinder.java
  6. +77 −0 src/wordchain/ChainTest.java
  7. +11 −0 src/wordchain/WordNotInDictionaryException.java
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="var" path="JUNIT_HOME/junit.jar"/>
+ <classpathentry kind="output" path="classes"/>
+</classpath>
@@ -0,0 +1,2 @@
+classes
+*~
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>Kata19</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
@@ -0,0 +1,16 @@
+PragProg Code Kata 19
+
+Kyle Cordes's solution
+
+Copyright 2003 Kyle Cordes
+
+More info online:
+
+http://kylecordes.com/2003/pragdave-kata-19
+
+I�ve been watching PragDave�s Code Katas with interest, since I am also in the habit of occassionally solve a small, standalone programming problem just for the learning experience. Today I worked out a solution for Kata 19, Word Chains. I did this Kata the �pure� way, i.e. without looking at any of the discussion of solution approaches before coding. Here are the results. I wrote the code this time in Java.
+
+Unlike Dave�s published solution, I didn�t precalculate adjacency lists; rather I took the more brute-force approach of scanning the word list at each step looking for neighbor words. In spite of that non-optimization, this still calculates the word chains for a bunch of examples in a few seconds (total).
+
+I was curious how much of the program�s time is spent checking for neighbor words; this provided a good reason to try out a profiler plug for Eclipse, available on SourceForge. The profiler worked fine, and told me, as I would have guessed, that the program spends approximately 100% of it�s time looking at words to decide if they are neighbors (in the word-chains sense). Of course the usual optimization advice applies: it would have been actively stupid of me to optimize without measuring where the slow parts are.
+
@@ -0,0 +1,125 @@
+/*
+ * Created on Nov 16, 2003
+ */
+package wordchain;
+
+import java.util.*;
+import java.io.*;
+
+/**
+ * @author Kyle
+ */
+public class ChainFinder {
+
+ List words;
+
+ private void readWordsOfLength(int wordLength) throws IOException {
+ words = new ArrayList();
+ BufferedReader r = new BufferedReader(new FileReader("wordlist.txt"));
+ try {
+ String line;
+ while ((line = r.readLine()) != null) {
+ if(line.length() == wordLength)
+ words.add(line);
+ }
+ } finally {
+ r.close();
+ }
+ }
+
+ private void checkIsWord(String word) throws WordNotInDictionaryException {
+ if (! words.contains(word)) {
+ throw new WordNotInDictionaryException();
+ }
+ }
+
+ List candidates;
+ Map seen;
+ int count;
+
+ public String findChain(String start, String end)
+ throws WordNotInDictionaryException, IOException {
+
+ if (start.length() != end.length())
+ throw new RuntimeException("words must be of the same length");
+
+ if(start.equals(end))
+ return start;
+
+ readWordsOfLength(start.length());
+
+ checkIsWord(start);
+ checkIsWord(end);
+
+ candidates = new LinkedList();
+ seen = new HashMap();
+ count = 0;
+
+ candidates.add(start);
+ seen.put(start, null);
+
+ return searchForEndWord(end);
+ }
+
+ private String searchForEndWord(String end) {
+ while (candidates.size() > 0) {
+ if (count++ > 15000)
+ throw new RuntimeException("exceeded search limit");
+
+ String c = (String) candidates.remove(0);
+
+ Iterator iter = words.iterator();
+ while (iter.hasNext()) {
+ String w = (String) iter.next();
+ if (!seen.containsKey(w) && adjacent(c, w)) {
+ seen.put(w, c);
+
+ if (end.equals(w))
+ return formatWordChain(w);
+
+ candidates.add(w);
+ }
+ }
+ }
+ return null;
+ }
+
+ private String formatWordChain(String word) {
+ String result = word;
+ word = (String) seen.get(word);
+ while (word != null) {
+ result = word + "," + result;
+ word = (String) seen.get(word);
+ }
+ return result;
+ }
+
+ public boolean adjacent(String a, String b) {
+ int nDifferent = 0;
+ int length = a.length();
+ for (int i = 0; i < length; i++) {
+ if (a.charAt(i) != b.charAt(i)) {
+ nDifferent++;
+ }
+ if(nDifferent > 1)
+ return false;
+ }
+ return true;
+ }
+
+ public static void main(String[] args) {
+ ChainFinder cf = new ChainFinder();
+
+ try {
+ System.out.println(cf.findChain("cat", "dog"));
+ System.out.println(cf.findChain("lead", "gold"));
+ System.out.println(cf.findChain("ruby", "code"));
+ System.out.println(cf.findChain("rogue", "Perth"));
+ System.out.println(cf.findChain("crosser", "stouter"));
+ System.out.println(cf.findChain("brushing", "cheating"));
+ System.out.println(cf.findChain("sputtered", "blistered"));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
@@ -0,0 +1,77 @@
+package wordchain;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Kyle
+ */
+public class ChainTest extends TestCase {
+
+ static ChainFinder cf = new ChainFinder();
+
+ public void testAdjacent() {
+ assertTrue(cf.adjacent("coo", "cox"));
+ assertTrue(cf.adjacent("boo", "bpo"));
+ assertTrue(cf.adjacent("angke", "angle"));
+ assertFalse(cf.adjacent("foo", "angle"));
+ assertFalse(cf.adjacent("fox", "mom"));
+ assertFalse(cf.adjacent("berry", "larry"));
+ }
+
+
+ private void checkScenario(String start, String end, String chain)
+ throws WordNotInDictionaryException, IOException {
+ String actualChain = cf.findChain(start, end);
+ if(! chain.equals(actualChain)) {
+ System.out.println("E: " + chain);
+ System.out.println("A: " + actualChain);
+ }
+ assertEquals(chain, actualChain);
+ }
+
+ public void testNoSteps() throws Exception {
+ checkScenario("cat", "cat", "cat");
+ }
+
+ public void testDetectNotInDict() throws Exception {
+ try {
+ checkScenario("cat", "qat", "cat,qat");
+ fail("should have objected to non dict word");
+ } catch (WordNotInDictionaryException eexpected) {
+ // ok
+ }
+ }
+
+ public void testOneStep() throws Exception {
+ checkScenario("cat", "cot", "cat,cot");
+ }
+
+ public void testTwoStep1() throws Exception {
+ checkScenario("cat", "cog", "cat,cot,cog");
+ }
+
+ public void testTwoStep2() throws Exception {
+ checkScenario("lead", "goad", "lead,load,goad");
+ }
+
+ public void testCatDog() throws Exception {
+ checkScenario("cat", "dog", "cat,cot,cog,dog");
+ }
+
+ public void testLeadGold() throws Exception {
+ checkScenario("lead", "gold", "lead,load,goad,gold");
+ }
+
+ public void testRubyCode() throws Exception {
+ //checkScenario("ruby", "code", "ruby,rubs,robs,rods,rode,code");
+ checkScenario("ruby", "code", "ruby,rubs,robs,robe,rode,code");
+ }
+
+ public void testCodeRuby() throws Exception {
+ //checkScenario("code", "ruby", "code,rode,rods,robs,rubs,ruby");
+ checkScenario("code", "ruby", "code,rode,robe,robs,rubs,ruby");
+ }
+
+}
@@ -0,0 +1,11 @@
+/*
+ * Created on Nov 16, 2003
+ */
+package wordchain;
+
+/**
+ * @author Kyle
+ */
+public class WordNotInDictionaryException extends Exception {
+
+}

0 comments on commit 7f2ac37

Please sign in to comment.