Solving the “Catching Car Mileage Numbers” Challenge Using Python

  • Home /
  • Blog Posts /
  • Solving the “Catching Car Mileage Numbers” Challenge using Python

The challenge

"7777…8?!??!", exclaimed Bob, "I missed it again! Argh!" Every time there's an interesting number coming up, he notices and then promptly forgets. Who doesn't like catching those one-off interesting mileage numbers?

Let’s make it so Bob never misses another interesting number. We’ve hacked into his car’s computer, and we have a box hooked up that reads mileage numbers. We’ve got a box glued to his dash that lights up yellow or green depending on whether it receives a 1 or a 2 (respectively).

It’s up to you, intrepid warrior, to glue the parts together. Write the function that parses the mileage number input, and returns a 2 if the number is “interesting” (see below), a 1 if an interesting number occurs within the next two miles, or a `` if the number is not interesting.

Note: In Haskell, we use NoAlmost and Yes instead of ``, 1 and 2.

“Interesting” Numbers

Interesting numbers are 3-or-more digit numbers that meet one or more of the following criteria:

  • Any digit followed by all zeros: 10090000
  • Every digit is the same number: 1111
  • The digits are sequential, incementing1234
  • The digits are sequential, decrementing4321
  • The digits are a palindrome: 1221 or 73837
  • The digits match one of the values in the awesome_phrases array

 For incrementing sequences,  should come after 9, and not before 1, as in 7890.
 For decrementing sequences,  should come after 1, and not before 9, as in 3210.

So, you should expect these inputs and outputs:

# "boring" numbers
is_interesting(3, [1337, 256])    # 0
is_interesting(3236, [1337, 256]) # 0

# progress as we near an "interesting" number
is_interesting(11207, []) # 0
is_interesting(11208, []) # 0
is_interesting(11209, []) # 1
is_interesting(11210, []) # 1
is_interesting(11211, []) # 2

# nearing a provided "awesome phrase"
is_interesting(1335, [1337, 256]) # 1
is_interesting(1336, [1337, 256]) # 1
is_interesting(1337, [1337, 256]) # 2

Error Checking

  • A number is only interesting if it is greater than 99!
  • Input will always be an integer greater than ``, and less than 1,000,000,000.
  • The awesomePhrases array will always be provided, and will always be an array, but may be empty. (Not everyone thinks numbers spell funny words…)
  • You should only ever output ``, 1, or 2.

Test cases

test.describe("Basic inputs")
test.it("Should handle {0}".format(format_msg(0, "boring numbers")))
test.assert_equals(is_interesting(1, []), 0, result_msg(1, 0))
test.assert_equals(is_interesting(30, []), 0, result_msg(30, 0))
test.assert_equals(is_interesting(88, []), 0, result_msg(88, 0))
test.assert_equals(is_interesting(97, []), 0, result_msg(97, 0))
test.assert_equals(is_interesting(7382, []), 0, result_msg(7382, 0))
test.assert_equals(is_interesting(99919911, []), 0, result_msg(99919911, 0))

test.it("Should handle {0}".format(format_msg(0, "ordered yet still boring numbers")))
test.assert_equals(is_interesting(7540, []), 0, result_msg(7540, 0))
test.assert_equals(is_interesting(1590, []), 0, result_msg(1590, 0))

Some solutions in Python code

Option 1 (using helper functions):

def is_incrementing(number): return str(number) in '1234567890'
def is_decrementing(number): return str(number) in '9876543210'
def is_palindrome(number):   return str(number) == str(number)[::-1]
def is_round(number):        return set(str(number)[1:]) == set('0')

def is_interesting(number, awesome_phrases):
    tests = (is_round, is_incrementing, is_decrementing,
             is_palindrome, awesome_phrases.__contains__)
       
    for num, color in zip(range(number, number+3), (2, 1, 1)):
        if num >= 100 and any(test(num) for test in tests):
            return color
    return 0

Option 2 (all inline):

def is_good(n, awesome):
    return n in awesome or str(n) in "1234567890 9876543210" or str(n) == str(n)[::-1] or int(str(n)[1:]) == 0

def is_interesting(n, awesome):
    if n > 99 and is_good(n, awesome):
        return 2
    if n > 97 and (is_good(n + 1, awesome) or is_good(n + 2, awesome)):
        return 1
    return 0

Option 3 (using any):

def is_interesting(number, awesome_phrases):
    for i in [number, number+1, number+2]:
        if i<100 :
            continue
        j=str(i)
        if any([
            i in awesome_phrases,
            all([j[x]=='0' for x in range(1,len(j))]),
            all([j[x]==j[0] for x in range(1,len(j))]),
            j == j[::-1],
            j in '1234567890',
            j in '9876543210'
                ]):
            return 2-bool(number-i)
    return 0

Option 4 (using zip):

def is_interesting(number, awesome_phrases):
    for r, num in zip((2, 1, 1), range(number, number + 3)):
        num_str = str(num)
        if num in awesome_phrases or num > 99 and (int(num_str[1:]) == 0 or num_str[::-1] == num_str or num_str in '1234567890' or num_str in '9876543210'):
            return r
    return 0