The core of the procedure to check if a number is happy requires to add on all its squared up digits. Thinking in a pythonic way, I have seen it as summing all the elements resulting from a custom iteration. I focused on the iterative part of this sub-problem, creating a generator that does the job:
def squared_ciphers(number): while number: number, cipher = divmod(number, 10) # 1 yield cipher ** 2 # 21. The handy built-in function divmod() returns the quotient and the remainder of the integer division by its passed parameters. I use it to get the rightmost digit in cipher removing it from number.
2. Each digit is squared and returned.
Now I am ready for the main part of the script. I am about to loop indefinitely until I see the number is happy or sad. Luckly we know that this loop is not infinite. See wikipedia for details.
def solution(line): candidate = int(line) explored = set() while candidate != 1: # 1 if candidate in explored: # 2 return 0 explored.add(candidate) candidate = sum(squared_ciphers(candidate)) # 3 return 11. If I get a 1, the originating number is happy. I can stop looping.
2. I store all the generate numbers in a set, so that I can easily check if I have already seen the current element. If so, I know I am entering a deadly loop, and so I can safely state the checked number is not happy.
3. I need to generate a new number from the current one. I call the generator to get all its squared ciphers, and I send the results to the sum() built-in function, so to get it.
Happy or not, this script nails it. You can get the full Python3 source from GitHub.