Word Spinner Puzzle

10

2

This is a word puzzle.

Your program should accept two words on the standard input.
Word one is the start word. Word two is the end word.

From the start word you have to reach the end word changing/add/remove one letter at a time. After each modification it must form a new valid word. Added letters are added to the beginning or end. You can remove letters from any location (but word must not fall bellow three letters in length). Note: You can not rearrange the letters to form a word.

The output of the program is the sequence of words to get from the start word to the end word.

Example:

Input:
    Post Shot

Output:
    Post
    cost
    coat
    goat
    got
    hot
    shot

Winner:

  • The program must run in a reasonable time (less than a 10 seconds).
  • The program that can generate the shortest output sequence to the prize words.
    • Zink -> Silicon
  • If more than one program gets the shortest sequence then the shortest program in chars (ignoring white space).
  • If we still have more than one program submission date/time shall be used.

Notes:

Martin York

Posted 2011-02-08T08:43:33.007

Reputation: 896

may be "post->pot->hot->shot" is shorter. – YOU – 2011-02-08T09:21:08.660

@S.Mark: Then your algorithm beats mine and you win. The above is an example of a possible solution. A shorter solution beats a longer solution. – Martin York – 2011-02-08T09:24:38.010

intentionally? sorry, I just got it wrong. – YOU – 2011-02-08T09:25:45.783

2

Could I solve it in Whitespace for 0 program size?

– None – 2011-02-08T12:12:02.517

@Tim Nordenfur: I would love to see a white space implementation. Note. there are two rules before program length to decide winner. But if you meet those requirements :-) – Martin York – 2011-02-08T15:56:17.810

What format is that dictionary in? I gunzip'd it but it is still gobbledygook. – Keith Randall – 2011-02-08T16:51:27.130

Ah, I see now. Some idiot decided that compressing it once helped, so why not compress it again? – Keith Randall – 2011-02-08T18:45:10.683

Should the program be able to exit when the end word is not reachable ? (i.e. not run forever) – Arnaud Le Blanc – 2011-02-08T19:43:21.100

@user300: That would be nice. – Martin York – 2011-02-08T20:51:50.620

@Martin, making the dictionary text file to some different format will break the rule? and if not, those prebuilding codes will count towards program code? – YOU – 2011-02-09T01:03:08.507

@ S.Mark: Interested to see where you are going with this. But feel free to change the format of the dictionary (no cost). The dictionary is just to provide a common set of words so that people were not failing because their system/language did not provide an extensive dictionary. – Martin York – 2011-02-09T20:36:38.503

@Martin, ok, I will post tomorrow, but I guess I already failed to golf dijkstra algorithm than 288 char solution :D Anyway, I will post just for reference, since I have no ability to create my own algorithm. – YOU – 2011-02-10T02:36:58.023

Answers

2

Python, 288 characters

(not counting the dictionary reading line)

X=set(open('websters-dictionary').read().upper().split())

(S,E)=raw_input().upper().split()
G={S:0}
def A(w,x):
 if x not in G and x in X:G[x]=w
while E not in G:
 for w in G.copy():
  for i in range(len(w)):
   for c in"ABCDEFGHIJKLMNOPQRSTUVWXYZ":A(w,w[:i]+c+w[i+1:]);A(w,w[:i]+w[i+1:]);A(w,c+w);A(w,w+c)
s=''
while E:s=E+'\n'+s;E=G[E]
print s

for the challenge zink to silicon:

ZINK
PINK
PANK
PANI
PANIC
PINIC
SINIC
SINICO
SILICO
SILICON

There are some strange words in that dictionary...

Keith Randall

Posted 2011-02-08T08:43:33.007

Reputation: 19 865

I did not actually check the content. I just tried to find a dictionary that everybody could use. – Martin York – 2011-02-08T18:56:59.543

try with guester overturn (takes some time) or regatta gyrally (does not returns) ;-) – Arnaud Le Blanc – 2011-02-10T20:57:59.940

Yes, some combinations take a while. The time gets longer as the shortest solution gets longer. And the last one has no solution - there's no spec for what should happen in that case :) It's pretty easy to modify to handle it though (save a handle to G.copy() and compare G against it at the end of the loop). – Keith Randall – 2011-02-11T23:47:20.813

16

traceroute - 10 chars

traceroute 

detail

post#traceroute shot

Type escape sequence to abort.
Tracing the route to shot (1.1.4.2)

  1 pot (1.1.1.2) 40 msec 68 msec 24 msec
  2 hot (1.1.3.2) 16 msec 32 msec 24 msec
  3 shot (1.1.4.2) 52 msec *  92 msec

