001    package aima.util;
002    
003    import java.util.List;
004    
005    /**
006     * @author Ciaran O'Reilly
007     * see: http://demonstrations.wolfram.com/MixedRadixNumberRepresentations/
008     * for useful example.
009     */
010    public class MixedRadixNumber extends Number {
011            //
012            private static final long serialVersionUID = 1L;
013            //
014            private long value = 0L;
015            private long maxValue = 0L;
016            private int[] radixs = null;
017            private int[] currentNumeralValue = null;
018            private boolean recalculate = true;
019            
020            public MixedRadixNumber(long value, int[] radixs) {
021                    this.value = value;
022                    this.radixs = new int[radixs.length];
023                    System.arraycopy(radixs, 0, this.radixs, 0, radixs.length);
024                    calculateMaxValue();
025            }
026            
027            public MixedRadixNumber(long value, List<Integer> radixs) {
028                    this.value = value;
029                    this.radixs = new int[radixs.size()];
030                    for (int i = 0; i < radixs.size(); i++) {
031                            this.radixs[i] = radixs.get(i);
032                    }
033                    calculateMaxValue();
034            }
035            
036            public long getMaxAllowedValue() {
037                    return maxValue;
038            }
039            
040            public boolean increment() {            
041                    if (value < maxValue) {
042                            value++;
043                            recalculate = true;
044                            return true;
045                    }
046                    
047                    return false;
048            }
049            
050            public boolean decrement() {
051                    if (value > 0) {
052                            value--;
053                            recalculate = true;
054                            return true;
055                    }
056                    return false;
057            }
058            
059            public int getCurrentNumeralValue(int atPosition) {
060                    if (atPosition >= 0 && atPosition < radixs.length) {
061                            if (recalculate) {
062                                    long quotient = value;
063                                    for (int i = 0; i < radixs.length; i++) {
064                                            if (0 != quotient) {                                            
065                                                    currentNumeralValue[i] = (int) quotient % radixs[i];
066                                                    quotient = quotient / radixs[i];
067                                            } else {
068                                                    currentNumeralValue[i] = 0;
069                                            }
070                                            
071                                    }
072                                    recalculate = false;
073                            }
074                            return currentNumeralValue[atPosition];                                            
075                    }
076                    throw new IllegalArgumentException("Argument atPosition must be >=0 and < "+radixs.length);
077            }
078            
079            //
080            // START-Number
081            public int intValue() {
082                    return (int) longValue();
083            }
084            
085            public long longValue() {
086                    return value;
087            }
088            
089            public float floatValue() {
090                    return longValue();
091            }
092            
093            public double doubleValue() {
094                    return longValue();
095            }
096            // END-Number
097            //
098            
099            public String toString() {
100                    StringBuilder sb = new StringBuilder();
101                    
102                    for (int i = 0; i < radixs.length; i++) {
103                            sb.append("[");
104                            sb.append(this.getCurrentNumeralValue(i));
105                            sb.append("]");
106                    }
107                    
108                    return sb.toString();
109            }
110            
111            //
112            // PRIVATE
113            //
114            private void calculateMaxValue() {
115                    if (0 == radixs.length) {
116                            throw new IllegalArgumentException("At least 1 radix must be defined.");
117                    }
118                    for (int i = 0; i < radixs.length; i++) {
119                            if (radixs[i] < 2) {
120                                    throw new IllegalArgumentException("Invalid radix, must be >= 2");
121                            }
122                    }
123                    
124                    // Calcualte the maxValue allowed
125                    maxValue = radixs[0];
126                    for (int i = 1; i < radixs.length; i++) {
127                            maxValue *= radixs[i];
128                    }
129                    maxValue -= 1;
130                    
131                    if (value > maxValue) {
132                            throw new IllegalArgumentException("The value ["+value+"] cannot be represented with the radixs provided, max value is " + maxValue);
133                    }
134                    
135                    currentNumeralValue = new int[radixs.length];
136            }
137    }