Task: Word ladder




Go: package main

import (
    "bytes"
    "fmt"
    "io/ioutil"
    "log"
    "strings"
)

func contains(a []string, s string) bool {
    for _, e := range a {
        if e == s {
            return true
        }
    }
    return false
}

func oneAway(a, b string) bool {
    sum := 0
    for i := 0; i < len(a); i++ {
        if a[i] != b[i] {
            sum++
        }
    }
    return sum == 1
}

func wordLadder(words []string, a, b string) {
    l := len(a)
    var poss []string
    for _, word := range words {
        if len(word) == l {
            poss = append(poss, word)
        }
    }
    todo := [][]string{{a}}
    for len(todo) > 0 {
        curr := todo[0]
        todo = todo[1:]
        var next []string
        for _, word := range poss {
            if oneAway(word, curr[len(curr)-1]) {
                next = append(next, word)
            }
        }
        if contains(next, b) {
            curr = append(curr, b)
            fmt.Println(strings.Join(curr, " -> "))
            return
        }
        for i := len(poss) - 1; i >= 0; i-- {
            if contains(next, poss[i]) {
                copy(poss[i:], poss[i+1:])
                poss[len(poss)-1] = ""
                poss = poss[:len(poss)-1]
            }
        }
        for _, s := range next {
            temp := make([]string, len(curr))
            copy(temp, curr)
            temp = append(temp, s)
            todo = append(todo, temp)
        }
    }
    fmt.Println(a, "into", b, "cannot be done.")
}

func main() {
    b, err := ioutil.ReadFile("unixdict.txt")
    if err != nil {
        log.Fatal("Error reading file")
    }
    bwords := bytes.Fields(b)
    words := make([]string, len(bwords))
    for i, bword := range bwords {
        words[i] = string(bword)
    }
    pairs := [][]string{
        {"boy", "man"},
        {"girl", "lady"},
        {"john", "jane"},
        {"child", "adult"},
    }
    for _, pair := range pairs {
        wordLadder(words, pair[0], pair[1])
    }
}




Python: import os,sys,zlib,urllib.request

def h ( str,x=9 ):
    for c in str :
        x = ( x*33 + ord( c )) & 0xffffffffff
    return x  

def cache ( func,*param ):
    n = 'cache_%x.bin'%abs( h( repr( param )))
    try    : return eval( zlib.decompress( open( n,'rb' ).read()))
    except : pass
    s = func( *param )
    open( n,'wb' ).write( zlib.compress( bytes( repr( s ),'ascii' )))
    return s

dico_url  = 'https://raw.githubusercontent.com/quinnj/Rosetta-Julia/master/unixdict.txt'
read_url  = lambda url   : urllib.request.urlopen( url ).read()
load_dico = lambda url   : tuple( cache( read_url,url ).split( b'\n'))
isnext    = lambda w1,w2 : len( w1 ) == len( w2 ) and len( list( filter( lambda l : l[0]!=l[1] , zip( w1,w2 )))) == 1

def build_map ( words ):
    map = [(w.decode('ascii'),[]) for w in words]
    for i1,(w1,n1) in enumerate( map ):
        for i2,(w2,n2) in enumerate( map[i1+1:],i1+1 ):
            if isnext( w1,w2 ):
                n1.append( i2 )
                n2.append( i1 )
    return map

def find_path ( words,w1,w2 ):
    i = [w[0] for w in words].index( w1 )
    front,done,res  = [i],{i:-1},[]
    while front :
        i = front.pop(0)
        word,next = words[i]
        for n in next :
            if n in done : continue
            done[n] = i
            if words[n][0] == w2 :
                while n >= 0 :
                    res = [words[n][0]] + res
                    n = done[n]
                return ' '.join( res )
            front.append( n )
    return '%s can not be turned into %s'%( w1,w2 )

for w in ('boy man','girl lady','john jane','alien drool','child adult'):
    print( find_path( cache( build_map,load_dico( dico_url )),*w.split()))