Routers are preconfigured with OSPF enabled and arranged this way.

enter image description here

And yes, I need 233614 routers to fully support all the words. :-)

YOU

Posted 2011-02-08T08:43:33.007

Reputation: 4 321

Very clever but you fail the 10 second rule. It will take you excessively longer than 10 seconds to configure all the routers. :-) Whats the route from : Zink -> Silicon – Martin York – 2011-02-08T15:53:27.160

@Martin, please be ignore for configuration time, it just like building dictionary, heheh, routes for Zink -> Silicon is zink->pink->pank->pani->panic->pinic->sinic->sinico->silico->silicon I am really trying with Dijkstra algorithm (which is used in OSPF) and its can find that path around 1s, I will post it in seperate post later, once I golfed. – YOU – 2011-02-08T15:59:58.760

3

PHP - 886 689 644 612

Dictionary loading:

<?php foreach(file('websters-dictionary') as $line) {
    $word = strtolower(trim($line));
    if (strlen($word) < 3) continue;
    $c[$word] = 1;
}

Actual code (just concat both) :

list($d,$e)=explode(' ',strtolower(trim(`cat`)));$f=range(@a,@z);function w($a,&$g){global$c;if(isset($c[$a]))$g[]=$a;}$h[$d]=$b=@levenshtein;$i=new SplPriorityQueue;$i->insert($d,0);$j[$d]=0;$k[$d]=$b($d,$e);while($h){if(isset($c[$l=$i->extract()])){unset($h[$l],$c[$l]);if($l==$e){for(;$m=@$n[$o[]=$l];$l=$m);die(implode("\n",array_reverse($o)));}for($p=strlen($l),$g=array();$p--;){w(substr_replace($q=$l,"",$p,1),$g);foreach($f as$r){$q[$p]=$r;w($q,$g);w($r.$l,$g);w($l.$r,$g);}}foreach($g as$m){$s=$j[$l]+1;if(!isset($h[$m])||$s<$j[$m]){$n[$m]=$l;$i->insert($m,-(($k[$m]=$b($m,$e))+$j[$m]=$s));}$h[$m]=1;}}}

usage:

php puzzle.php <<< 'Zink Silicon'
# or
echo 'Zink Silicon'|php puzzle.php

Result:

zink
pink
pank
pani
panic
pinic
sinic
sinico
silico
silicon
(0.23s)

This should run in less than 0.5 second for 'Zink Silicon', and less than 1 second for most cases (sometimes longer when no solution exists, but it sill returns).

This uses the A* algorithm with levenshtein distance to estimate a lower bounds of the distances.

Some intersting tests:

  • vas arm -> vas bas bar barm arm (with a word longer than both start and end)
  • oxy pom -> oxy poxy poy pom
  • regatta gyrally -> (none, but the script correctly terminates)
  • aal presolution -> +8 chars
  • lenticulated aal -> -9 chars
  • acarology lowness -> 46 hops
  • caniniform lowness -> 51 hops
  • cauliform lowness -> 52 hops
  • overfoul lowness -> 54 hops
  • dance facia -> some words in the path have 4 more chars than both start/end

Arnaud Le Blanc

Posted 2011-02-08T08:43:33.007

Reputation: 2 286

Try Zink Silicon – Martin York – 2011-02-08T10:46:32.370

This should work, now :-) – Arnaud Le Blanc – 2011-02-08T13:40:49.247

I will find a bigger machine: PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 71 bytes) – Martin York – 2011-02-08T16:48:58.310

You just hit the 128M memory_limit setting ;-) Try with php -dmemory_limit=256M. – Arnaud Le Blanc – 2011-02-08T16:55:55.490

had->hand is not a valid move, you can only add a letter to the beginning or end. Same for vest->verst :-) – Arnaud Le Blanc – 2011-02-11T08:52:41.613

@user300, imm, that is a strange rule, but fixed it anyway. became same counts now :P – YOU – 2011-02-11T09:21:11.540

By the way, You may try to ask moderators to get your post back to non-CW (because of too many edits) by flagging the post->moderators attention->others – YOU – 2011-02-11T17:29:16.510

Conversion to CW is a one-way street. – Rebecca Chernoff – 2011-02-12T15:05:00.970

3

Python

Since I couldn't golf dijkstra codes to compress to few hundreds bytes, here is ungolfed version of mine.

import sys, heapq, time

