I'm implementing a game which allows two players to pick alternately from a pile of 27 sticks. Each player may take 1, 2, or 3 sticks on each turn; the player forced to take the final stick loses.
I've done most of the code, but I must include validation. Besides taking 1-3 sticks, a player is not allowed to take the final stick. I've tried using a continue statement, but when player two exceeds the limit, the program returns to player 1's turn.
Here's what I have so far:
count = 27
T = False
F = False
while count > 1:
Playerone = int(input("Player 1's Turn, Enter from 1-3"))
if Playerone < 1 or Playerone > 3:
print("Error")
continue
count -= Playerone
print(count)
if count == 1:
print("P1 wins")
break
if count < 1:
print("You can't pick up those many sticks")
continue
Playertwo = int(input("Player 2's Turn, Enter from 1-3"))
if Playertwo < 1 or Playertwo > 3:
print("Error")
continue
count -= Playertwo
print(count)
if count == 1:
print("P2 wins")
break
if count < 1:
print("You can't pick up those many sticks")
continue
The last if statement is the issue
Help would be much appreciated,
You have a basic flaw in your loop flow: regardless of the problem encountered with either player's input, you use continue to return to the top of the loop, which gets you back to Player 1. You need to fix this: loop on a given player's input until it's valid in all ways. Something like this should do:
valid = False
while not valid:
Playertwo = int(input("Player 2's Turn, Enter from 1-3"))
if Playertwo < 1 or Playertwo > 3:
print("Error")
elif count - Playertwo < 1:
print("You can't pick up those many sticks")
else:
valid = True
Apply this to each player's input. Once you get out of this loop, you have valid input. From there, you can decrease the count and determine whether someone has won.
One way to ensure a valid user input is to use a loop.
Here's a quick example of a function you might use:
def prompt_integer(msg, minval, maxval, err_invalid, err_oob):
while True:
resp = input(msg) # Python3, use raw_input in Python2
try:
resp = int(resp)
if minval <= resp <= maxval:
return resp
else:
print(err_oob)
except ValueError:
print(err_invalid)
x = prompt_integer("Enter an integer: ", 1, 3, "Invalid Integer.", "Integer Out of Bounds")
Here, the function will not return until the user enters a valid integer between 1 and 3 (inclusive).
If they enter, say, 'abc', then the program will display "Invalid Integer." and ask them again.
If they enter, say, 5, when you've specified that the bounds are 1 and 3 then the program will display "Integer Out Of Bounds", and then ask them again.
When this function returns you know you've got an acceptable value.
You might use this function in your code, and modify maxval argument each time you call it according to how many sticks they're able to pick up.
This is what I would do, you could go crazy with Classes, but that is a little much for you right now(but something to look into). You should also look into creating methods, but check out my code below with the comments I left.
def player_input(player_number: int): # This is a method, that requires an integer to be pass to it
p_input = int(input("Player {}'s Turn, Enter from 1-3: ".format(player_number)))
while p_input < 1 or p_input > 3: # This will cause a loop continuously asking the player to input a number until that number is between 1 or 3.
print('Please choose a number between 1 and 3')
p_input = int(input("Player {}'s Turn, Enter from 1-3: ".format(player_number))) # Format will replace the '{}' with the value of the variable you give it
return p_input # This 'return' line will return the what the results of what the player typed in
def found_winner(stick_number: int): # stick_number is a required variable and ': int' requires that that variable be an integer
winner = False
if stick_number == 1:
winner = True
return winner # This method will return if a winner is found or not
def next_player(player_number: int): # This method will swap the players turn
if player_number == 1:
player_number = 2
elif player_number == 2:
player_number = 1
return player_number
def start_game(stick_count: int = 27): # This method will start the game, the '= 27' says that you can give me any stick count you want(that is an integer), but if you don't provide one I will use '27' by default
player_number = 1
while stick_count > 1: # This will loop through until the stick count is 1 or less
sticks_to_remove = player_input(player_number) # I store the plays result just in case the stick_count goes below 1, and then I remove the sticks if the the count doesn't go below 1
if stick_count - sticks_to_remove < 1:
print('You cant pick up that many sticks')
continue
else:
stick_count -= sticks_to_remove # Remove the sticks
if found_winner(stick_count): # Look for the winner
print('Player {} wins!'.format(player_number))
else:
player_number = next_player(player_number) # If no winner go to the next player
if __name__ == '__main__': # This says only execute the 'start_game()' method automatically if this python script is called, this is useful later when you start creating more complicated Python scripts that span multiple files.
start_game()
Related
I have this dice game made in python for class, I am using functions for the scoring logic (which I believe is all working as desired). I have put these functions in a while loop so that when either player reaches 100 banked score the game ends. However, I cannot get this to work as intended.
while int(player1Score) < 100 or int(player2Score) < 100:
player1()
player2()
Here is one of the functions (the other is the same with score added to player 2's variable and some output changes):
def player1():
global player1Score #global score to reference outside of function
rTotal = 0 #running total - used when gamble
print("\nPlayer 1 turn!")
while 1==1:
d = diceThrow() #dicethrow output(s)
diceIndexer(d)
print(f"Dice 1: {dice1} \nDice 2: {dice2}")
if dice1 == '1' and dice2 == '1': #both die = 1 (banked & running = 0)
player1Score = 0
rTotal = 0
print("DOUBLE ONE! Banked total reset, Player 2's turn.")
break
elif dice1 == '1' or dice2 == '1': #either die = 1 (running = 0)
rTotal = 0
print("Rolled a single one. Player 2's turn!")
break
else: #normal dice roll - gamble or bank
choice = input("Gamble (G) or Bank (B): ")
choice = choice.upper() #incase lowercase letter given
if choice == 'G': #if Gamble chosen - reroll dice & add to running
rTotal += int(dice1) + int(dice2)
elif choice == 'B': #used to save score.
rTotal += int(dice1) + int(dice2)
player1Score += rTotal
print(f"\nPlayer 1 banked! Total: {player1Score}")
break
print("Turn over")
I have tried changing the 'or' in the while loop to an 'and'. While that did stop faster, it did not stop exactly as the other player achieved a score higher than 10.
bro.
i read your code but i can't get some points as below.
if dice1 == '1' and dice2 == '1': #both die = 1 (banked & running = 0)
player1Score = 0
the code above makes player1Score as zero.
and there's no adding score code for player2Score.
For this reason, the while loop doesn't stop.
plz, check it first.
Boolean logic works like this.
You want both scores to be less then 100 while the game runs which also means one of the scores should not be 100 or higher.
both scores less then 100
int(player1Score) < 100 and int(player2Score) < 100
one of the socres is not 100 or higher
!int(player1Score) >= 100 or !int(player1Score) >= 100
The reason why the game didn't stop when you changed the "or" to "and" is because player1Score and player2Score are being evaluated after both player1() and player2() are called. Even if player1 scored over 100, the game wouldn't stop and the turn would go over to player2, goes into the next loop evaluation and finally stop the loop.
To fix this, change the while loop of both player1() and player() to this.
while player1Score < 100:
And also add evaluation after calculating scores.
else: #normal dice roll - gamble or bank
choice = input("Gamble (G) or Bank (B): ")
choice = choice.upper() #incase lowercase letter given
# rTotal += int(dice1) + int(dice2)
# rewriting the same code is a bad practice.
# In this case, you can just write the same code outside the if-else logic since if-else doesn't effect the code.
rTotal += int(dice1) + int(dice2)
if choice == 'G': #if Gamble chosen - reroll dice & add to running
# added evaluation to stop the game
if player1Score+rTotal >= 100:
break
if choice == 'B': #used to save score.
player1Score += rTotal
print(f"\nPlayer 1 banked! Total: {player2Score}")
break
Hope this helps.
What I did is inside the function put an if statement (outside of the while) to return a value from the function using return like this:
def exampleFunction1():
#scoring logic here
if bank > finalScore: #Score to reach to win game
print(f"Score is over {finalScore}!")
return 0
Then inside the while loop, attach the functions to a variable so that the return value could be identified. Use the return value to break the while loop:
while True: #Breaks as soon as either player gets above 100 score
x = exampleFunction1()
if x == 0:
break
x = exampleFunction2()
if x == 0:
break
(Sidenote: I rewrote my whole program to take one gameLogic() function and apply this to the different players, but I still used the while loop stated second)
So, I'm working on Hand Cricket script & i want to stop "for" loop from iterating when a user's choice of number & CPU's choice of number are equal & if it's unequal it should keep iterating until it doesnt reach the final range's value
for i in range(1,7):
print("Ball %d"%i)
user_choice =int(input("Enter a number between 1 to 6 --> "))
cpu_choice=random.randint(1,6)
if user_choice < 7:
print("CPU picked --> ",cpu_choice)
run=cpu_choice+run
if user_choice == cpu_choice:
print("User is OUT!!")
run -= cpu_choice
print("Runs = %d \t Over = %d.%d\n"%(run,i//6,i%6))
break
print("Runs = %d \t Over = %d.%d\n"%(run,i//6,i%6))
else:
print("\nWRONG CHOICE!! %d ball is cancelled.\n"%i)
break
I might be missing something in your question, but it looks like you've already got it. break will force the for loop to exit. So if you wrap your break-statement in a conditional gate (if statement), you can set the criteria that must be met for the break.
Something like this comes to mind:
# Calculate the CPU's Random Integer ONCE
cpu_choice=random.randint(1,6)
# Iteratively Ask User for Input and Validate
for i in range(1,7):
# Capture Input from User
user_choice =int(input("Enter a number between 1 to 6 --> "))
# Verify Input in Specific Range
if user_choice not in range(1,7):
print("{} is not in the valid range. Try again.".format(user_choice))
else:
# Check if User Input Matches CPU's Selection
if user_choice == cpu_choice:
print("You've got the right number! The number was: {}".format(user_choice))
break # break out of the `for` loop!
# Not Correct Input from User
else:
print("{} is not the correct number. Try again.".format(user_choice))
Again, it seems like you've already come to this answer in a way. Are you asking something else instead?
Working on a battleship game in python. My function to check the user's 'guess' input in resulting in an endless validation loop. I want a guess in the format of 'a10' on a 10x10 grid. The validation function i have built to help validate is as follows:
def validate_guess(self,guess):
while True:
if (len(guess)) in range(2, 4):
if guess[0] not in 'abcdefghij' or guess[1:] not in '1,2,3,4,5,6,7,8,9,10':
print("Sorry the Grid is a 10x10 square you must enter a valid position. Try again...")
continue
else:
return guess
else:
if len(guess) < 2 or len(guess) > 3:
print("Oops! That's too not the right amount of characters. Please try again...")
continue
If the user guesses an incorrect value--it does spot it--but the error is returning a never ending loop with the printed error statement.
This is the portion of my game where the validation function is being used:
while True:
print("\n")
# get guess from player one in coordinate form (example: a10)
guess = input("{}'s turn to guess: ".format(player1.player))
# strip characters from the guess input
guess = guess.strip()
# validate the guess
guess = self.validate_guess(guess)
# append the guess to a list for player 1
player1.guesses.append(guess)
# break down the coordinates into x and y variables
x, y = ship1.split_guess(guess)
# increment guesses
guesses += 1
# loop to assess whether, hit, miss or a won game
if any(guess in ship for ship in grid2.play_two_board):
print("HIT")
grid2.print_guess_board(x, y, "h")
for ship in grid2.play_two_board:
try:
ship.remove(guess)
print(len(Board.play_two_board))
self.check_if_sunk(ship)
win = self.play_one_win_check(player1.player)
if win == 1:
print ("GAVE OVER!")
break
except ValueError:
pass
else:
print("Miss!")
grid2.print_guess_board(x, y, "m")
Not sure if it might be because i have two While statements? Just really stuck here would appreciate any guidance. Thanks.
*****************************8
edit --changed function to include the guess without actually passing it that value from the input statement but still getting same problem.
def validate_guess(self):
guess = input("Please enter a location:")
while True:
if len(guess) in range(2, 4):
if guess[0] not in 'abcdefghij' or guess[1:] not in '1,2,3,4,5,6,7,8,9,10':
print("Sorry the Grid is a 10x10 square you must enter a valid position. Try again...")
continue
else:
return guess
else:
if len(guess) < 2 or len(guess) > 3:
print("Oops! That's too not the right amount of characters. Please try again...")
continue
and just calling it like this:
while True:
print("\n")
# get guess from player one in coordinate form (example: a10)
# guess = input("{}'s turn to guess: ".format(player1.player))
# strip characters from the guess input
# guess = guess.strip()
# validate the guess
guess = self.validate_guess()
Within validate_guess, when the user enters a bad value, you have to get new input before you check again. See here.
Either return an error code (True/False ?) from your function, or have the function loop until the input is valid. Just add a command for new input at the bottom of the function's while loop.
Where can I add a while loop in this code to ask for another move. I really need help I can't figure it out. I want it to re-prompt the move so when the move is invalid it will ask for another move again. And if the move is valid it will ask for the NEXT move?
def valid1(pile1):
move = False
pile1 = 3
if pile1 == 0:
print 'please choose from pile 2 and 3:'
elif pile1 == 3:
move = int(input('please choose the amount you would like:'))
if move > 0 and move <= 2:
pile1 = pile1 - move
else:
print 'you have entered a invalid move'
return pile1
elif pile1 == 2:
move = int(input('please choose the amount you would like:'))
if move > 0 and move <= 2:
pile1 = pile1 - move
else:
print 'you have entered a invalid move'
return pile1
elif pile1 == 1:
move = int(input('please choose the amount'))
if move > 0 and move <= 1:
pile1 = pile1 - move
else:
print 'you have entered a invalid move'
return pile1
else:
print pile2
print valid1(3)
I'm finding it a bit hard to understand your code precisely, so I'm not sure which bit to loop around, but I think if you use the following general principle you'll fix this:
looping = True
while looping = True :
move = int(input('please choose the amount you would like:'))
if move > 0 and move <= 2:
pile1 = pile1 - move
else:
print 'you have entered a invalid move'
return pile1
In the code above, you'll keep looping and so the input prompt will keep being asked after you've entered a move. If you want to break out of the loop when a certain condition is met, then after you've coded the condition put looping = False. In python, the first letter of Boolean values must be capitalized. There are other ways to do this, such as with break statements etc, but this is the method I prefer to use. As I said, I wasn't sure exactly what you wanted looping around in the code, but if you enclose it all in a 'while' statement like above, it should be fixed. Hope this helps!
I have updated my code with the changes made. I am still getting incorrect results...
# Import statements
import random
# Define main function that will ask for input, generate computer choice,
# determine winner and show output when finished.
def main():
# Initialize Accumulators
tie = 0
win = 0
lose = 0
score = 0
# initialize variables
user = 0
computer = 0
# Initialize loop control variable
again = 'y'
while again == 'y':
userInput()
computerInput()
if score == win:
print('You won this round, good job!')
win += 1
elif score == tie:
print('You tied this round, please try again!')
tie += 1
else:
print('You lost this round, please try again!')
lose += 1
again = input('Would you like to play another round (y/n)? ')
#determine winning average
average = (win / (win + lose + tie))
print('You won ', win, 'games against the computer!')
print('You lost ', lose, 'games against the computer.')
print('You tied with the computer for', tie)
print('Your winning average is', average)
print('Thanks for playing!!')
# get user input for calculation
def userInput():
print('Welcome to Rock, Paper, Scissor!')
print('Please make your selection and and Good Luck!')
print('1) Rock')
print('2) Paper')
print('3) Scissor')
user = int(input('Please enter your selection here: '))
print('You selected', user)
# get compter input for calculation
def computerInput():
computer = random.randint(1, 3)
print('The computer chose', computer)
def getScore():
if user == 1 and computer == 3:
score = win
return score
elif user == 2 and computer == 1:
score = win
return score
elif user == 3 and computer == 2:
score = win
return score
elif user == computer:
score = tie
return score
else:
score = lose
return score
# Call Main
main()
In Python:
>>> print("3" == 3)
False
Strings and integers are values of different data types, and will not compare equal. Try changing your input to:
userInput = int(input('Please enter your selection here: '))
This will convert the string typed by the user to a number for later comparison. (Note that I have assumed you are using Python 3.x, because input() behaves slightly differently in Python 2.x.)
Note that this will throw an error if you type anything other than a number.
Update: As pointed out by #FelipeFG in the comments below, you are also overwriting the function userInput with the value typed by the user. You'll need to change the name of one or the other, for example:
def getUserInput():
...
Also don't forget to change the place where you call the function. Do the same for computerInput (change to getComputerInput).
Later on, you can change those to actual functions that return values.
userInput() calls the function "userInput", but you discard the result. The same remark applies to computerInput().
userInput == 1 asks whether the function userInput itself is equal to 1. It isn't. The same remark applies to computerInput == 3 and the others.
In the function "userInput", userInput = ... binds the name "userInput" to the result of the expression. This makes "userInput" a local variable of the function. The function doesn't explcitly return anything, therefore it returns None.
If you're using Python 3, input returns a string, and you should convert its result to an int. If you're using Python 2, input evaluates whatever is entered, which isn't safe; you should use raw_input instead and convert its result to an int.
You need to compare against the return value of your function, not the function itself.
Also:
again = input('Would you like to play another round (y/n)? ')
This will throw an exception if you enter y or n, because there is no defined identifier of that name! What you want to use instead is raw_input()
Edit: As pointed out by Greg, this only applies to Python 2.x. You seem to be using Python3 though.