Happy Number Function Won't Return True - python

https://www.youtube.com/watch?v=kC6YObu61_w
After watching the linked video "7 and Happy Numbers", I decided to write up a bit of code to check whether or not the given number is a happy number.
c = []
num = int(input("What number would you like to check? "))
def happyNum(n):
newNum = 0
c = []
a = str(n)
for b in a:
c.append(int(b))
for d in c:
newNum = newNum + d**2
if newNum <= 1:
return True
elif newNum == 145:
return False
elif newNum == 113:
return False
elif newNum == 130:
return False
else:
happyNum(newNum)
if happyNum(num) == True:
print("You've found yourself a happy number!")
elif happyNum(num) == False:
print("Not a happy number I'm afraid!")
I tested it with 7, which I knew from the video is a lucky number, and found that nothing was printed. I did a few tests, and the function works fine. Once it reaches 1, it enters the if statement. The only problem is that it never returns True. Why is this happening, and how can I fix it? By the way, incase this might be significant, the function is recursive.

The video is incomplete in its description of happy numbers. Numbers that are happy will wind up at 1 but they don't say what happens with unhappy numbers. If they are unhappy, they will eventually cycle through a series of numbers. So to detect if they are unhappy, you have to keep track of the numbers produced and see if you get any repeats. (Presumably what you had c = [] for but didn't use in the end.) This means you need to pass a growing set along in your recursive calls. The numbers 145, 113 and 130 aren't generally useful and shouldn't be in your code.
Here's a rework that addresses the above issues:
def is_happy(number, seen=None):
if number == 1: # it's happy
return True
if seen is None:
seen = set()
if number in seen: # a cycle, it's unhappy
return False
seen.add(number)
# separate the digits into a list; several ways to do this
digits = [ord(digit) - ord('0') for digit in str(number)]
number = 0 # we can reuse number as we got what we needed
for digit in digits:
number += digit ** 2
return is_happy(number, seen) # this could have also been a loop
number = int(input("What number would you like to check? "))
if is_happy(number):
print("You've found yourself a happy number!")
else:
print("Not a happy number I'm afraid!")
But, if we find a happy number, then all the numbers we checked in the process of determing that it is happy, are themselves happy. Ditto for unhappy numbers. So if we add some caching, using dangerous default values that carry through to subsequent calls:
def is_happy(number, seen=None, happy=set([1]), unhappy=set()):
if seen is None:
seen = set()
if number in happy: # it's happy
happy.update(seen) # all seen numbers are happy too
return True
if number in unhappy or number in seen: # a cycle, it's unhappy
unhappy.update(seen) # all seen numbers are unhappy too
return False
seen.add(number)
# separate the digits into a list; several ways to do this
digits = [ord(digit) - ord('0') for digit in str(number)]
number = 0 # we can reuse number as we got what we needed
for digit in digits:
number += digit ** 2
return is_happy(number, seen) # this could have also been a loop
for number in range(1, 1000001):
if is_happy(number):
print(number, end=" ")
print()
We can determine the happiness of numbers up to a million in 1/6 of the time than if we hadn't kept track of previous happy and unhappy numbers!

Related

Number guessing game will not print the right phrase

I am extremely new to python and this is one of the first things I have tried. There are 3 criteria that I want this game to meet. First is to use the number 0-10 and guess the number 3 which it does correctly. Next is 0-25 when 11 is chosen. This also works correctly.
However this last part has been giving me trouble. When picking from 0-50, it should guess 1 which it does. It should also print the "I'm out of guesses" line when another input is placed as it cannot go higher than one now. What am I doing wrong here?
import random
import math
smaller = int(input("Enter the smaller number: "))
larger = int(input("Enter the larger number: "))
maxTry = math.log(larger - smaller)
count = 0
guess = int((smaller+larger)/2)
while count != maxTry:
count += 1
guess = int((smaller+larger)/2)
print("Your number is ", guess)
help = input("Enter =, <, or >: ")
if help == ">":
smaller = guess +1
elif help == "<":
larger = guess -1
elif help == "=":
print("Hooray, I've got it in", count, "tries")
break
elif count == maxTry:
print("I'm out of guesses, and you cheated")
break
Your maxTry is a log so it is not an integer, therefore it can never be equal to count.
You can either use an int for maxTry (cast it to int maxTry = int(math.log(larger - smaller))) or compute it with something different than log that will return an int.
Alternatively, your condition could be count > maxTry instead of equal. It would actually be a bit better conceptually.
Note: you should not use capital letters in variable names in python but all lowercase with _ max_try. It is only a convention though so won't affect your program directly. You can find more info on conventions in the PEP8 documentation

