Task: Teacup rim text




Go: package main

import (
    "bufio"
    "fmt"
    "log"
    "os"
    "sort"
    "strings"
)

func check(err error) {
    if err != nil {
        log.Fatal(err)
    }
}

func readWords(fileName string) []string {
    file, err := os.Open(fileName)
    check(err)
    defer file.Close()
    var words []string
    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        word := strings.ToLower(strings.TrimSpace(scanner.Text()))
        if len(word) >= 3 {
            words = append(words, word)
        }
    }
    check(scanner.Err())
    return words
}

func rotate(runes []rune) {
    first := runes[0]
    copy(runes, runes[1:])
    runes[len(runes)-1] = first
}

func main() {
    dicts := []string{"mit_10000.txt", "unixdict.txt"} 
    for _, dict := range dicts {
        fmt.Printf("Using %s:\n\n", dict)
        words := readWords(dict)
        n := len(words)
        used := make(map[string]bool)
    outer:
        for _, word := range words {
            runes := []rune(word)
            variants := []string{word}
            for i := 0; i < len(runes)-1; i++ {
                rotate(runes)
                word2 := string(runes)
                if word == word2 || used[word2] {
                    continue outer
                }
                ix := sort.SearchStrings(words, word2)
                if ix == n || words[ix] != word2 {
                    continue outer
                }
                variants = append(variants, word2)
            }
            for _, variant := range variants {
                used[variant] = true
            }
            fmt.Println(variants)
        }
        fmt.Println()
    }
}




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()