Python: Cows and Bulls game - python

I am writing a code fora game which randomly generates a 4-digit number. Ask the user to guess a 4-digit number. For every digit that the user guessed correctly
in the correct place, they have a “cow”. For every digit the user guessed correctly in the wrong place is a “bull.” Every time the user makes a guess, tell them how many “cows” and “bulls” they have. Once the user guesses the correct number, the game is over. Keep track of the number of guesses the user makes throughout the game and tell the user at the end.
The code is below.
import random
rand=[random.randint(0,9) for n in range(3)]
user_guess=[input("Please guess 4-digit number: ")]
def game():
count=0
while True:
guess=[i for i in rand]
listnum=[i for i in user_guess]
if guess == listnum:
print("You won.")
print("It took you "+str(count)+" guess.")
break
if guess != listnum:
cow=0
bull=0
count+=1
for x in range(0,3):
if guess[x]==listnum[x]:
cow+=1
if len(set(guess)&set(listnum))>num:
bull=len(set(guess)&set(listnum)) - cow
print("Cows: "+str(cow)+' Bulls: '+str(bull))
game()
But I am getting the following error after it asks the user to guess the number and takes the input. The error is given below.
Please guess 4-digit number: 1234
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-48-64a0b0d4d766> in <module>()
41 print("Cows: "+str(cow)+' Bulls: '+str(bull))
42
---> 43 game()
44
45
<ipython-input-48-64a0b0d4d766> in game()
33 count+=1
34 for x in range(0,3):
---> 35 if guess[x]==listnum[x]:
36 cow+=1
37
IndexError: list index out of range
What mistake am I making here?

So it's basically a variant of Mastermind, eh? Anyway, for user_guess, you have brackets around the entire return of input. Since input is a string, then this gives you back a list with just one item. For example, if the user enters 1234, then user_guess becomes the list ['1234'], not ['1', '2', '3', '4']. This means listnum=[i for i in user_guess] just gives you back [1234] (a list with one element, which is the number one thousand, two hundred thirty-four), not [1,2,3,4]. So try removing the brackets you have around input.
Also, you should change your creation of listnum to listnum=[int(i) for i in user_guess], since you're ultimately trying to compare integers, not strings.
Some other things I noticed:
You tell users to use a 4-digit number. So you should be using range(4)
You ask the user to guess only once. You should have the input statement in your function.
Your counter for the number of guesses is off by one. Try putting the count += 1 right after the while True.
The guess=[i for i in rand] seems redundant. You could just use the list rand here. Also, it seems counter-intuitive to call the secret answer "guess".
In fact, since you have everything as a function, there's no need for a while loop. You can just call the game() function again after a wrong guess, and use return when the user finally wins.
For the bull count, you use a variable called num, but I don't see this defined anywhere. Shouldn't this just be 8? Also, consider the case where the bull count should be 4, or the secret answer is something like '1233': should a guess of '3354' give you two bulls?
And a grammatical point: the answer you print says "It took you [however many] guess", not "guesses" if the number of guesses is more than one.