Running into issues with looping the calculation of # of digits in a number

My assignment requires me to take in an input, determine how many digits are in said input, then spit it back out. we are not allowed to use string conversion in order to determine the length of the input. I've managed to get that to work properly. My issue is that I'm supposed to have it repeat in a loop until a sentinel is reached. Here's my code so far.
print("This program determines the number of digits in a number.")
print("Enter a number, or 0 to quit.")
count = 0
num = 1
final = 0
num = int(input("Enter a number: "))
while num != 0:
num = num //10
count += 1
print("There are", count, "digits in", num)
I'm also seeming to have trouble with having my input integer print properly, but it might just be my ignorance there. I've cut out what my attempts at looping it were, as they all seemed to just break the code even more. Any help is welcome, even criticism! Thank you in advance!
Firstly, that is a strange way to get the digits in the number. There's no need to modify the actual number. Just cast the int back to a string and get the length (don't just keep the original string, it could have spaces or something in it which would throw off the count). That is the number of digits.
Secondly, you can do all the work in the loop. There's no need for setup variables, incrementing, a second loop, or anything like that. The key insight is the loop should run forever until you break out of it, so you can just use "while True:" for the loop, and break if the user inputs "0".
print("This program determines the number of digits in a number.")
print("Enter a number, or 0 to quit.")
def find_digits(num):
count = 0
while num != 0:
num = num //10
count += 1
return count
count += 1
# loop forever
while True:
# hang onto the original input
text_input = input("Enter a number: ")
# cast to int - this will throw an exception if the input isn't int-able
# you may want to catch that
num = int(text_input)
# the number of digits is the length of the int as a string
num_digits = find_digits(num)
if num == 0:
print("Goodbye.")
# "break" manually ends the loop
break
# if we got to this point, they didn't input 0 and the input was a number, so
# print our response
print(f"There are {num_digits} digits in {num}.")
The problem with printing the input integer correctly is, that you first save it in the num variable and then constantly change it in your while loop. So the original input is lost of course and in the end it always prints the 0, that ends up in num after the while loop finishes.
You can easily fix it, by saving the input value to another variable, that you don't touch in the loop.
print("This program determines the number of digits in a number.")
print("Enter a number, or 0 to quit.")
count = 0
num = int(input("Enter a number: "))
numcopy = num
while numcopy != 0:
numcopy = numcopy // 10
count += 1
print("There are", count, "digits in", num)
Counting is better done with Python builtin functions.
len(str(num))
will give you number of digits in your number.

Find the number of common items in two sequences for repeating items

