blackjack game: for loops 'not in' vs 'in' - python

I have run into some trouble using for loops while making a blackjack game simulation. The function new_game simulates four cards being dealt, while new_card ensures no card is repeated in a game. I created two variations of the function new game and was wondering how they differ.
In Version 1, there were situations where the function only returned 3 cards, while Version 2 seems to work as expected.
Version 1:
def new_game():
game=[];
for x in range(4):
n=new_card();
if n not in game:
game+=[n];
else:
new_game();
print(game);
return game
Version 2:
def new_game():
game=[];
for x in range(4):
n=new_card();
if n in game:
new_game();
print(game);
else:
game+=[n];
return game

Calling new_game is not the best way to solve this project. You can try multiple ways , one of which I am showing. Rather than a constant for loop try to check the length of list until it is of desired length.
def new_game():
game=[];
while len(game)!=4:
n = new_card()
while(n in game):
n = new_card()
else:
game.append(n)
return game
print new_game()
I am not sure if this is a good design but still it works and you may modify it.
EDIT
Thanks to Blckknght for suggesting this.
def new_game():
game=[]
while len(game)!=4:
n = new_card()
if n not in game:
game.append(n)
return game
print new_game()

Related

My while loop stops after 6 loops despite the fact it is meant to go on forever

I am coding a game called tanks in python and there are meant to be 50 rounds however it stops after only 6 can anybody tell me what is going on. It is also meant to stop when the user's score reaches 10 and because there are only 6 rounds there is no way it can be stopped due to that.
Here is my code:
#Tanks problem
import random
Grid = [["" for X in range(8)] for Y in range(8)]
PlacePicked=[]
#subroutine to place tanks
def TankPlace():
global Grid
for I in range(0,10,1):
while True:
X=random.randint(0,7)
Y=random.randint(0,7)
if Grid[X][Y]=="T":
pass
else:
Grid[X][Y]="T"
break
#subroutine to output places already picked
def OutputPlacePicked():
global PlacePicked
Places=""
if len(PlacePicked)==0:
pass
else:
for I in range(0,len(PlacePicked),1):
Places=Places+PlacePicked[I]+", "
print("\nSo far you have picked the coordinates of {}".format(Places[:-2]))
#subroutine to check if inputted coordinate is a tank or not
def GameInput(X,Y):
X1=X-1
Y1=Y-1
global Grid
global PlacePicked
while True:
if "({} ,{})".format(X,Y) in PlacePicked:
print("\nYou have already chosen ({}, {})".format(X, Y))
X=int(input("\nWhat is your X coordinate?\n"))
Y=int(input("\nWhat is your Y coordinate?\n"))
elif Grid[X1][Y1]=="T":
print("\nTank Hit!")
PlacePicked.append("({} ,{})".format(X, Y))
tank="True"
return tank
else:
print("\nTank Missed!")
PlacePicked.append("({} ,{})".format(X, Y))
tank="False"
return tank
#maincode
print("Welcome to Tanks!\n")
print("Instructions:\n-Tanks is a game for 1 player.\n-At the start of the game, the computer places 10 tanks on an 8x8 board but does not\nreveal their locations to the player.\n-Each tank occupies one square on the board.\n-The player enters a grid reference, e.g. (1,5) on each turn.\n-The player destroys the tank if the square is occupied by a tank.\n-The player wins if they destroy all the tanks within 50 turns.")
go=0
score=0
while True:
TankPlace()
OutputPlacePicked()
GameInput(int(input("\nWhat is your X coordinate?\n")), int(input("\nWhat is your Y coordinate?\n")))
if GameInput=="True":
score=score+1
elif GameInput=="False":
pass
if score==10:
print("You Win!")
break
else:
pass
if go==50:
print("You Lose")
break
else:
pass
go=go+1
Could anybody tell me why this is happening?
I've modified you "main" a little:
#maincode
print("Welcome to Tanks!\n")
print("""Instructions:
-Tanks is a game for 1 player.
-At the start of the game, the computer places 10 tanks on an 8x8 board but does not
reveal their locations to the player.
-Each tank occupies one square on the board.
-The player enters a grid reference, e.g. (1,5) on each turn.
-The player destroys the tank if the square is occupied by a tank.
-The player wins if they destroy all the tanks within 50 turns.""")
go=0
score=0
TankPlace()
while True:
OutputPlacePicked()
GameInput(int(input("\nWhat is your X coordinate?\n")), int(input("\nWhat is your Y coordinate?\n")))
if GameInput=="True":
score=score+1
elif GameInput=="False":
pass
if score==10:
print("You Win!")
break
else:
pass
if go==50:
print("You Lose")
break
else:
pass
go=go+1
Note that I've moved the call to TankPlace() before the loop; I figured that placing the tanks anew with each move, wouldn't help the player to win.
I've also removed the global tank because it wasn't used.
Anyway, after that I was able to play more than 6 moves.
The game ended prematurely nevertheless, since I guessed a 9 which then produced an exception. It would be a real improvement for the next release to check the user's input.
My guess is the compare of GameInput which has been cast to int vs the string "True"
I will let you look it up, but I fear the compare of two different types will degrade to a compare of the bool types and always succeed if the int is non-zero and the string is non-empty..

