RosettaCodeData/Task/Balanced-ternary/Groovy/balanced-ternary-1.groovy
2014-01-17 05:34:36 +00:00

160 lines
5.3 KiB
Groovy

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) //-3
case [[T.m, T.m, T.z]]: return carrySum(T.m, T.p) //-2
case [[T.m, T.z, T.z], [T.m, T.m, T.p]]: return carrySum(T.z, T.m) //-1
case [[T.z, T.z, T.z], [T.m, T.z, T.p]]: return carrySum(T.z, T.z) //+0
case [[T.z, T.z, T.p], [T.m, T.p, T.p]]: return carrySum(T.z, T.p) //+1
case [[T.z, T.p, T.p]]: return carrySum(T.p, T.m) //+2
case [[T.p, T.p, T.p]]: default: return carrySum(T.p, T.z) //+3
}
}
BalancedTernaryInteger plus(BalancedTernaryInteger that) {
assert that != null
if (this == ZERO) return that
if (that == ZERO) return this
def prep = prepValueLen.curry([value.size(), that.value.size()].max())
List values = [prep(value), prep(that.value)].transpose()
new BalancedTernaryInteger(values[-1..(-values.size())].inject(INITIAL_SUM_PARTS, partSum).sum)
}
BalancedTernaryInteger negative() {
!this ? this : new BalancedTernaryInteger(negate(value))
}
BalancedTernaryInteger minus(BalancedTernaryInteger that) {
assert that != null
this + -that
}
private static final INITIAL_PRODUCT_PARTS = [sum:ZERO, pad:'']
private static final sigTritCount = { it.value.replaceAll(T.z.symbol,'').size() }
private BalancedTernaryInteger paddedValue(String pad) {
new BalancedTernaryInteger(value + pad)
}
private BalancedTernaryInteger partialProduct(T multiplier, String pad){
switch (multiplier) {
case T.z: return ZERO
case T.m: return -paddedValue(pad)
case T.p: default: return paddedValue(pad)
}
}
BalancedTernaryInteger multiply(BalancedTernaryInteger that) {
assert that != null
if (that == ZERO) return ZERO
if (that == PLUS) return this
if (that == MINUS) return -this
if (this.value.size() == 1 || sigTritCount(this) < sigTritCount(that)) {
return that.multiply(this)
}
that.value.collect{ T.get(it) }[-1..(-value.size())].inject(INITIAL_PRODUCT_PARTS) { parts, multiplier ->
[sum: parts.sum + partialProduct(multiplier, parts.pad), pad: parts.pad + T.z]
}.sum
}
BigInteger asBigInteger() {
value.collect{ T.get(it) }.inject(0) { i, trit -> i * 3 + trit.value }
}
def asType(Class c) {
switch (c) {
case Integer: return asBigInteger() as Integer
case Long: return asBigInteger() as Long
case [BigInteger, Number]: return asBigInteger()
case Boolean: return this != ZERO
case String: return toString()
default: return super.asType(c)
}
}
boolean equals(Object that) {
switch (that) {
case BalancedTernaryInteger: return this.value == that?.value
default: return super.equals(that)
}
}
int hashCode() { this.value.hashCode() }
String toString() { value }
}