I'm trying to make a pin number guessing game. A random 4 digit pin number is generated and you need to guess the pin number, if you get it wrong then it should tell you how many of the digits you guessed appear in the pin.
For example, if the pin number was 8823 and i guessed 1788, it should tell me that i got two digits correct because 8 is present twice in both. However, it only tells me that one digit is correct as the digits are the same number. If the numbers are different then there isn't a problem, for example if the pin was 1234 and i guessed 3456 then it would say i got two correct because 3 and 4 both appear once and are different numbers.
This is all of the code (i have made the area i believe to contain the problem bold):
import random
pin=random.randint(1000,9999)
pin2=str(pin)
pin3=list(pin2)
tries=0
x=1
guess="1"
while x==1:
pin3=list(pin2)
guess2=int(guess)
while guess2<1000 or guess2>9999:
guess2=int(input("Please guess a 4 digit number: "))
guess=str(guess2)
tries+=1
# BEGIN OF INDICTED CODE ============================
correct=0
for i, a in enumerate(pin3):
guess3=list(guess)
if a in guess:
del(pin3[i])
correct+=1
print("You got", correct, "correct")
# END OF INDICTED CODE ==============================
if guess==pin2:
x=0
guess="1"
print("You guessed correctly")
print("You had", tries, "attempts")
Thank you in advance.
You could try using the collections.Counter type, which is kind of like a set that allows duplicate items (also known as a bag or multiset).
This way, you can do a simple intersection between two counters to find the common elements. For example:
>>> from collections import Counter
>>> pin1 = Counter('8823')
>>> pin2 = Counter('1788')
>>> common = pin1 & pin2
>>> list(common.elements())
['8', '8']
>>>
Taking the length of this list gives you the number of common elements when duplicates are included.
this is my way of implementing your game
from random import randint
here we are generating the pin with the list comprehensions, we iterate 4 times and each time we are generating a random number
pin = [randint(0,9) for i in range(4)]
print(pin)
continue_game = True
correct = 0
tries = 0
guessed = []
in the below while loop, using "map" we are splitting the guess into a list with 4 elements, and then compare each element from the guess_pin list with each element from the pin list. If the element are matching we increasc correct with 1, if not we increase tries with 1.
while continue_game:
guess = str(input("Guess pin: "))
guess_pin = list(map(int, guess))
print(guess_pin)
for y in guess_pin:
for x in pin:
if y == x:
correct += 1
guessed.append(y)
else:
tries += 1
if correct == 4:
continue_game = False
else:
pass
print(f"You had guessed {correct} elements, and tried {tries} times")
In the end, we check if the correct equals 4, which means we have guessed all the numbers
Hope it helps you
Check this out:
def check_matching(
guess,
truth):
remaining = list(truth)
n = 0
for x in guess:
try:
remaining.remove(x)
except ValueError:
pass
else:
n += 1
return n
to be used like:
check_matching('8823', '1788')
# 2
check_matching('1234', '3456')
# 2
check_matching('8823', '5678')
# 1
This basically relies on the behavior of the .remove() method from built-in Python lists. Inputs can be list, tuple or str. Hence I'd recommend sticking to strings to avoid adding unnecessary operations.
Here
def get_num_of_common_digits(pin_number, guessed_pin_number):
pin_number_str = str(pin_number)
guessed_pin_number_str = str(guessed_pin_number)
result = 0
for x in pin_number_str:
idx = guessed_pin_number_str.find(x)
if idx != -1:
guessed_pin_number_str = guessed_pin_number_str[:idx] + guessed_pin_number_str[idx+1:]
result += 1
return result
print(get_num_of_common_digits(8823, 1788))
print(get_num_of_common_digits(1234, 3456))
print(get_num_of_common_digits(8823, 5678))
output
2
2
1

creating a python program which ask the user for a number - even odd