Force Python code to restart itself properly

I have tried to figure out a way on how to restart my code in Python, but I can't get it to work properly.
if keepLooping == True:
if userInput == randomNumber:
if attempt == 1:
print()
print("Correct, First try!")
stop = time.time()
print("It took", int(stop - start), "seconds.")
replay = input("Do you want to play again?: ")
if replay.lower() in ("yes"):
print()
os.execl(sys.executable, '"{}"'.format(sys.executable), *sys.argv) # Restart code. You are here
elif replay.lower() in ("no"):
break
else:
print("Invalid input, Yes or No?")
continue # Restart segment. You are here
replayAttempt += 1
print()
As you can see, I have tried using os.execl(sys.executable, '"{}"'.format(sys.executable), *sys.argv). Sure, it works, but then one of my inputs turn red, as you can see here. I have been trying to solve this but I can't find a solution.
I found a solution for the text being red, I added '\033[37m' before my inputs. The only problem I have now is that it can only restart once. When I try it again I get this error code here.
One way to this is to encapsulate thing into function
going from this
#start of scrip
#... game logic
#end of script
to
def game():
#...game logic
game()
encapsulated like this allow for easier reuse of stuff, and allow you to reduce repetition, if you do same thing in your code two or more times that is when you should factor that out into its own function, that is the DRY principle, Don't Repeat Yourself.
You can do something like this for example
def game():
#...game logic
return game_result
def main():
done=False
result=[]
while not done:
result.append( game() )
reply = input("Do you want to play again?: ")
if reply=="no":
done=True
#display the result in a nice way
main()
Here the main function do a couple of simple thing, play one round of the game, save the result, ask if you want to play again and display the result, and the game function do all the heavy work of playing the game.
Here is a simple working example of guess the number between 0 and 10
import random
def game(lower,upper):
answer = str(random.randint(lower, upper))
user_answer = input(f"Guess a number between {lower} and {upper}: ")
game_result = user_answer == answer
if game_result:
print("you win")
else:
print("you lose, the answer was:",answer)
return game_result
def main(lower=0,upper=10):
done=False
result=[]
while not done:
result.append( game(lower,upper) )
reply = input("Do you want to play again?: ")
if reply=="no":
done=True
print("Your result were",sum(result),"/",len(result) )
main()
Notice that the game function take 2 arguments, so you can play this game not just with 0 and 10, but any two number you desire, in turn the main function also take those same arguments but assign them default value so if you don't call this function with any of them it will use those default value and use them to call the game function, doing so allow for flexibility that you wouldn't have if you lock it to just 0 and 10 in this case.
(the sum(result) is because boolean are a subclass of int(numbers) so in math operation they are True==1 and False==0)