Your definition of when a digit is a bull is a little bit unclear. Let's say your solution key is e.g. [1, 8, 5, 8] and your guess 8888. The number 8 is present multiple times in the solution key. So you have 2 cows. But what is your expected output for bulls in this case? One possible solution (see below) would be to check if each guessed number is present anywhere in the solution key (even though it might already be a cow).
The solution below includes some of the remarks already mentioned by others (see post by #Bill M.).
Possible solution:
import random
def game(num_digits):
# generate list of random integers of length num_digits
listnum = [random.randint(0,9) for n in range(num_digits)]
print("Solution key = " + str(listnum))
count=0
while True:
count+=1
print("~~~ Guess: " + str(count) + " ~~~")
print("Please guess " + str(num_digits) + "-digit number: ")
# transform input string (e.g. "1234") to list of integers (e.g. [1,2,3,4])
guess = [int(i) for i in str(input())]
if guess == listnum:
print("You won.")
print("It took you "+str(count)+" guess(es).")
break
else:
cow=0
bull=0
for x in range(0,num_digits):
if guess[x]==listnum[x]:
cow += 1
elif guess[x] in listnum: # look if digit is somewhere else in the solution key (might already be a cow)
bull += 1
print("Cows: "+str(cow)+" Bulls: "+str(bull))
print("++++++++++++++++")
game(4)
Example output:
Solution key = [1, 8, 5, 8]
~~~ Guess: 1 ~~~
Please guess 4-digit number:
2288
Cows: 1 Bulls: 1
++++++++++++++++
~~~ Guess: 2 ~~~
Please guess 4-digit number:
8888
Cows: 2 Bulls: 2
++++++++++++++++
~~~ Guess: 3 ~~~
Please guess 4-digit number:
1858
You won.
It took you 3 guess(es).

define input as string not as one elemented list with one string in it
user_guess=input("Please guess 4-digit number: ")
then split the list using a seperator
listnum= user_guess.split(',')
https://www.tutorialspoint.com/python/string_split.htm
plus num is undefined in
if len(set(guess)&set(listnum))>num:

Remove the square-brackets from this line user_guess=[input("Please guess 4-digit number: ")], as is creating a list with one entry, the user string input. which is probably related to IndexError as there is only one entry in the list, e.g. ['1234'].
Another fix is convert the user string input into a list of integers, before the while-loop:
user_guess = input("Please guess 4-digit number: ")
def game():
count=0
listnum = [int(num) for num in user_guess]
# or use `map`
# listnum = list(map(int, user_guess))
The infinite-loop that happens after that is a different problem.

Related

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

Why can't I compare an input to a random number in Python

So I basically wanna compare "Number" and "Guess" in the if statement, but no matter what it says they don't match (I get the else response, not included here). Even if I copy the random number they don't match.
Thanks in advance!
import time
def the_start():
points = 0
attempt = 1
print("Attempt:",attempt)
print("Your goal is to guess a number between 1 and 10 - Points:",points)
time.sleep(2)
attempt = attempt + 1
number = random.randint(0,10)
print(number)
guess = input("What is your guess? :")
time.sleep(2)
if guess == number:
points = points + 1
print("OMG YOU WERE RIGHT! Here, have some fake cheers! *cheer*")
time.sleep(5)
guess is a string. You need to do conversion of the string and handle error conditions. int() will convert a string to an integer, but it will throw an exception if the string is not purely numbers.

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

Python code to guess a number produces same number twice or thrice when close

I am new to python, sorry about a basic one.
The code works fine but it guesses same number twice or maybe more number of times. I want to guess an unique number every time.
import random
print("Hey human guess a number between 1 to 50 and i will try guessing what it is ! \n ")
input("Press enter when you have done the first step \n")
print("after my guess if its correct then hit y, if i need to guess higher than hit g and if i need to guess lower then hit l\n")
answer = ""
m = 1
n = 50
while(answer!='y'):
guess = random.randint(m,n)
print(guess)
reply = input("Is my guess correct ?")
if reply == 'y':
print("GG")
answer = 'y'
elif reply == 'l':
n = guess
print("\n Okay let me try again")
elif reply == 'g':
m = guess
print("\n aaah let me try again please \n")
else:
print("\n Seriously man what did i tell you before ?")
Thank you in advance.
As stated in the docstring of random.randint, this method "returns a random integer in range [a, b], including both end points". That means that when you assign the guess to either m or n the guess is going to be included for the range of the random.
Thus, to fix your code you could modify the following lines:
m = 0
n = 51
guess = random.randint(m+1,n-1)
In this way, you never include the guess in the range of the random. Hope this helps.
Create a list of guessed numbers guessed_numbers = []
Then whenever save the guess guessed_numbers.append(guess)
And before setting guess, check that guess is not in guessed numbers.
So you wind up with:
n = 50
guessed_numbers = []
while (answer != 'y'):
guess = random.randint(m, n)
while (guess in guessed_numbers):
guess = random.randint(m, n)
guessed_numbers.append(guess)
print(guess)
The problem is likely that random.randint produces a number between m and n inclusive. If the range is 1-50, and the program guesses 50, it sets the upper bound to 50 again, which means it could guess that number twice. It will be more likely to happen as the range narrows.
I think if you change the line
n=guess
to read
n=guess-1
and similarly add one for m when it guesses too low, you'll get the result you're looking for.

python while loop unexpected behavior

I'm relatively new to Python, and I don't understand the following code produces the subsequently unexpected output:
x = input("6 divided by 2 is")
while x != 3:
print("Incorrect. Please try again.")
x = input("6 divided by 2 is")
print(x)
the output of which is:
6 divided by 2 is 3
Incorrect. Please try again.
6 divided by 2 is 3
3
Incorrect. Please try again.
6 divided by 2 is
Why is the while loop still being executed even though x is equal to 3?
input() returns a string, which you are comparing to an integer. This will always return false.
You'll have to wrap input() in a call to int() for a valid comparison.
x = int(input("6 divided by 2 is"))
while x != 3:
print("Incorrect. Please try again.")
x = int(input("6 divided by 2 is"))
print(x)
Read more on int() here.
You are getting this error is because you are not parsing the input like so:
x = int(input("6 divided by 2 is"))
If you replace your inputer statement with that, it'll work.
input method gives the string. So you need to typecast to int as:
x = int(input("6 divided by 2 is"))
Here is my answer to your question
Guesses = 0
while(Guesses < 101):
try:
x = int(input("6 divided by 2 is: "))
if(x == 3):
print("Correct! 6 divide by 2 is", x)
break
else:
print("Incorrect. try again")
Guesses += 1
except ValueError:
print("That is not a number. Try again.")
Guesses += 1
else:
print("Out of guesses.")
I am assuming you wanted the user to input a number so i put your code into a while\else loop containing a try\except loop. The try\except loop ensures that if the users inputs a number, a ValueError will appear and it will inform them that what they inputted was not a number. The while\else loop ensures that the user will be inputted the question if the Guesses limit is no higher than 100. This code will ensure that if the user guesses the answer which is 3, the user will be prompted that they got the answer right and the loop will end; if the users guesses anything besides 3 (Number wise) the answer will be incorrect and the user will be prompted the question again; if the user guesses a string it will be classified as a ValueError and they will be notified that their answer wasn't a number and that the user has to try again.
Considering this was asked a long time ago, I'm assuming your probably forgot about this or you figured out the answer but if not try this and tell me if you like this answer. Thank :)
I actually tried this myself now with python 2.6, and did get an int without converting to int. For example, when I try the following:
x = input("6 divided by 2 is")
print "Your input is %s, %s" % (x, type(x))
I get the following:
6 divided by 2 is 2
Your input is 2, <type 'int'>
So is this a version issue? Or maybe an environment issue (I'm using OS X)?
What I do conclude is that it should be a good practice using previous recommendations using int().

Categories