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.
Related
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..
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
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
I am trying to get the game to take an input for how many ships the user would like, and to place that many ships. I have put the coordinates into a list and that is how I am storing them, and checking if it is a hit. But the ships get placed over each other, and with this list method, I don't know how to first of all, check they are not overlapping, and second of all, change it so they aren't.
from random import randint
print('Welcome to Battleships for 1 player! Please be careful with entries, as if you get it wrong, you will still lose a go!')
print('Good luck!')
print('')
no_of_goes = int(input("How many goes would you like: "))
size_of_board = int(input("And how big would you like the board to be: "))
if size_of_board > 56:
print("That board will be too big to fit on the screen (max 56)")
size_of_board = int(input("And choose a more sensible number: "))
no_of_ships = int(input("And finally, how many ships would you like?: "))
board = []
# printing out the board
for x in range(size_of_board):
board.append(["O"] * size_of_board)
def print_board(board):
for row in board:
print (" ".join(row))
print_board(board)
# the lists that will become the locations
ship_rows = []
ship_cols = []
# generating random locations
def random_row(board):
return randint(0, len(board) - 1)
def random_col(board):
return randint(0, len(board) - 1)
# adding locations to lists
ships = list(range(no_of_ships))
for i in ships:
row = random_row(board)
col = random_col(board)
ship_rows.append(row)
ship_cols.append(col)
##
## And this is my attempt (didn't work)
##
for row in ship_cols:
if row == ship_cols and col == ship_cols:
ship_rows[-1] = random_row(board)
ship_cols[-1] = random_col(board)
# allowing to see where ships are and logging how many ships have been hit
print(ship_rows)
print(ship_cols)
ship_count = [1]
## I couldn't find a way of ending the game once the ships were sunk, so I stuck in a recursive function (sorry)
def printing_stars():
print('You have won!! ' +'*' * 56)
printing_stars()
for turn in range(no_of_goes):
# asking for their guesses
print('Turn ' + str(turn + 1) + ' out of ' + str(no_of_goes))
guess_col = int(input("Guess Col:")) - 1
guess_row = int(input("Guess Row:")) - 1
for item in ship_rows:
# If they hit, it gives a '!'
if len(ship_count) == no_of_ships and guess_row == item and guess_col == ship_cols[ship_rows.index(item)]:
print("You have won!!!! Congratulations")
board [guess_row][guess_col] = '!'
print_board(board)
printing_stars()
elif guess_row == item and guess_col == ship_cols[ship_rows.index(item)]:
print ("Congratulations! You sunk one of my battleships")
board [guess_row][guess_col] = '!'
print_board(board)
ship_count.append(1)
break
else:
# all misses
if (guess_row < 0 or guess_row > size_of_board - 1) or (guess_col < 0 or guess_col > size_of_board - 1):
print ("Oops, that's not even in the ocean.")
elif board[guess_row][guess_col] == "X" or board[guess_row][guess_col] == "!":
print ("You guessed that one already.")
turn -= 1
else:
print ("You missed my battleship!")
board[guess_row][guess_col] = "X"
print_board(board)
if turn == (no_of_goes - 1):
print('Game Over')
break
Any ideas? Would be very grateful :)
Some suggestion for your code :
You could model the player board with a numpy array like this :
Size : i lines and j colums => (i, j)
0 if water
1 if water that was shot by the palyer
2 if ship unharm
3 if ship case is hit
Once they are no more 2, it means there is a winner.
With this system, you can tell a player if he is shooting twice the same spot and you could also generate a display.
Moreover, to randomly position the ship, you could use this procedure :
Set ship size : let's say 4 spots.
Choose randomly 0 or 1 : 0 to place the ship horizontaly, and 1 to place the ship verticaly
Now we have to look if it is placed horizontaly or verticaly.
If it's horizontaly placed :
Choose 2 random number between 0 and j-4 and 0 and i. That will be your ship first spot coordinate, it means, this spot turn to 2, and the 3 spot on after it also.
Example with a 5*5 board, and a position pick of (1,0) for an horizontal ship
00000
22220
00000
00000
00000
I let you take care of the case verticaly, just have to change the random number generation indices.
Then that solution doesn't prevent from getting a ship on an other one. One simple solution, is with this loop :
while True:
if all ship placed:
break
pick number
Try to place the ship. (with an if statement, check if one of the spot your gonna change is already a 2.)
That solution should work as long as it is possible to place all the ship on the board. If it's impossible, you'll the loop won't end. Moreover if the number of ship is not limited in regard of the board size, it could be long to place them.
You can then keep improving the method with more complicated scenario. One other solution would be to check after each ship positioning where you still have place to put one.
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)))