The dec­i­mal numeral system is com­posed of ten digits, which we rep­re­sent as “0123456789” (the digits in a system are writ­ten from lowest to high­est). Imag­ine you have dis­cov­ered an alien numeral system com­posed of some number of digits, which may or may not be the same as those used in dec­i­mal. For exam­ple, if the alien numeral system were rep­re­sented as “oF8”, then the num­bers one through ten would be (F, 8, Fo, FF, F8, 8o, 8F, 88, Foo, FoF). We would like to be able to work with num­bers in arbi­trary alien sys­tems. More gen­er­ally, we want to be able to con­vert an arbi­trary number that’s writ­ten in one alien system into a second alien system.

The above was exactly one of the prac­tice prob­lems of the google code­jam (I still don’t know if I could join the event since I’ll prob­a­bly be very busy with uni­ver­sity exams in the day of the qual­i­fi­ca­tion round) and more gen­er­ally the prob­lem is the con­ver­sion of a number (that isn’t nec­es­sar­ily com­posed by the usual digits) from any base to any base. I just fig­ured a solu­tion out and passed both the the small input test and the large one. My solu­tion is simple: con­vert the source base number in base 10 and then con­vert the pro­duced base 10 number in another base. There are known algo­rithms for doing this (just think that 1986 for exam­ple is noth­ing but 1 * 10^3 + 9 * 10^2 + 8 * 10^1 + 6 * 10^0) and I fin­ished imple­ment my own solu­tion in python.

The biggest issue here is that the source base can have sym­bols instead of digit and I solved this issue by map­ping the sym­bols to an array and using the index value of the sym­bols as digit value. Here it is my solu­tion:

#!/usr/bin/env python
import sys, array

def main(argv=None):
    if not argv:
        argv = sys.argv

    try:
        f = open(argv[1])
    except IOError:
        print "File doesn't exist"
        return 0

    try:
        i = 0
        for line in f:
            if i == 0:
                # first line
                line_num = int(line)
            else:
                number, input_b, output_b = line.strip('\n').split(' ')
                print 'Case #%d: %s' % (i, convert(number, input_b, output_b))

            i += 1
    finally:
        f.close()

    return 1

def convert(number, input_b, output_b):
    """
    Convert a number from any base to any base
    """

    return convert_from_10(convert_to_10(number, input_b), output_b)

def convert_to_10(input, base):
    """
    Input can be a number in any base, even in an 'alien' base.
    For example: 'Foo' could be a number in a numerical system
    whose digits are 'oF8'.

    Base is exactly the digits representation.
    If you want to convert that 'Foo' to base 10 then you must
    call ``convert_to_10('Foo', 'oF8')``.

    Remember that the number in ``base`` must be written in an
    ordered form

    Returns a string of the number in base 10
    """

    current_base = len(base)

    map_to_base = array.array('c')
    map(map_to_base.append, base)

    i = len(input) - 1
    base_10 = 0
    for digit in input:
        base_10 += map_to_base.index(digit) * current_base**i
        i -= 1

    return str(base_10)

def convert_from_10(input, base):
    """
    ``input`` is a number in base 10, while ``base`` is the digit
    representation of the new base (for example, for base 16 this
    could be '0123456789ABCDEF' or for an alien base 3 could be
    'oF8').

    Returns the number converted from base 10 to the specified
    base
    """

    map_to_base = array.array('c')
    map(map_to_base.append, base)

    current = int(input)
    base_n = ''
    while current != 0:
        base_n = map_to_base[current % len(base)] + base_n
        current = current / len(base)

    return base_n

if __name__ == '__main__':
    sys.exit(main())

And giving this input (the first line is number of the fol­low­ing lines):

4
9 0123456789 oF8
Foo oF8 0123456789
13 0123456789abcdef 01
CODE O!CDE? A?JM!.

I have the cor­rect output:

Case #1: Foo
Case #2: 9
Case #3: 10011
Case #4: JAM!

Of course this is one of the prac­tice prob­lems and you should try to solve it by your own (oth­er­wise it’s use­less to try to join the event).