Task: Casting out nines




Go: package main

import (
    "fmt"
    "log"
    "strconv"
)







func co9Peterson(base int) (cob func(string) (byte, error), err error) {
    if base < 2 || base > 36 {
        return nil, fmt.Errorf("co9Peterson: %d invalid base", base)
    }
    
    
    
    
    
    addDigits := func(a, b byte) (string, error) {
        ai, err := strconv.ParseInt(string(a), base, 64)
        if err != nil {
            return "", err
        }
        bi, err := strconv.ParseInt(string(b), base, 64)
        if err != nil {
            return "", err
        }
        return strconv.FormatInt(ai+bi, base), nil
    }
    
    s9 := strconv.FormatInt(int64(base-1), base)
    b9 := s9[0]
    
    
    cob = func(n string) (r byte, err error) {
        r = '0'
        for i := 0; i < len(n); i++ { 
            d := n[i]
            switch {
            case d == b9: 
                continue
            
            case r == '0':
                r = d
                continue
            }
            
            s, err := addDigits(r, d)
            if err != nil {
                return 0, err
            }
            switch {
            case s == s9: 
                r = '0'
                continue
            
            case len(s) == 1:
                r = s[0]
                continue
            }
            
            
            r, err = cob(s)
            if err != nil {
                return 0, err
            }
        }
        return
    }
    return
}






func subset(base int, begin, end string) (s []string, err error) {
    
    begin64, err := strconv.ParseInt(begin, base, 64)
    if err != nil {
        return nil, fmt.Errorf("subset begin: %v", err)
    }
    end64, err := strconv.ParseInt(end, base, 64)
    if err != nil {
        return nil, fmt.Errorf("subset end: %v", err)
    }
    
    cob, err := co9Peterson(base)
    if err != nil {
        return
    }
    for k := begin64; k <= end64; k++ {
        ks := strconv.FormatInt(k, base)
        rk, err := cob(ks)
        if err != nil { 
            panic(err) 
        }
        rk2, err := cob(strconv.FormatInt(k*k, base))
        if err != nil { 
            panic(err) 
        }
        
        if rk == rk2 {
            s = append(s, ks)
        }
    }
    return
}

var testCases = []struct {
    base       int
    begin, end string
    kaprekar   []string
}{
    {10, "1", "100", []string{"1", "9", "45", "55", "99"}},
    {17, "10", "gg", []string{"3d", "d4", "gg"}},
}
    
func main() {
    for _, tc := range testCases {
        fmt.Printf("\nTest case base = %d, begin = %s, end = %s:\n",
            tc.base, tc.begin, tc.end)
        s, err := subset(tc.base, tc.begin, tc.end)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println("Subset:  ", s)
        fmt.Println("Kaprekar:", tc.kaprekar)
        sx := 0
        for _, k := range tc.kaprekar {
            for {
                if sx == len(s) {
                    fmt.Printf("Fail:", k, "not in subset")
                    return
                }
                if s[sx] == k {
                    sx++
                    break
                }
                sx++
            }
        }
        fmt.Println("Valid subset.")
    }
}