"Exercise: AllYourBaseInputBase"

allYourBaseInputBase: inputBase digits: digitsArray outputBase: outputBase
"Convert a sequence of digits in one base, representing a number, into a sequence of digits in another base, representing the same number.
    Try to implement the conversion yourself.
    Do not use something else to perform the conversion for you.
    In positional notation, a number in base b can be understood as a linear combination of powers of b."
"(self new allYourBaseInputBase: 2 digits: #(1) outputBase: 10) >>> #(1)"
"(self new allYourBaseInputBase: 10 digits: #(5) outputBase: 2) >>> #(1 0 1)"
| decimal division remainder resultDigits |
    inputBase >= 2 ifFalse: [ Error signal: 'input base must be >= 2' ].
    outputBase >= 2 ifFalse: [ Error signal: 'output base must be >= 2' ].

    decimal := 0.
    digitsArray reversed withIndexDo: [:digit :i |
        (digit >= 0 and: [ digit < inputBase ])
            ifFalse: [ Error signal: 'all digits must satisfy 0 <= d < input base' ].
        decimal := decimal + (digit * (inputBase raisedTo: i - 1)).
    ].

    resultDigits := OrderedCollection new.
    division := decimal.
    [
        remainder := division \\ outputBase.
        division := division // outputBase.
        resultDigits addFirst: remainder.
    ] doWhileFalse: [ division isZero ].

    ^ resultDigits asArray


"Tests"
testAllYourBase
| result |
  result := (task allYourBaseInputBase: 2 digits: #(1) outputBase: 10).
  self assert: result equals: #(1).

  result := (task allYourBaseInputBase: 2 digits: #(1 0 1) outputBase: 10).
  self assert: result equals: #(5).

  result := (task allYourBaseInputBase: 10 digits: #(5) outputBase: 2).
  self assert: result equals: #(1 0 1).

  result := (task allYourBaseInputBase: 2 digits: #(1 0 1 0 1 0) outputBase: 10).
  self assert: result equals: #(4 2).

  result := (task allYourBaseInputBase: 10 digits: #(4 2) outputBase: 2).
  self assert: result equals: #(1 0 1 0 1 0).

  result := (task allYourBaseInputBase: 3 digits: #(1 1 2 0) outputBase: 16).
  self assert: result equals: #(2 10).

  result := (task allYourBaseInputBase: 16 digits: #(2 10) outputBase: 3).
  self assert: result equals: #(1 1 2 0).

  result := (task allYourBaseInputBase: 97 digits: #(3 46 60) outputBase: 73).
  self assert: result equals: #(6 10 45).

  result := (task allYourBaseInputBase: 2 digits: #() outputBase: 10).
  self assert: result equals: #(0).

  result := (task allYourBaseInputBase: 10 digits: #(0) outputBase: 2).
  self assert: result equals: #(0).

  result := (task allYourBaseInputBase: 10 digits: #(0 0 0) outputBase: 2).
  self assert: result equals: #(0).

  result := (task allYourBaseInputBase: 7 digits: #(0 6 0) outputBase: 10).
  self assert: result equals: #(4 2).

  self
    should: [ task allYourBaseInputBase: 1 digits: #(0) outputBase: 10 ]
    raise: Error.

  self
    should: [ task allYourBaseInputBase: 0 digits: #() outputBase: 10 ]
    raise: Error.

  self
    should: [ task allYourBaseInputBase: -2 digits: #(1) outputBase: 10 ]
    raise: Error.

  self
    should: [ task allYourBaseInputBase: 2 digits: #(1 -1 1 0 1 0) outputBase: 10 ]
    raise: Error.

  self
    should: [ task allYourBaseInputBase: 2 digits: #(1 2 1 0 1 0) outputBase: 10 ]
    raise: Error.

  self
    should: [ task allYourBaseInputBase: 2 digits: #(1 0 1 0 1 0) outputBase: 1 ]
    raise: Error.

  self
    should: [ task allYourBaseInputBase: 10 digits: #(7) outputBase: 0 ]
    raise: Error.

  self
    should: [ task allYourBaseInputBase: 2 digits: #(1) outputBase: -7 ]
    raise: Error.

  self
    should: [ task allYourBaseInputBase: -2 digits: #(1) outputBase: -7 ]
    raise: Error