I am new to python and I am taking a summer online class to learn python.
Unfortunately, our professor doesn't really do much. We had an assignment that wanted us to make a program (python) which asks the user for a number and it determines whether that number is even or odd. The program needs to keep asking the user for the input until the user hit zero. Well, I actually turned in a code that doesn't work and I got a 100% on my assignment. Needless to say our professor is lazy and really doesn't help much. For my own knowledge I want to know the correct way to do this!!! Here is what I have/had. I am so embarrassed because I know if probably very easy!
counter = 1
num = 1
while num != 0:
counter = counter + 1
num=int(input("Enter number:"))
while num % 2 == 0:
print ("Even", num)
else:
print ("Odd", num)
There are a couple of problems with your code:
You never use counter, even though you defined it.
You have an unnecessary nested while loop. If the number the user inputs is even, then you're code will continue to run the while loop forever.
You are incorrectly using the else clause that is available with while loops. See this post for more details.
Here is the corrected code:
while True:
# Get a number from the user.
number = int(input('enter a number: '))
# If the number is zero, then break from the while loop
# so the program can end.
if number == 0:
break
# Test if the number given is even. If so, let the
# user know the number was even.
if number % 2 == 0:
print('The number', number, 'is even')
# Otherwise, we know the number is odd. Let the user know this.
else:
print('The number', number, 'is odd')
Note that I opted above to use an infinite loop, test if the user input is zero inside of the loop, and then break, rather than testing for this condition in the loop head. In my opinion this is cleaner, but both are functionally equivalent.
You already have the part that continues until the user quits with a 0 entry. Inside that loop, all you need is a simple if:
while num != 0:
num=int(input("Enter number:"))
if num % 2 == 0:
print ("Even", num)
else:
print ("Odd", num)
I left out the counter increment; I'm not sure why that's in the program, since you never use it.
Use input() and If its only number specific input you can use int(input()) or use an If/else statement to check
Your code wasn't indented and you need to use if condition with else and not while
counter = 1
num = 1
while num != 0:
counter = counter + 1
num = int(input("Enter number:"))
if num % 2 == 0:
print ("Even", num)
else:
print ("Odd", num)
Sample Run
Enter number:1
Odd 1
Enter number:2
Even 2
Enter number:3
Odd 3
Enter number:4
Even 4
Enter number:5
Odd 5
Enter number:6
Even 6
Enter number:0
Even 0

Generating a prime number bigger than a number found in a list

What isn't working below: I can't make the genPrim function work, as I get the "TypeError: 'int' object is not subscriptable".
A few observations:
1. What my program should do is first input a number into a list and then apply the other functions on that number.
2. The problem is that I can't seem to use that number from the list to do so. How can I do it? I was first thinking about asking for its position, but when going for the genPrim, both genPrim and Prim work because they are interdependent but they ask for the same thing.
def Adauga(L):
n = int(input("Give number:"))
L = L + [n]
return L
#Verify if number is prime
def Prim(L):
poz = int(input("Position of number: "))
n = L[poz]
if n<2 :
return False
NrDiv=0
for a in range (2,int(n/2+1)):
if n%a==0:
NrDiv=NrDiv+1
if (NrDiv==0):
return True
else:
return False
#Generate prime number
def genPrim(L):
poz = int(input("Give number: "))
a = L[poz]
b=a+1
while Prim(b)==False:
b=b+1
return b
#Display menu
def AfisMeniu():
print()
print("1.Add number")
print("2.Check if number is prime")
print("3.Generate prime number")
print("0.End of program")
i = int(input("Your option: "))
return i
def Main():
"""
Start the program
"""
L = []
Opt = AfisMeniu()
while (Opt != 0):
if Opt == 1:
L=Adauga(L)
elif Opt ==2:
L=Prim(L)
print (L)
elif Opt ==3:
L=genPrim(L)
print (L)
else:
print ("Wrong!")
Opt = AfisMeniu()
print()
print("End of program")
Main()
You are getting that error because genPrim returns an int, but Main() assigns that result to L, so L no longer contains a list of numbers, just that single int.
Similarly, Prim() returns a boolean (True or False) but Main() assigns that to L, too.
FWIW, the basic logic of your Prim() function is correct, but it's a very inefficient way to test if a number is prime. At the very least you should change it to return False as soon as it has found one divisor, i.e. when n%a==0.
I've managed to make the third option work, as in generating a prime number. However, what I would also like is to make the second option work as well, the prime verification.
My idea is modifying the code in the Main() function, by taking the len of the position, however I can't really make it work.
elif Opt ==2:
L=Prim(L)
poz1=int(len(L))
print (L[poz1])
Or perhaps, should I attempt a different method?

Categories