Task: Word ladder


C++: #include <algorithm>
#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include <vector>

using word_map = std::map<size_t, std::vector<std::string>>;


bool one_away(const std::string& s1, const std::string& s2) {
    if (s1.size() != s2.size())
        return false;
    bool result = false;
    for (size_t i = 0, n = s1.size(); i != n; ++i) {
        if (s1[i] != s2[i]) {
            if (result)
                return false;
            result = true;
        }
    }
    return result;
}


template <typename iterator_type, typename separator_type>
std::string join(iterator_type begin, iterator_type end,
                 separator_type separator) {
    std::string result;
    if (begin != end) {
        result += *begin++;
        for (; begin != end; ++begin) {
            result += separator;
            result += *begin;
        }
    }
    return result;
}




bool word_ladder(const word_map& words, const std::string& from,
                 const std::string& to) {
    auto w = words.find(from.size());
    if (w != words.end()) {
        auto poss = w->second;
        std::vector<std::vector<std::string>> queue{{from}};
        while (!queue.empty()) {
            auto curr = queue.front();
            queue.erase(queue.begin());
            for (auto i = poss.begin(); i != poss.end();) {
                if (!one_away(*i, curr.back())) {
                    ++i;
                    continue;
                }
                if (to == *i) {
                    curr.push_back(to);
                    std::cout << join(curr.begin(), curr.end(), " -> ") << '\n';
                    return true;
                }
                std::vector<std::string> temp(curr);
                temp.push_back(*i);
                queue.push_back(std::move(temp));
                i = poss.erase(i);
            }
        }
    }
    std::cout << from << " into " << to << " cannot be done.\n";
    return false;
}

int main() {
    word_map words;
    std::ifstream in("unixdict.txt");
    if (!in) {
        std::cerr << "Cannot open file unixdict.txt.\n";
        return EXIT_FAILURE;
    }
    std::string word;
    while (getline(in, word))
        words[word.size()].push_back(word);
    word_ladder(words, "boy", "man");
    word_ladder(words, "girl", "lady");
    word_ladder(words, "john", "jane");
    word_ladder(words, "child", "adult");
    word_ladder(words, "cat", "dog");
    word_ladder(words, "lead", "gold");
    word_ladder(words, "white", "black");
    word_ladder(words, "bubble", "tickle");
    return EXIT_SUCCESS;
}



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])
    }
}