"""
Birthday problem:
You have a baby. The doctor tells you your baby will live to be exactly 128 years old.
Because you are a kind parent, you intend to buy your child enough candals to last every
birthday of their lifetime. Because you are a thrifty parent, you intend to buy the
fewest number of candals possible to represent every birthday your child will have.
How many candals do you need to represent every birthday number between 1 and 128 in base
10? In base 9? 8? Which base system requires you to buy the fewest candals?
"""
DIGITS = "0123456789ABCDEFG"
def toString(num: int, base: int) -> str:
"""
Convert |num| to a string base |base|
"""
ret = ""
while num:
ret = DIGITS[num % base]+ ret
num = num // base
return ret
assert(toString(7, 2) == "111")
assert(toString(8, 2) == "1000")
assert(toString(7, 10) == "7")
def countMaxOfDigit(ageMax: int, base: int, digit: str) -> int:
"""
Given all the birthday cake needs from 0 to |ageMax|, find
the most candals of type |digit| you need at any given point
"""
return max([toString(age, base).count(digit) for age in range(ageMax)])
assert(countMaxOfDigit(150, 10, '0') == 2)
def countTotalCandals(ageMax: int, base: int) -> int:
"""
Count the total number of candals needed to represent all ages
from 0 to |ageMax| in base |base|
"""
return sum([countMaxOfDigit(ageMax, base, digit) for digit in DIGITS])
assert(countTotalCandals(128, 10) == 21)
from IPython.display import HTML, display
def renderBirthdayMatrix(maxAgeMax: int, maxBase: int):
rows = []
firstRow = ["<th></th>"]
for base in range(2, maxBase):
firstRow.append("<th>base %s</th>" % (base,))
rows.append(''.join(firstRow))
for ageMax in range(5, maxAgeMax, 5):
row = ["<th>age %s</th>" % (ageMax,)]
for base in range(2, maxBase):
row.append("<td>%d</td>" % (countTotalCandals(ageMax, base),))
rows.append(''.join(row))
rows = ["<tr>%s</tr>" % (row) for row in rows]
return HTML("<table>%s</table>" % (''.join(rows)))
display(renderBirthdayMatrix(128, 15))
base 2 | base 3 | base 4 | base 5 | base 6 | base 7 | base 8 | base 9 | base 10 | base 11 | base 12 | base 13 | base 14 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
age 5 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
age 10 | 6 | 6 | 5 | 6 | 7 | 8 | 9 | 9 | 9 | 9 | 9 | 9 | 9 |
age 15 | 6 | 7 | 6 | 7 | 8 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 14 |
age 20 | 8 | 7 | 8 | 8 | 8 | 9 | 10 | 10 | 11 | 12 | 13 | 14 | 15 |
age 25 | 8 | 7 | 9 | 9 | 9 | 10 | 10 | 11 | 12 | 13 | 13 | 14 | 15 |
age 30 | 8 | 9 | 9 | 10 | 10 | 10 | 11 | 11 | 12 | 13 | 14 | 15 | 15 |
age 35 | 10 | 9 | 9 | 11 | 10 | 11 | 11 | 12 | 13 | 13 | 14 | 15 | 16 |
age 40 | 10 | 9 | 9 | 11 | 12 | 11 | 12 | 12 | 13 | 14 | 15 | 15 | 16 |
age 45 | 10 | 10 | 10 | 11 | 13 | 12 | 12 | 13 | 14 | 14 | 15 | 16 | 16 |
age 50 | 10 | 10 | 10 | 11 | 13 | 14 | 13 | 13 | 14 | 15 | 15 | 16 | 17 |
age 55 | 10 | 10 | 10 | 11 | 13 | 14 | 14 | 14 | 14 | 15 | 16 | 16 | 17 |
age 60 | 10 | 10 | 10 | 11 | 13 | 15 | 14 | 14 | 15 | 15 | 16 | 17 | 17 |
age 65 | 12 | 10 | 12 | 12 | 13 | 15 | 16 | 15 | 15 | 16 | 16 | 17 | 18 |
age 70 | 12 | 10 | 12 | 12 | 13 | 15 | 16 | 15 | 16 | 16 | 17 | 17 | 18 |
age 75 | 12 | 10 | 12 | 12 | 13 | 15 | 17 | 16 | 16 | 17 | 17 | 18 | 18 |
age 80 | 12 | 10 | 12 | 12 | 13 | 15 | 17 | 16 | 17 | 17 | 18 | 18 | 19 |
age 85 | 12 | 12 | 12 | 12 | 13 | 15 | 17 | 18 | 17 | 18 | 18 | 19 | 19 |
age 90 | 12 | 12 | 13 | 12 | 14 | 15 | 17 | 18 | 18 | 18 | 18 | 19 | 19 |
age 95 | 12 | 12 | 13 | 13 | 14 | 15 | 17 | 19 | 18 | 18 | 19 | 19 | 20 |
age 100 | 12 | 12 | 13 | 13 | 14 | 15 | 17 | 19 | 19 | 19 | 19 | 20 | 20 |
age 105 | 12 | 12 | 13 | 13 | 14 | 15 | 17 | 19 | 20 | 19 | 20 | 20 | 20 |
age 110 | 12 | 12 | 13 | 13 | 14 | 15 | 17 | 19 | 20 | 20 | 20 | 20 | 21 |
age 115 | 12 | 12 | 13 | 13 | 14 | 16 | 17 | 19 | 21 | 20 | 20 | 21 | 21 |
age 120 | 12 | 12 | 13 | 13 | 14 | 16 | 17 | 19 | 21 | 20 | 21 | 21 | 21 |
age 125 | 12 | 13 | 13 | 14 | 14 | 16 | 17 | 19 | 21 | 22 | 21 | 21 | 22 |