Comparing lists in Python for mastermind - python

I’m trying to make a Mastermind game in python. The idea behind it is that the computer generates a 4 number code between 1 and 6. Then you have so many guesses to figure it out. If you get the right number in the right spot you get an x, if you get the right number in the wrong spot you get an o and if you get nothing right, you don’t receive anything. The code I have now mostly works but there’s one issue. Say the code is [4, 4, 4, 3] and the guess is [4, 3, 3, 2], the output will be [x, o, o, ,] (it should be [x, o, , ,], it reads the 3 twice)
import random
length_of_password = (range(4))
number_of_guesses = (range(8))
code = []
# Generates random code
for random_letter in length_of_password:
code += str((random.randint(1, 6)))
print(code) # Here just for testing
# Takes guesses and compares them to the code
for guesses in number_of_guesses:
indicator = ""
guess = list(input("Guess: "))
if guess == code:
print("Congratulations, you won!")
break
for letter in length_of_password:
if guess[letter] == code[letter]:
print("x")
elif guess[letter] in code:
print("o")
else:
pass
print(indicator)
Also I am trying to return the indicator sorted so all the x’s are first and o’s are second (that way they don’t know which number is in the right spot) bonus points if you can help with that.
Thank you!

code=['4','4','4','3']
for guess in range(8):
result=[]
guess=list(input("Enter guess\n"))
if guess==code:
print('success')
break
code_copy=code.copy()
for i in range(4):
if guess[i]==code[i]:
result.append('X')
elif guess[i] in code_copy:
result.append('O')
for j in range(4):
if code_copy[j]==guess[i]:
code_copy[j]='7'
break
else:
result.append('')
print(result)
Not the neatest solution, but what I tried was making a copy of the original 'code', and in the If clause managing the right number-wrong spot condition, change the first find of that number in the copy to a 7. I chose 7 since you mentioned the code has digits in the range 1-6.
Note that in the first if condition we must check against the original code, not the copy.

Related

Happy Numbers doesn't update variable

