Correct approach to solve turn based puzzles - python

I am simulating a game in python. It involves two players, each has a set of turns. Based on a hit or a miss, we decide if that player will get another turn.
I not able to craft this logic programmatically, here is what I have so far:
Let's simulate each player separately for the sake of simplicity
for coordinate in list_of_player1_moves:
result = fire(coordinate[0], coordinate[1])
#result is either a 'Hit' or a 'Miss'
for coordinate in list_of_player2_moves:
result = fire(coordinate[0], coordinate[1])
#result is either a 'Hit' or a 'Miss'
Now, in order to have individual turns for each player, I did:
turns = len(list_of_player2_moves) if len(list_of_player2_moves) > len(list_of_player1_moves) else len(list_of_player1_moves)
for turn in range(0, turns):
r = move_player1(turn) #move player inturn calls fire()
if(r == 'Hit'):
break #start over, giving them another turn
r = move_player2(turn)
if r == 'Hit':
#how do give player 2 another turn?
I am out of ideas on how to approach this further. Please suggest. Also please advice on alternative/better approaches.
Thanks!
Edit:
Sample Output for better understanding,
Player1 fires got miss
Player2 fires which got hit
Player2 fires which got miss
Player1 fires which got hit
Player1 fires which got hit
Player1 fires which got miss
Player2 fires which got miss
Player1 has no more missiles left to launch
Player2 fires which got hit
Player2 fires which got miss
Player1 has no more missiles left to launch
Player2 fires which got miss
Player1 has no more missiles left to launch
Player2 fires which got hit
Player2 fires which got miss
Player1 no more missiles left to launch
Player2 fires which got hit
Player2 won the battle

Your problem description is a bit ambiguous, so I am assuming that
Every time a player hits another player, he gets 1 more move
The game doesn't terminate until both of the players run out of moves
Thus I rewrote the function
counter = 0
no_of_player1_moves = len(list_of_player1_moves)
no_of_player2_moves = len(list_of_player2_moves)
while counter < no_of_player1_moves or counter < no_of_player2_moves:
# won't terminate until both players run out of turns
r = move_player1(turn)
if(r == 'Hit'):
no_of_player1_moves += 1 #if player1 hits, player1 gets 1 more turn
r = move_player2(turn)
if(r == 'Hit'):
no_of_player2_moves += 1 #if player2 hits, player2 gets 1 more turn
counter += 1
P.S:
Instead of your long statement
turns = len(list_of_player2_moves) if len(list_of_player2_moves) > len(list_of_player1_moves) else len(list_of_player1_moves)
You can simply use
turns = max(len(list_of_player2_moves),len(list_of_player1_moves))
Edit:
no_of_player1_moves = len(list_of_player1_moves)
no_of_player2_moves = len(list_of_player2_moves)
while no_of_player1_moves>0 or no_of_player2_moves>0:
# won't terminate until both players run out of turns
while move_player1(turn)=="Hit" and no_of_player1_moves!=0:
no_of_player1_moves -= 1
while move_player2(turn)=="Hit" and no_of_player2_moves!=0:
no_of_player2_moves -= 1
This would probably solve your problem, but the design doesn't scale well (imagine if you have 10 players, you wouldn't want to write it 10 times).
For that, I would suggest creating a Player object, and placing them in a list, then keep cycling through the list (nested while loop) until all players run out of moves. There is probably a better solution out there too (even compared to this), but that would at least be scalable.

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..

Checking winner TIC TAC TOE

