enum T {
    m('-', -1), z('0', 0), p('+', 1)

    final String symbol
    final int value

    private T(String symbol, int value) {
        this.symbol = symbol
        this.value = value
    }

    static T get(Object key) {
        switch (key) {
            case [m.value, m.symbol]: return m
            case [z.value, z.symbol]: return z
            case [p.value, p.symbol]: return p
            default:                   return null
        }
    }

    T negative() {
        T.get(-this.value)
    }

    String toString() { this.symbol }
}


class BalancedTernaryInteger {

    static final MINUS = new BalancedTernaryInteger(T.m)
    static final ZERO  = new BalancedTernaryInteger(T.z)
    static final PLUS  = new BalancedTernaryInteger(T.p)
    private static final LEADING_ZEROES = /^0+/

    final String value

    BalancedTernaryInteger(String bt) {
        assert bt && bt.toSet().every { T.get(it) }
        value = bt ==~ LEADING_ZEROES ? T.z: bt.replaceAll(LEADING_ZEROES, '');
    }

    BalancedTernaryInteger(BigInteger i) {
        this(i == 0 ? T.z.symbol: valueFromInt(i));
    }

    BalancedTernaryInteger(T...tArray) {
        this(tArray.sum{ it.symbol });
    }

    BalancedTernaryInteger(List<T> tList) {
        this(tList.sum{ it.symbol });
    }

    private static String valueFromInt(BigInteger i) {
        assert i != null
        if (i < 0) return negate(valueFromInt(-i))
        if (i == 0) return ''
        int bRem = (((i % 3) - 2) ?: -3) + 2
        valueFromInt((i - bRem).intdiv(3)) + T.get(bRem)
    }

    private static String negate(String bt) {
        bt.collect{ T.get(it) }.inject('') { str, t ->
            str + (-t)
        }
    }

    private static final Map INITIAL_SUM_PARTS = [carry:T.z, sum:[]]
    private static final prepValueLen = { int len, String s ->
        s.padLeft(len + 1, T.z.symbol).collect{ T.get(it) }
    }
    private static final partCarrySum = { partialSum, carry, trit ->
        [carry: carry, sum: [trit] + partialSum]
    }
    private static final partSum = { parts, trits ->
        def carrySum = partCarrySum.curry(parts.sum)
        switch ((trits + parts.carry).sort()) {
            case [[T.m, T.m, T.m]]:                  return carrySum(T.m, T.z)