AI tictactoe - future boards and computer moves

I was requested to improve my player vs. player tic-tac-toe to an AI tic-tac-toe in which the player plays against the computer:
to do this I need to write two functions:
one that gets the board and the symbol of the current player and returned a list of all possible future boards - each future board is a list that contains two elements: one is the place that the symbol was placed in and the other is the board after placing the symbol - the board after one turn (I am using a nested list board as can be seen in the code below (in which I received help, here)
The second function I need is a function which does the computers turn - it uses the first function and picks an optimal move in one of the following ways:
picks a random move (just for the beginning, if the computer goes first) and plays it
OR
if the computer can win in the next turn he picks and plays this option
AND
if the player can win in the next turn the computer should "block" him.
what I have is a player vs player tic-tac-toe
code:
def get_move(whoseturn, board):
rowloc=int(input(f'{whoseturn},insert the deserved row to place your symbol: '))
coloc=int(input(f'{whoseturn} insert the deserved column to place your symbol: '))
while True:
if not (0 <= rowloc < 3 and 0 <= coloc < 3):
print('row and column must be 0, 1, or 2')
rowloc = int(input(f'{whoseturn},insert the deserved row to place your symbol: '))
coloc = int(input(f'{whoseturn} insert the deserved column to place your symbol: '))
elif board[rowloc][coloc] !='e':
print("The deserved place is taken, choose again ")
rowloc = int(input(f'{whoseturn},insert the deserved row to place your symbol: '))
coloc = int(input(f'{whoseturn} insert the deserved column to place your symbol: '))
else:
board[rowloc][coloc] = whoseturn
break
return rowloc, coloc
def display_board(board):
print('\n'.join([' '.join(board[i]) for i in range(3)]))
def win(board, whoseturn, x, y):
if board[0][y] == board[1][y] == board [2][y] == whoseturn:
return True
if board[x][0] == board[x][1] == board [x][2] == whoseturn:
return True
if x == y and board[0][0] == board[1][1] == board [2][2] == whoseturn:
return True
if x + y == 2 and board[0][2] == board[1][1] == board [2][0] == whoseturn:
return True
return False
def isfull(board):
for i in range(0,3):
for j in range(0,3):
if board[i][j]=='e':
return False
return True
def main():
board = [['e','e','e']
,['e','e','e']
,['e','e','e']]
print("Welcome to the great tic tac toe game!")
player1=input("Player 1, select your symbol (X/O): ")
if player1 =='O':
print('X is player 2s symbol')
player2 = 'X'
else:
print('O is player 2s symbol')
player2 = 'O'
print("Player 1 will start")
whoseturn=player1
while True:
display_board(board)
rowloc, coloc = get_move(whoseturn, board)
if win(board,whoseturn, rowloc, coloc):
print(f'{whoseturn} wins!')
display_board(board)
break
if isfull(board):
print('Tied')
break
if whoseturn=='O':
whoseturn='X'
else:
whoseturn='O'
if __name__ == '__main__':
main()
and a start of the future boards function
code:
def futuremove(board,whoseturn):
newboard=copy.deepcopy(board)
place = []
copyboard = []
arrangement=[]
final=[]
for i in range(3):
for j in range(3):
if newboard[i][j]=='e':
newboard[i][j]=whoseturn
if win(newboard,whoseturn,i,j)==True:
loctup=[i,j]
place.append(loctup)
copyboard.append(newboard)
arrangement.append(place)
arrangement.append(copyboard)
final.append(arrangement)
print(final)
else:
break
please help me get a working player vs. computer tic-tac-toe game!
any help will be very much appreciated!
There are a lot of different ways you can approach it, one fairly simple approach you might take would be to utilize the Minimax Algorithm
In a simple example, where your program looks only one turn ahead, after the play makes a move, your AI would generate a board for every possible move it could make, and from those moves, every possible counter move that the player could make.
Now you want to assign a score to each of the AI's possible moves, how you want to define the scoring algorithm is up to you, but it should represent how good or bad a particular game state is for your AI.
The score of each of the AI's potential moves should be equal to the worst score of all the player's counter moves, because we want to assume that the player will act in their best interest.
As such you'll be able to determine which of the AI's potential moves puts it in the best chance of winning the game from the current state. I highly recommend reading the attached article for implementation details and a deeper understanding.

My function is too long and I'm told to optimize

So I'm doing a project for an online class and when i got it scored it came back as not passed because my "play game" function was more than 18 lines long and I'm supposed to optimize it. The problem is they didn't make any suggestions as to what i should do and I keep looking at it and feel as if I need everything in it to make the fill in the blank quiz I'm building work. Any suggestions would be great as I am still very new to coding, and maybe what they are asking me to do is easy and I'm over complicating it in my head. This is the part of the code they want optimized...
def play():
'''
This is the main function which allows to play the game/quiz.
It calls the previous functions we have written.
'''
quiz = difficulty_level(user_level) #gives the difficulty
paragraph that the user asks for.
print quiz
print "\nYou will get maximum 3 guesses for each blank. Good luck.\n"
answers_list = relate_answer(user_level) #makes sure that the right
list is called up
blanks_index = 0
answers_index = 0
number_of_guesses = 3
while blanks_index < len(blanks): #This loop keeps going if all the
blanks are not replaced.
user_answer = raw_input("type in your answer for " + blanks[blanks_index] + ": ")
if check_answer(user_answer,answers_list,answers_index) == "Correct":
print "Awesome job! You gave the right answer!\n"
quiz = quiz. replace(blanks[blanks_index],user_answer)
blanks_index += 1
answers_index += 1
number_of_guesses = 3
print quiz
else:
number_of_guesses -= 1
if number_of_guesses == 0:
print "Game over! But try again!"
break
elif number_of_guesses < 0:
print "invalid"
break
else:
print "please try again."
print "You have " + str(number_of_guesses) + " guesses left."
print "Congratulations! You really know your stuff!."
play()
A quick summation of changes:
It looks like answers_index and blanks_index share the same state, no matter what, so we can generalize that to one variable idx. That cuts down on the number of variables you have to keep track of.
As others have suggested, initializing variables as a tuple like var1, var2 = 1, 2 decreases length and makes code more readable (to a point). If you have lots of variables to initialize, you can break the initialization into groups of related variables.
Setting a default value to user_level increases readability, and also gives an easy place to start debugging your function. This occurs in the def statement, so if you don't pass the argument, user_level will be 1, otherwise it will be whatever you give it in the function call. Example play(user_level=40) will overwrite that default value.
Putting the game loss condition at the start of the while loop increases visibility of the checks the code goes through before executing anything unnecessary. This should help you avoid the case where guess would be less than 0, because that code won't execute when guess==0 is True.
Setting a lose boolean with the check after exiting the while loop will also prevent the wrong print statement at the end from executing. That way, if the player loses, you will print the proper message.
Breaking the update of quiz into another function adds a more compact breakpoint into the code. In general, smaller functions that do less are preferable to large functions that do a lot. The smallest number of changes necessary is a good standard for what should be wrapped into a function, though this could be considered a stylistic convention more than a hard and fast rule.
The correct_answer method allows you to update quiz and guess in one line, and if something is wrong with the update itself, you don't have to run the entire script over and over. Instead you can take the quiz that might be causing the problem and plug it into that function until you find what's causing the problem.
I've made some minimal updates to the function you've provided which keep most of your conventions so far. Hopefully this is helpful, and happy coding!
def correct_answer(quiz, blank, answer):
"""
Function to update the quiz and return
both the quiz and reset guess to 3
"""
print("Awesome job! You gave the right answer!\n")
quiz = quiz.replace(blank, answer)
return quiz, 3
def play(user_level=1):
'''
This is the main function which allows to play the game/quiz.
It calls the previous functions we have written.
'''
idx, guess, lose = 0, 3, False
quiz = difficulty_level(user_level) #gives the difficulty paragraph that the user asks for.
print(quiz)
print("\nYou will get maximum 3 guesses for each blank. Good luck.\n")
answers_list = relate_answer(user_level) #makes sure that the right list is called up
while idx < len(blanks): #This loop keeps going if all the blanks are not replaced.
if guess <= 0:
lose = True
break
user_answer = raw_input("type in your answer for %s:" %str(blanks[idx]))
if check_answer(user_answer,answers_list,idx) == "Correct":
quiz, guess = correct_answer(quiz, blanks[idx], user_answer)
print(quiz)
else:
guess -= 1
print("please try again.\nYou have %s guesses left.\n"%str(guess))
idx += 1
if lose:
print("Game over, try again")
else:
print("Congratulations! You really know your stuff!.")
play(user_level = 3)

How to create a loop for multiple players turn?

Im trying to get this loop to work, but it just refuses to work. Any help would be very much appreciated.
while player1_score < 100 and player2_score < 100 and player3_score < 100 and player4_score < 100:
while player_turn != playerholder:
dice_rolling()
scoring()
score_awarding()
player_turn = player_turn + 1
if player_turn == playerholder:
player_turn == 1
What im trying to do is get the number of players present (playerholder) and then keep player turn within the bounds of it i.e repeating till someone gains a score of 100 or more.
Just ask if you need any more code :)
Thanks in advance.
EDIT: Everyone seems to be confused as to what I'm asking so I'm going to try explain it more elaborately.
So the game has from 2 to 4 players, and what they are trying to do is get a score of 100 or more. Since there are multiple players, I want to try and have a repeating structure to efficiently use the functions I have created over and over. With the current code, it will score Players like it should up until the last player, where the code stops completely and nothing is presented. What I would like to do is get the code to repeat infinitely until the required score is gained, as in it will keep cycling through the players with no errors. I have tried multiple times with different loops but I cannot get it to work. Hopefully this is a little bit clearer to everyone. Sorry about the unorganized/unclear question, relatively new to StackOverflow.
EDIT: Problem has been solved
As an aside, you should be keeping your players in some sort of list and iterating through them, allowing them each to take a turn in their iteration. Something like:
players = [player1,player2,player3,player4]
for player in players:
if player.score >= 100: win(player)
dice_rolling()
player.score += scoring()
But of course this only works if you have some sort of class Player in your code (which you should).
class Player(object):
def __init__(self,name):
self.name = name
self.score = 0
# what else does a Player do?
In fact you can probably make a Game class as well!
class Game(object):
def __init__(self,players):
self.players = players # a list of players
self.running = False
def dice_rolling(self):
diceroll = sum(random.randint(1,6) for _ in range(2))
def scoring(self):
return score # I don't know how you're doing this so...
def win(self,player):
print("{} wins!".format(player.name))
def run(self):
self.running = True
while self.running:
for player in self.players:
roll = dice_rolling()
player.score += scoring()
if player.score >= 100:
self.running = False
win(player)
Game().run()
Your code probably doesn't work as intended because instead
of assigning 1 to the player_turn you do this:
player_turn == 1
when it should be this:
player_turn = 1
You could try something using a list structure.
It would look like this if there were 4 players:
turns = [0,1,2,3,4,0,1,2,3,4]
#this would add another turn for player 0, to remove you just use del
turns.append(0)
#This would remove a winner from your turn stack while preserving the order
for i in turns:
if i ==4:
del i
#You could also use a dictionary if you don't like list indicies or numbers:
Players = {"blue":3, red":4, "green":2, "orange":1}
turn = [4,2,1,3,4,2,1,3]
#If there is also a maximum number of turns, you can have that hard coded also:
for i in range(max):
turn.append(1)
turn.append(2)
turn.append(3)
turn.append(4)
Truthfully, I don't really understand what your question but hopefully this may have answered it wholly or in part.

Categories