# dijkstra algorithm from 
# http://code.activestate.com/recipes/119466-dijkstras-algorithm-for-shortest-paths/
def dijkstra(G, start, end):
   def flatten(L):
      while len(L) > 0:
         yield L[0]
         L = L[1]

   q = [(0, start, ())]
   visited = set()
   while True:
      (cost, v1, path) = heapq.heappop(q)
      if v1 not in visited:
         visited.add(v1)
         if v1 == end:
            return list(flatten(path))[::-1] + [v1]
         path = (v1, path)
         for (v2, cost2) in G[v1].iteritems():
            if v2 not in visited:
               heapq.heappush(q, (cost + cost2, v2, path))

nodes = tuple(sys.argv[1:])

print "Generating connections,",
current_time = time.time()

words = set(x for x in open("websters-dictionary", "rb").read().lower().split() if 3 <= len(x) <= max(5, *[len(l)+1 for l in nodes]))

print len(words), "nodes found"

def error():
    sys.exit("Unreachable Route between '%s' and '%s'" % nodes)

if not all(node in words for node in nodes):
    error()

# following codes are modified version of
# http://norvig.com/spell-correct.html
alphabet = 'abcdefghijklmnopqrstuvwxyz'

def edits(word):
   splits = [(word[:i], word[i:]) for i in range(len(word) + 1)]
   deletes = [a + b[1:] for a, b in splits if b]
   replaces = [a + c + b[1:] for a, b in splits for c in alphabet if b]
   prepends = [c+word for c in alphabet]
   appends = [word+c for c in alphabet]
   return words & set(deletes + replaces + prepends + appends)

# Generate connections between nodes to pass to dijkstra algorithm
G = dict((x, dict((y, 1) for y in edits(x))) for x in words)

print "All connections generated, %0.2fs taken" % (time.time() - current_time)
current_time = time.time()

try:
    route = dijkstra(G, *nodes)
    print '\n'.join(route)
    print "%d hops, %0.2fs taken to search shortest path between '%s' & '%s'" % (len(route), time.time() - current_time, nodes[0], nodes[1])
except IndexError:
    error()

Tests

$ python codegolf-693.py post shot
Generating connections, 15930 nodes found
All connections generated, 2.09s taken
post
host
hot
shot
4 hops, 0.04s taken to search shortest path between 'post' & 'shot'

$ python codegolf-693.py zink silicon
Generating connections, 86565 nodes found
All connections generated, 13.91s taken
zink
pink
pank
pani
panic
pinic
sinic
sinico
silico
silicon
10 hops, 0.75s taken to search shortest path between 'zink' & 'silicon'

Added user300's Tests

$ python codegolf-693.py vas arm
Generating connections, 15930 nodes found
All connections generated, 2.06s taken
vas
bas
bam
aam
arm
5 hops, 0.07s taken to search shortest path between 'vas' & 'arm'

$ python codegolf-693.py oxy pom
Generating connections, 15930 nodes found
All connections generated, 2.05s taken
oxy
poxy
pox
pom
4 hops, 0.01s taken to search shortest path between 'oxy' & 'pom'

$ python codegolf-693.py regatta gyrally
Generating connections, 86565 nodes found
All connections generated, 13.95s taken
Unreachable Route between 'regatta' and 'gyrally'

Some more

$ python codegolf-693.py gap shrend
Generating connections, 56783 nodes found
All connections generated, 8.16s taken
gap
rap
crap
craw
crew
screw
shrew
shrewd
shrend
9 hops, 0.67s taken to search shortest path between 'gap' & 'shrend'

$ python codegolf-693.py guester overturn
Generating connections, 118828 nodes found
All connections generated, 19.63s taken
guester
guesten
gesten
geste
gest
gast
east
ease
erse
verse
verset
overset
oversee
overseed
oversend
oversand
overhand
overhard
overcard
overcare
overtare
overture
overturn
23 hops, 0.82s taken to search shortest path between 'guester' & 'overturn'

YOU

Posted 2011-02-08T08:43:33.007

Reputation: 4 321

3 <= len(x) <= max(map(len, [nodea, nodeb])) is it guaranteed that the path will never go through a word longer than both start and end words ? – Arnaud Le Blanc – 2011-02-10T19:10:36.187

Try with oxy pom; shortest path is oxy->poxy->poy->pom. Also is seems that you allow permutations and insertions at any place, which are not allowed :-) – Arnaud Le Blanc – 2011-02-10T19:46:21.220

@user300, fixed permutations and insertions parts, I copy-pasted too much, thanks ;-) and I am setting initial limit to 5 chars and allowing +1 more chars start and end words, let me know if that still be issue. thanks. – YOU – 2011-02-11T05:39:35.437