I guess this must be some simple fix, but I am still becoming familiar with coding, so every once in a while I get stuck in some silly things (will catch up, eventually lol)
I have been trying to stop my Tic Tac Toe game once a winning condition is met (horizontal, vertical or diagonal), and I successfully have the message of the winner printed on the screen once one of conditions is met.
The thing is that after showing the message, I still can't stop the game. I would like to know what's the problem with my interruption.
This is the code I am using for the function that sets the symbols and that identifies the winner:
def player_char():
marker = ''
player1 = ''
player2 = ''
# Keep asking Player 1 to choose X or O, until entry is correct:
while marker != ('x').lower() and marker != ('o').lower():
marker = input("\n PLAYER 1 - CHOOSE X OR O : ")
# Assign opposite marker to Player 2
player1 = marker.upper()
if player1 == 'X':
player2 = 'O'
else:
player2 = 'X'
print (f"\n P1 playing with: {player1}" + f"\n P2 playing with: {player2}")
markers = [player1, player2]
return markers
def check_victory(board, markers):
player1_win = False
player2_win = False
draw = False
# Check if players win the game in one of the lines, columns or diagonals available
for n in range(len(markers)):
if board[7] == board[8] == board[9] == markers[n]:
if n == 0:
player1_win = True
else:
player2_win = True
break
(I HAVE IMPLEMENTED ALL THE OTHER LINES AND COLUMNS THAT COULD BE A WIN. DID NOT PASTE THEM HERE TO MAKE QUESTION SHORTER, BUT THEY ALL FOLLOW THE LOGIC ABOVE)
I call the function while players are placing their markers and once one winning condition is met, I have the message printed:
if player1_win:
print("\n >>> GAME FINISHED! PLAYER 1 WINS!")
if player2_win:
print("\n >>> GAME FINISHED! PLAYER 2 WINS!")
But then the game is not interrupted (I was guessing it would be, due to my "break" after each condition). What could be going on within my IF ? As I said, guessing it must be pretty simple, but got stuck for now.
So this is my function that executes the game.
"display_board" was implemented to print the board, so I didn't add it here, because I am simply calling it and printing the board, it doesn't return anything else. "free" is a parameter to print a second board next to the actual game board, showing available slots for a play
def play_game(board, markers, winner):
moves = 1
while winner[0] or winner[1] or winner[2] != True:
if moves % 2 == 1:
display_board(game_board, free)
print(game_board)
p1 = (input("\n >>> ( P1 ) Enter number for your move: "))
board[position_p1] = markers[0]
moves += 1
check_victory(board, markers)
(Next play follows same format for player 2, when "moves" is a pair number. I can verify if player 2 wins, but obviously game does not stop too)
break in the inner if condition will just break out of that if condition.
Instead, you can have one more condition at the end which will check if any of the following condition is True, then break out of the for loop.
player1_win = True or player2_win = True or draw = True

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.

I want to know why my program is not stopping in my while loop

Hy guys i have the following problem - Write a program to play the following simple game. The player starts with $100. On each
turn a coin is flipped and the player has to guess heads or tails. The player wins $9 for each
correct guess and loses $10 for each incorrect guess. The game ends either when the player
runs out of money or gets to $200.
My program is actually running. However when players points go bellow zero my program still runs and that is not what i expected. I need to know if there is something that i can do in my if sentences or if there is an easier way to make statements when i have to much conditions.
import random
list=['heads','tails']
def game():
p1=100
p2=100
while (p1>0 or p2>0)and(p1<200 or p2<200):
x=random.choice(list)
x1=input('digit your guess player1 - ')
x2=input('digit your guess player2 - ')
if x1==x:
p1+=30
else:
p1=p1-40
if x2==x:
p2+=30
else:
p2=p2-40
return p1,p2
print(game())
I expect the program to return the scores and end if any player points goes above 200 or bellow 0
If I consider your original problem, the problem is that you are returning whatever current value the player has, instead you should remember the last score and if the condition you want the game to stop on happens, return the last score. This will ensure only valid scores are returned
import random
list=['heads','tails']
def game():
player=100
last_score = 0
#Conditions to break while loop
while player > 0 and player < 200:
#Keep track of last score
last_score = player
#Get choice from player, and increase/decrease score
x=random.choice(list)
x1=input('digit your guess player1 - ')
if x1 == x:
player += 9
else:
player -= 10
#Return last score
return last_score
print(game())
Extending this idea to the 2 player game will solve your issue as well!
import random
list=['heads','tails']
def game():
p1=100
p2=100
last_scores = 0,0
# Conditions to break while loop
while (0<p1<200) and(0<p2<200):
# Keep track of last score
last_scores = p1,p2
# Get choice from player, and increase/decrease score
x=random.choice(list)
x1=input('digit your guess player1 - ')
x2=input('digit your guess player2 - ')
if x1==x:
p1+=30
else:
p1=p1-40
if x2==x:
p2+=30
else:
p2=p2-40
return last_scores
print(game())
Change the while condition to:
while p1>0 and p2>0 and p1<200 and p2<200
but it is more readable if:
while 0<p1<200 and 0<p2<200

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