Task: Teacup rim text


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


std::set<std::string> load_dictionary(const std::string& filename) {
    std::ifstream in(filename);
    if (!in)
        throw std::runtime_error("Cannot open file " + filename);
    std::set<std::string> words;
    std::string word;
    while (getline(in, word))
        words.insert(word);
    return words;
}

void find_teacup_words(const std::set<std::string>& words) {
    std::vector<std::string> teacup_words;
    std::set<std::string> found;
    for (auto w = words.begin(); w != words.end(); ++w) {
        std::string word = *w;
        size_t len = word.size();
        if (len < 3 || found.find(word) != found.end())
            continue;
        teacup_words.clear();
        teacup_words.push_back(word);
        for (size_t i = 0; i + 1 < len; ++i) {
            std::rotate(word.begin(), word.begin() + 1, word.end());
            if (word == *w || words.find(word) == words.end())
                break;
            teacup_words.push_back(word);
        }
        if (teacup_words.size() == len) {
            found.insert(teacup_words.begin(), teacup_words.end());
            std::cout << teacup_words[0];
            for (size_t i = 1; i < len; ++i)
                std::cout << ' ' << teacup_words[i];
            std::cout << '\n';
        }
    }
}

int main(int argc, char** argv) {
    if (argc != 2) {
        std::cerr << "usage: " << argv[0] << " dictionary\n";
        return EXIT_FAILURE;
    }
    try {
        find_teacup_words(load_dictionary(argv[1]));
    } catch (const std::exception& ex) {
        std::cerr << ex.what() << '\n';
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}






Python: 

from itertools import chain, groupby
from os.path import expanduser
from functools import reduce



def main():
    
    print('\n'.join(
        concatMap(circularGroup)(
            anagrams(3)(
                
                lines(readFile('~/mitWords.txt'))
            )
        )
    ))



def anagrams(n):
    
    def go(ws):
        def f(xs):
            return [
                [snd(x) for x in xs]
            ] if n <= len(xs) >= len(xs[0][0]) else []
        return concatMap(f)(groupBy(fst)(sorted(
            [(''.join(sorted(w)), w) for w in ws],
            key=fst
        )))
    return go



def circularGroup(ws):
    
    lex = set(ws)
    iLast = len(ws) - 1
    
    
    (i, blnCircular) = until(
        lambda tpl: tpl[1] or (tpl[0] > iLast)
    )(
        lambda tpl: (1 + tpl[0], isCircular(lex)(ws[tpl[0]]))
    )(
        (0, False)
    )
    return [' -> '.join(allRotations(ws[i]))] if blnCircular else []



def isCircular(lexicon):
    
    def go(w):
        def f(tpl):
            (i, _, x) = tpl
            return (1 + i, x in lexicon, rotated(x))

        iLast = len(w) - 1
        return until(
            lambda tpl: iLast < tpl[0] or (not tpl[1])
        )(f)(
            (0, True, rotated(w))
        )[1]
    return go



def allRotations(w):
    
    return takeIterate(len(w) - 1)(
        rotated
    )(w)





def concatMap(f):
    
    def go(xs):
        return chain.from_iterable(map(f, xs))
    return go



def fst(tpl):
    
    return tpl[0]



def groupBy(f):
    
    def go(xs):
        return [
            list(x[1]) for x in groupby(xs, key=f)
        ]
    return go



def lines(s):
    
    return s.splitlines()



def mapAccumL(f):
    
    def go(a, x):
        tpl = f(a[0], x)
        return (tpl[0], a[1] + [tpl[1]])
    return lambda acc: lambda xs: (
        reduce(go, xs, (acc, []))
    )



def readFile(fp):
    
    with open(expanduser(fp), 'r', encoding='utf-8') as f:
        return f.read()



def rotated(s):
    
    return s[1:] + s[0]



def snd(tpl):
    
    return tpl[1]



def takeIterate(n):
    
    def go(f):
        def g(x):
            def h(a, i):
                v = f(a) if i else x
                return (v, v)
            return mapAccumL(h)(x)(
                range(0, 1 + n)
            )[1]
        return g
    return go



def until(p):
    
    def go(f):
        def g(x):
            v = x
            while not p(v):
                v = f(v)
            return v
        return g
    return go



if __name__ == '__main__':
    main()