I've been coding for about 3 months. Could someone help me understand why my code isn't working? I could look up the answer, but I'd really like to figure out what is going wrong. It runs perfectly the first time through the code, but while it is While-Looping, x always stays as the number inserted into the function. Thanks for your help! The assignment and code is below (for an Udemy class).
Happy Numbers -
A happy number is defined by the following process. Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers, while those that do not end in 1 are unhappy numbers. Display an example of your output here. Find first 8 happy numbers.
def find_happy_number(x):
#we need a bunch of lists
digit_list = []
squared_list = []
result_list = []
happy_numbers = []
unhappy_numbers = []
while True:
#break our number into digits
x = str(x)
for digit in x:
digit_list.append(int(digit))
#square each digit and store in list
for digit in digit_list:
squared_digit = digit**2
squared_list.append(squared_digit)
#adds all numbers on that list
result = sum(squared_list)
print(result)
#check to see if it is a happy number
if result == 1:
print(f'{x} is a happy number!')
break
#check to see if it is an un-happy number
if result in result_list:
print(f'{x} is an UN-happy number!')
break
#if it isn't we continue the churning.
#adds result to result list to see if we are looping infinitally
x = result
result_list.append(result)
`
The PROBLEM is that you are not resetting digit_list and squared_list in every loop, so they just keep getting bigger and bigger. Move their initialization into the while loop, or use a list comprehension instead of a loop.
Consider this for your loop:
while True:
digit_list = [int(digit) for digit in str(x)]
squared_list = [digit**2 for digit in digit_list]
Now you don't need to initialize them. Or, for extra fun, combine it all into one:
while True:
result = sum(int(digit)**2 for digit in str(x))

how can I reduce my code? A lot of it is repetitive

The code creates a random addition problem and spits out "Congratulations" if correct and "sorry...." if the inputted value is wrong. The while loop repeats this process until the user inserts "N" for the question "continue (Y/N):, at the same time it keeps track of how many questions have been answered, and which ones are correct. The code works fine, my problem is it has repetitive code. I was wondering if there is a way to shrink it.
**I appreciate everyone one's help and advice. I"m a noob that's just learning python **
import random
correct=0
count=1
num1=random.randint(0,100)
num2=random.randint(0,100)
print(format(num1,'4d'))
print('+',num2)
answer=int(input('='))
sum=num1+num2
if answer==sum:
print('Congraulations!')
correct+=1
else:
print('Sorry the correct answer is',sum)
c=input('Continue (Y/N):')
while c == "Y":
count+=1
num1=random.randint(0,100)
num2=random.randint(0,100)
print(format(num1,'4d'))
print('+',num2)
answer=int(input('='))
sum=num1+num2
if answer==sum:
print('Congraulations!')
correct+=1
else:
print('Sorry the correct answer is',sum)
c=input('Continue (Y/N):')
else:
print('Your final score is',correct,'/',count)
A first start, would be eliminating the code before the while, by initializing the count variable (which keeps track of the turns), in zero, and allowing the while loop to run the first turn, we just need to have a variable like want_to_play and by default it's True, so the first time we'll be playing, and at the end of the game If I don't input Y or y it will asume I don't want to play any more and set the variable to false, that way I can have all the turns ran by the while loop.
and you'll be getting something like this.:
from random import sample
correct = 0
count = 0 # STartint in turn zero
want_to_play = True # Control Variable
while want_to_play:
count += 1
# First turn this is zero, and adds one.
[num1, num2] = sample(range(0, 101), 2)
# Just another way of getting two random numbers from 1 up to (including) 100.
# Printing could be done in one line.
print(format(num1, '5d') + '\n+' + format(num2, '4d'))
answer = int(input('= '))
# The comparison really doesn't really hurt if you do it this way.
if answer == num1 + num2:
print('Congraulations!')
correct += 1
else:
print('Sorry the correct answer is', sum)
# HERE you ask if you want to play again or not, using a one line if
# you decide.
want_to_play = (True if 'y' == input('Continue (Y/N).lower():')
else False)
else:
print('Your final score is',correct,'/',count)
By initializing the variable c as "Y", the condition is met and the loop can be executed:
import random
correct=0
count=1
c = "Y"
while c == "Y":
count+=1
num1=random.randint(0,100)
num2=random.randint(0,100)
print(format(num1,'4d'))
print('+',num2)
answer=int(input('='))
sum=num1+num2
if answer==sum:
print('Congraulations!')
correct+=1
else:
print('Sorry the correct answer is',sum)
c=input('Continue (Y/N):')
c = c.upper()
else:
print('Your final score is',correct,'/',count)
I also added the method upper() to the Y/N input so the user can also type it in lowercase
Try to move as much of the processing as possible into the loop. The first "paragraph" of your code was basically a duplicate of the main-loop. By creating the continuation variable c so that it drops straight into the loop, most of that first block could be removed.
import random
correct=0
count=0
c = 'Y'
while c == "Y":
count+=1
num1=random.randint(0,100)
num2=random.randint(0,100)
print(format(num1,'4d'))
print('+',num2)
answer=int(input('='))
sum=num1+num2
if answer==sum:
print('Congratulations!')
correct+=1
else:
print('Sorry the correct answer is',sum)
c=input('Continue (Y/N):')
else:
print('Your final score is',correct,'/',count)
The two formula printing statements can also be reduced to a single one:
print(format(num1,'4d'))
print('+',num2)
could be
print( format(num1,'4d') + '+', num2 )
The variable sum could be removed, but it does make the code self-documenting, which is a good thing.

Multiple Same Numbers Entered in Guessing Game; Loop Stops Working?

I've been making a 4 number guessing game to learn python that meets three criteria:
replayable
tells player how many tries it took to guess correct answer
tells player how many numbers are correct to steer player to right answer
I thought I met the criteria but there is this really weird bug that happens in the game. If you try to guess the number using trial and error; the game breaks and doesn't detect that your answer is right. If the answer is '[1, 2, 3, 4]' and you try to get the answer by doing '[1, 1, 1, 1]' then '[1, 2, 2, 2,]' and eventually get '[1, 2, 3, 4]'; the program will say that the 4 numbers match but it won't let you win the game and just asks you to play again. This bug has been really killing me and I hope the person reading understands what I'm trying to say.
Sorry about the big long block of code but, the problem could be anywhere here but I honestly cannot see it; I will annotate as best as I can to make it look less confusing. I just... why is this happening!?
def compareLists(a, b): # to compare the guessed numbers and random numbers
return list(set(a) & set(b))
rNums = random.sample(range(10), 4) # random list of numbers
def start():
count = 0 # count for number of tries
global rNums
gNums = [] # guessed numbers
print(rNums) # cheating to save time
flag = True # to stop the guessing loop
while flag:
print("Get ready to guess 4 numbers!")
for i in range(0, 4): # asks the player 4 times to input a number
x = int(input("Guess: "))
gNums.append(x) # puts numbers in guessed numbers
comparison = len(compareLists(rNums, gNums)) # storing the length of the list of similar numbers
isCorrect = gNums == rNums # to check if lists are the same
print("You guessed: ", gNums) # telling player what they have guessed
if isCorrect: # if the lists are the same
if count > 1:
print("You win!! It only took you %d tries!" %count) # telling the player how many tries it took
else: #congratulating the player on a flawless guess
print("I CAN'T BELIEVE WHAT I'M SEEING!!!")
print("YOU GOT IT IN ONE GO!!")
count += 1 # increment count
rNums = random.sample(range(10), 4) # generate new numbers
gNums.clear()
pAgain = input("Play again?")
if pAgain.lower() in ('y', 'yes'): # replaying the game
continue
elif pAgain.lower() in ('n', 'no'):
flag = False
else:
print("Incorrect syntax!")
else:
print("You guessed " + str(comparison) + " numbers right, keep guessing!") # tells the player how many numbers are similar so the player can get a more educated guess
gNums.clear() # empties guessed numbers
count += 1 # increment count
print("Number of tries so far: %d" %count) # showing player number of tries so far
Your comparison for checking if the two lists are the same isn't working:
isCorrect = gNums == rNums # to check if lists are the same
The above code is checking if the two lists are identical, but the elements have to be in the same order.
For your test, you can just check if the number that match (ignoring order) is equal to the length of the list of numbers:
isCorrect = comparison == len(gNums) # to check if lists are the same
For more information on comparing lists regardless of order, see this answer.
Also, you should increment your count before you do your comparison with 1, or else your program will say you only took one go when you actually took two.

Loop and validation in number guessing game

I have previously studied Visual Basic for Applications and am slowly getting up to speed with python this week. As I am a new programmer, please bear with me. I understand most of the concepts so far that I've encountered but currently am at a brick wall.
I've written a few functions to help me code a number guessing game. The user enters a 4 digit number. If it matches the programs generated one (I've coded this already) a Y is appended to the output list. If not, an N.
EG. I enter 4567, number is 4568. Output printed from the list is YYYN.
import random
def A():
digit = random.randint(0, 9)
return digit
def B():
numList = list()
for counter in range(0,4):
numList.append(A())
return numList
def X():
output = []
number = input("Please enter the first 4 digit number: ")
number2= B()
for i in range(0, len(number)):
if number[i] == number2[i]:
results.append("Y")
else:
results.append("N")
print(output)
X()
I've coded all this however theres a few things it lacks:
A loop. I don't know how I can loop it so I can get it to ask again. I only want the person to be able to guess 5 times. I'm imagining some sort of for loop with a counter like "From counter 1-5, when I reach 5 I end" but uncertain how to program this.
I've coded a standalone validation code snippet but don't know how I could integrate this in the loop, so for instance if someone entered 444a it should say that this is not a valid entry and let them try again. I made an attempt at this below.
while myNumber.isnumeric() == True and len(myNumber) == 4:
for i in range(0, 4)):
if myNumber[i] == progsNumber[i]:
outputList.append("Y")
else:
outputList.append("N")
Made some good attempts at trying to work this out but struggling to patch it all together. Is anyone able to show me some direction into getting this all together to form a working program? I hope these core elements that I've coded might help you help me!
To answer both your questions:
Loops, luckily, are easy. To loop over some code five times you can set tries = 5, then do while tries > 0: and somewhere inside the loop do a tries -= 1.
If you want to get out of the loop ahead of time (when the user answered correctly), you can simply use the break keyword to "break" out of the loop. You could also, if you'd prefer, set tries = 0 so loop doesn't continue iterating.
You'd probably want to put your validation inside the loop in an if (with the same statements as the while loop you tried). Only check if the input is valid and otherwise continue to stop with the current iteration of your loop and continue on to the next one (restart the while).
So in code:
answer = [random.randint(0, 9) for i in range(4)]
tries = 5
while tries > 0:
number = input("Please enter the first 4 digit number: ")
if not number.isnumeric() or not len(number) == len(answer):
print('Invalid input!')
continue
out = ''
for i in range(len(answer)):
out += 'Y' if int(number[i]) == answer[i] else 'N'
if out == 'Y' * len(answer):
print('Good job!')
break
tries -= 1
print(out)
else:
print('Aww, you failed')
I also added an else after the while for when tries reaches zero to catch a failure (see the Python docs or maybe this SO answer)

For Loop Not Breaking (Python)

I'm writing a simple For loop in Python. Is there a way to break the loop without using the 'break' command. I would think that by setting count = 10 that the exit condition would be met and the loop would stop. But that doesn't seem to be the case.
NOTE: Part of the challenge is to use the FOR loop, not the WHILE loop.
import random
guess_number = 0
count = 0
rand_number = 0
rand_number = random.randint(0, 10)
print("The guessed number is", rand_number)
for count in range(0, 5):
guess_number = int(input("Enter any number between 0 - 10: "))
if guess_number == rand_number:
print("You guessed it!")
count = 10
else:
print("Try again...")
count += 1
I'm new to programming, so I'm just getting my feet wet. I could use a 'break' but I'm trying figure out why the loop isn't ending when you enter the guessed number correctly.
The for loop that you have here is not quite the same as what you see in other programming languages such as Java and C. range(0,5) generates a list, and the for loop iterates through it. There is no condition being checked at each iteration of the loop. Thus, you can reassign the loop variable to your heart's desire, but at the next iteration it will simply be set to whatever value comes next in the list.
It really wouldn't make sense for this to work anyway, as you can iterate through an arbitrary list. What if your list was, instead of range(0,5), something like [1, 3, -77, 'Word', 12, 'Hello']? There would be no way to reassign the variable in a way that makes sense for breaking the loop.
I can think of three reasonable ways to break from the loop:
Use the break statement. This keeps your code clean and easy to understand
Surround the loop in a try-except block and raise an exception. This would not be appropriate for the example you've shown here, but it is a way that you can break out of one (or more!) for loops.
Put the code into a function and use a return statement to break out. This also allows you to break out of more than one for loop.
One additional way (at least in Python 2.7) that you can break from the loop is to use an existing list and then modify it during iteration. Note that this is a very bad way to it, but it works. I'm not sure that this will this example will work in Python 3.x, but it works in Python 2.7:
iterlist = [1,2,3,4]
for i in iterlist:
doSomething(i)
if i == 2:
iterlist[:] = []
If you have doSomething print out i, it will only print out 1 and 2, then exits the loop with no error. Again, this is a bad way to do it.
You can use while:
times = 5
guessed = False
while times and not guessed:
guess_number = int(input("Enter any number between 0 - 10: "))
if guess_number == rand_number:
print("You guessed it!")
guessed = True
else:
print("Try again...")
times -= 1
For loops in Python work like this.
You have an iterable object (such as a list or a tuple) and then you look at each element in the iterable, storing the current value in a specified variable
That is why
for i in [0, 1, 2, 3]:
print item
and
for j in range(4):
print alist[j]
work exactly the same. i and j are your storage variables while [0, 1, 2, 3] and range(4) are your respective iterables. range(4) returns the list [0, 1, 2, 3] making it identical to the first example.
In your example you try to assign your storage variable count to some new number (which would work in some languages). In python however count would just be reassigned to the next variable in the range and continue on. If you want to break out of a loop
Use break. This is the most pythonic way
Make a function and return a value in the middle (I'm not sure if this is what you'd want to do with your specific program)
Use a try/except block and raise an Exception although this would be inappropriate
As a side note, you may want to consider using xrange() if you'll always/often be breaking out of your list early.
The advantage of xrange() over range() is minimal ... except when ...
all of the range’s elements are never used (such as when the loop is
usually terminated with break)
As pointed out in the comments below, xrange only applies in python 2.x. In python 3 all ranges function like xrange
In Python the for loop means "for each item do this". To end this loop early you need to use break. while loops work against a predicate value. Use them when you want to do something until your test is false. For instance:
tries = 0
max_count = 5
guessed = False
while not guessed and tries < max_count:
guess_number = int(input("Enter any number between 0 - 10: "))
if guess_number == rand_number:
print("You guessed it!")
guessed = True
else:
print("Try again...")
tries += 1
What #Rob Watts said: Python for loops don't work like Java or C for loops. To be a little more explicit...
The C "equivalent" would be:
for (count=0; count<5; count++) {
/* do stuff */
if (want_to_exit)
count=10;
}
... and this would work because the value of count gets checked (count<5) before the start of every iteration of the loop.
In Python, range(5) creates a list [0, 1, 2, 3, 4] and then using for iterates over the elements of this list, copying them into the count variable one by one and handing them off to the loop body. The Python for loop doesn't "care" if you modify the loop variable in the body.
Python's for loop is actually a lot more flexible than the C for loop because of this.
What you probably want is to use break and to avoid assigning to the count variable.
See the following, I've edited it with some comments:
import random
guess_number = 0
count = 0
rand_number = 0
rand_number = random.randint(0, 10)
print("The guessed number is", rand_number)
# for count in range(0, 5): instead of count, use a throwaway name
for _ in range(0, 5): # in Python 2, xrange is the range style iterator
guess_number = int(input("Enter any number between 0 - 10: "))
if guess_number == rand_number:
print("You guessed it!")
# count = 10 # instead of this, you want to break
break
else:
print("Try again...")
# count += 1 also not needed
As others have stated the Python for loop is more like a a traditional foreach loop in the sense that it iterates over a collection of items, without checking a condition. As long as there is something in the collection Python will take them, and if you reassign the loop variable the loop won't know or care.
For what you are doing, consider using the for ... break ... else syntax as it is more "Pythonic":
for count in range(0, 5):
guess_number = int(input("Enter any number between 0 - 10: "))
if guess_number == rand_number:
print("You guessed it!")
break
else:
print("Try again...")
else:
print "You didn't get it."
As your question states NOTE: Part of the challenge is to use the FOR loop, not the WHILE loop and you don't want to use break, you can put it in a function and return when the correct number is guessed to break the loop.
import random
def main():
guess_number = 0
count = 0
rand_number = 0
rand_number = random.randint(0, 10)
print("The guessed number is", rand_number)
for count in range(0, 5):
guess_number = int(input("Enter any number between 0 - 10: "))
if guess_number == rand_number:
print ("You guessed it!")
return
else:
print("Try again...")

Categories