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.
Related
In this post I will do 3 things in order:
A introduce the question
B display the answer in the textbook to this question
C show my doubt
A introduce the question
The question goes like this:
(1)
Make a list or tuple containing a series of 10 numbers and five letters.
Randomly select four numbers or letters from the list and print a message saying that any ticket matching these four numbers or letters wins a prize;
(2)
Make a list or tuple containing a series of 10 numbers and five letters.
Randomly select four numbers or letters from the list and print a message saying that any ticket matching these four numbers or letters wins a prize.
B display the answer in the textbook to this question
This answer code is from the textbook:
(1)
from random import choice
possibilities = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 'a', 'b', 'c', 'd', 'e']
winning_ticket = []
print("Let's see what the winning ticket is...")
# We don't want to repeat winning numbers or letters, so we'll use a
# while loop.
while len(winning_ticket) < 4:
pulled_item = choice(possibilities)
# Only add the pulled item to the winning ticket if it hasn't
# already been pulled.
if pulled_item not in winning_ticket:
print(f" We pulled a {pulled_item}!")
winning_ticket.append(pulled_item)
(2)
from random import choice
def get_winning_ticket(possibilities):
"""Return a winning ticket from a set of possibilities."""
winning_ticket = []
# We don't want to repeat winning numbers or letters, so we'll use a
# while loop.
while len(winning_ticket) < 4:
pulled_item = choice(possibilities)
# Only add the pulled item to the winning ticket if it hasn't
# already been pulled.
if pulled_item not in winning_ticket:
winning_ticket.append(pulled_item)
return winning_ticket
def make_random_ticket(possibilities):
"""Return a random ticket from a set of possibilities."""
ticket = []
# We don't want to repeat numbers or letters, so we'll use a while loop.
while len(ticket) < 4:
pulled_item = choice(possibilities)
# Only add the pulled item to the ticket if it hasn't already
# been pulled.
if pulled_item not in ticket:
ticket.append(pulled_item)
return ticket
def check_ticket(played_ticket, winning_ticket):
# Check all elements in the played ticket. If any are not in the
# winning ticket, return False.
for element in played_ticket:
if element not in winning_ticket:
return False
# We must have a winning ticket!
return True
possibilities = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 'a', 'b', 'c', 'd', 'e']
winning_ticket = get_winning_ticket(possibilities)
plays = 0
won = False
# Let's set a max number of tries, in case this takes forever!
max_tries = 1_000_000
while not won:
new_ticket = make_random_ticket(possibilities)
won = check_ticket(new_ticket, winning_ticket)
plays += 1
if plays >= max_tries:
break
if won:
print("We have a winning ticket!")
print(f"Your ticket: {new_ticket}")
print(f"Winning ticket: {winning_ticket}")
print(f"It only took {plays} tries to win!")
else:
print(f"Tried {plays} times, without pulling a winner. :(")
print(f"Your ticket: {new_ticket}")
print(f"Winning ticket: {winning_ticket}")
print(check_ticket(new_ticket, winning_ticket))
C Show my doubt
And my question lies in this para:
plays = 0
won = False
# Let's set a max number of tries, in case this takes forever!
max_tries = 1_000_000
while not won:
new_ticket = make_random_ticket(possibilities)
won = check_ticket(new_ticket, winning_ticket)
plays += 1
if plays >= max_tries:
break
if won:
print("We have a winning ticket!")
print(f"Your ticket: {new_ticket}")
print(f"Winning ticket: {winning_ticket}")
print(f"It only took {plays} tries to win!")
else:
print(f"Tried {plays} times, without pulling a winner. :(")
print(f"Your ticket: {new_ticket}")
print(f"Winning ticket: {winning_ticket}")
I wonder why it first define
won=False,then in the if not won (why doesn't it say if True?)
it defines won = check_ticket(new_ticket,winning_ticket)
which can return False or True,
and at the end says if won??? is this mean if False? why doesn't it say so?
And moreover,I wonder why my code to this question connot work:
from random import choice
possibilities=['1','2','3','4','5','6','7','8','9','10','a','b','c','d','e']
def make_winning_ticket(possibilities):
winning_ticket=[]
while len(winning_ticket)<4:
new_number=choice(possibilities)
if new_number not in winning_ticket:
winning_ticket.append(new_number)
return winning_ticket
def make_new_ticket(possibilities):
new_ticket=[]
while len(new_ticket)<4:
new_number=choice(possibilities)
if new_number not in new_ticket:
new_ticket.append(new_number)
return new_ticket
play=0
max_try=100000
def check_ticket(new_ticket,winning_ticket):
while play<max_try:
for element in new_ticket:
if new_ticket not in winning_ticket:
play+=1
make_new_ticket(possibilities)
print(play)
make_winning_ticket(possibilities)
make_new_ticket(possibilities)
check_ticket(winning_ticket,new_ticket)
Thank you for your patience:)
I wonder why it first define won=False, then in the if not won (why doesn't it say if True?) it defines won = check_ticket(new_ticket,winning_ticket) which can return False or True, and at the end says if won??? is this mean if False? why doesn't it say so?
No. It means what it says:
First we have a while loop which continuously checks whether "we" have won. This decision (won or not won) is saved in a variable won.
In order to be able to properly enter the while loop, the condition (not won) must be true, so won must be False. So it is set this way.
After the while loop, we check hether we have won. And it clearly says so: if won: means "if we have won".
And moreover,I wonder why my code to this question connot work:
To be honest, I didn't try to follow each line of it, but what seems to be one of the biggest problems: you discard the return values of your functions.
If we have a function, say
def f(x):
y = 2 * x
return y
it is not sufficient to do
f(10)
and then to expect that we have done something useful: the y variable is completely inside the function. In order to get access to its value, we must do
y = f(10) # y will be 20
or even (with a completely different name than inside the function):
y1 = f(10) # y1 will be 20
y2 = f(15) # y2 will be 30
So in your example, you should do at least
winning_ticket = make_winning_ticket(possibilities)
new_ticket = make_new_ticket(possibilities)
check_ticket(winning_ticket, new_ticket)
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.
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
I'm just starting to learn python and have come across some trouble when trying to program a simple 1-D version of single player battleship.
2 things I can't seem to make work:
I have a created a 1 dimensional list (which is the gameplay board), but need to display/print the indices of the repeating element of the list. In other words, how can I print a list that only shows the indices of the elements in my board?
I want to replace a that element with a "*" if it was a wrong guess. For example, if I wrongly guess the position as 4 in a board of 5 elements, I want to display:
1 2 3 * 5
Moreover, I want to display the winning hit as an "X":
1 2 X * 5
Here's my current code:
from random import randint
ship=randint(0, 5)
board = ["O","O","O","O","O"]
print ("Let's play Battleship!")
attempts = 1
while attempts < 4:
print (board)
guess = int(input("Guess Where My Ship Is: "))
if guess == ship:
print ("Congratulations Captain, you sunk my battleship!")
break
else:
print ("You missed my battleship!")
if attempts<3:
print("Try again!")
elif attempts==3:
print("Better luck next time, Captain!")
attempts+=1
Thank you and apologies for the lame question.
Good practice: set the board size to a variable so you can reference it regularly. Put this at the top
size = 5 # Can be changed later if you want to make the board bigger
Next, have your ship location be chosen based on that
ship = randint(0, size)
Instead of making a board filled with 0's, Generate the board dynamically so that it's already pre-populated with the possible values.
board = [] # Creating an empty board
for i in range(1, size):
position = str(i) # Converting integers to strings
board.append(position) # Adding those items to the board
Then, inside of the game logic, after the "You missed my battleship" line, change the relevant square on the board
...
print("You missed my battleship!")
number_guess = int(guess) - 1 # Because lists are zero-indexed
board[number_guess] = "*" # Assign "*" to the spot that was guessed
if attempts < 3:
...
To implement your two display functionalities, I would recommend just letting your board list just hold the display values, as you're not using it anywhere else anyway.
from random import randint
ship=randint(1, 5)
board = ['1', '2', '3', '4', '5']
print ("Let's play Battleship!")
attempts = 1
while attempts < 4:
print(' '.join(board))
guess = int(input("Guess Where My Ship Is: "))
if guess == ship:
print ("Congratulations Captain, you sunk my battleship!")
board[guess - 1] = 'X'
break
else:
print ("You missed my battleship!")
board[guess - 1] = '*'
if attempts<3:
print("Try again!")
elif attempts==3:
print("Better luck next time, Captain!")
attempts+=1
print(' '.join(board))
One more thing: You have a bug when you're selecting the index of the ship (should be in range [1, 5]), which I've also corrected.
In case you're expanding on your battleship program and you must have a function that prints out the indices of a list (unless the value is '*' or 'X'), one way is to simply do:
def display(b):
print(' '.join(y if y in 'X*' else str(x + 1) for x, y in enumerate(b)))
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...")