I need some help with my tic-tac-toe game that I created in Python 3. Have a look at my fun program and try it out. After that, please help me creating a while statement in my program. That is while the user choice of square if filled, you should continue to ask them until they choose an empty square. When the choose an empty square, the program continues as before. I am not used to the while statements, please help me on this!
Here is my program:
from turtle import *
def setUp():
#Set up the screen and turtle
win = Screen()
tic = Turtle()
tic.speed(10)
#Change the coordinates to make it easier to tranlate moves to screen coordinates:
win.setworldcoordinates(-0.5,-0.5,3.5, 3.5)
#Draw the vertical bars of the game board:
for i in range(1,3):
tic.up()
tic.goto(0,i)
tic.down()
tic.forward(3)
#Draw the horizontal bars of the game board:
tic.left(90) #Point the turtle in the right direction before drawing
for i in range(1,3):
tic.up()
tic.goto(i,0)
tic.down()
tic.forward(3)
tic.up() #Don't need to draw any more lines, so, keep pen up
#Set up board:
board = [["","",""],["","",""],["","",""]]
return(win,tic,board)
def playGame(tic,board):
#Ask the user for the first 8 moves, alternating between the players X and O:
for i in range(4):
x,y = eval(input("Enter x, y coordinates for X's move: "))
tic.goto(x+.25,y+.25)
tic.write("X",font=('Arial', 90, 'normal'))
board[x][y] = "X"
x,y = eval(input("Enter x, y coordinates for O's move: "))
tic.goto(x+.25,y+.25)
tic.write("O",font=('Arial', 90, 'normal'))
board[x][y] = "O"
# The ninth move:
x,y = eval(input("Enter x, y coordinates for X's move: "))
tic.goto(x+.25,y+.25)
tic.write("X",font=('Arial', 90, 'normal'))
board[x][y] = "X"
def checkWinner(board):
for x in range(3):
if board[x][0] != "" and (board[x][0] == board[x][1] == board[x][2]):
return(board[x][0]) #we have a non-empty row that's identical
for y in range(3):
if board[0][y] != "" and (board[0][y] == board[1][y] == board[2][y]):
return(board[0][y]) #we have a non-empty column that's identical
if board[0][0] != "" and (board[0][0] == board[1][1] == board[2][2]):
return(board[0][0])
if board[2][0] != "" and (board[2][0] == board[1][1] == board[2][0]):
return(board[2][0])
return("No winner")
def cleanUp(tic,win):
#Display an ending message:
tic.goto(-0.25,-0.25)
tic.write("Thank you for playing!",font=('Arial', 20, 'normal'))
win.exitonclick()#Closes the graphics window when mouse is clicked
def main():
win,tic,board = setUp() #Set up the window and game board
playGame(tic,board) #Ask the user for the moves and display
print("\nThe winner is", checkWinner(board)) #Check for winner
cleanUp(tic,win) #Display end message and close window
main()
You're probably looking for something like this:
x,y = None,None
while x == None or y == None or board[x][y] != "";
x,y = eval(input("Enter x, y coordinates for X's move: "))
This will keep asking the user for input as long as x and y do not indicate an empty tile on the board.
By the way, you might consider changing the way you process the input. Right now you are using eval, which can be dangerous as any input can be executed. It might be better to process the input manually, something like this:
x,y = map(int,input("Enter coordinates").split(','))
This splits the input at the comma, turning it into a list of strings. map then applies the function int to each element in the list, turning them into integers. These are then unpacked into x and y.
for i in range(4):
while True:
move = input("Enter x, y coordinates for X's move: ")
x,y = int(move[0]), int(move[-1]) # don't use eval()
if board[x][y] not in ('X', 'O') # if valid
tic.goto(x+.25,y+.25)
tic.write("X",font=('Arial', 90, 'normal'))
board[x][y] = "X"
break # break out of loop after doing stuff
You might want to use a validation function taking the whole input string and parse it in the validation function, like the code below:
def isUserInputValid (s):
cordinate=s.split(',')
...... # Your validation logic goes here
while not isUserInputValid(input("Please put your cell cordinate x, y:")):
print("Your choice is not valid!")
Related
I'm having a slight issue figuring out how to replace the dashed list on my hangman game. What I want it to do is replace itself into the word the player guesses, like in the actual hangman. In addition, my program is not able to draw the head or body of the hangman. Could you guys help me out? Thanks.
I tried using .replace but I'm either too incompetent or have no idea how to use it despite going through other sources. Ditto with the turtle drawing.
Here is the code if it helps out.
import random
import os
import turtle as t
#declare variables
alphaList = list("abcdefghijklmnopqrstuvwxyz")
wordlist = ['penguin', 'pengalin', 'ability', 'absense', 'academy', 'swordman']
chosenList = []
dashedList = []
Newlist = list (random.choice (wordlist))
# make the cls() method
def cls():
os.system('cls' if os.name=='nt' else 'clear')
# call the cls method
def circle(x, y, rad, col):
t.color ("black", col)
t.goto (x,y)
t.pendown ()
t.begin_fill ()
t.circle (rad)
t.end_fill ()
t.penup ()
def rectangle(x, y, hor, vert, col):
t.color ("black", col)
t.goto (x,y)
t.pendown ()
t.begin_fill ()
#trace out rectangle
for x in range (2):
t.forward (hor)
t.right (90)
t.forward (vert)
t.right (90)
t.end_fill ()
t.penup ()
def setup():
#randomly choose word and make a list
Newlist = list (random.choice (wordlist))
for i in range (0, len(Newlist)):
dashedList.append ("_")
def display ():
print ("Available letters: ")
print ("".join (alphaList))
print ()
print ("Mystery Word: ")
print (dashedList)
#main logic
def hangman():
points = 6
guessed_letters = []
print(Newlist, "ChosenList")
while points > 0:
print(guessed_letters)
userguess = input("Tell me a letter: ").lower()
if points < 6:
return circle
if points < 5:
return rectangle
if len(userguess) != 1:
print("Try using only 1 letter next time.")
if userguess in guessed_letters:
print("You have already chosen", userguess, ",friend.")
elif userguess in Newlist:
print("You got a correct letter!")
guessed_letters.append(userguess)
else:
guessed_letters.append(userguess)
print("Uh oh ",userguess, " not in the word")
points -= 1
print(points, "Tries left. ")
#main logic
setup ()
display ()
hangman()
circle(x, y, rad, col)
rectangle(x, y, hor, vert, col)
I'm new to python and writing my first project. I'm trying to implement a check that if a space is already occupied, not to move there. I can't seem to figure out why my move_player method overwrites the index value of the board even though I am explicitly checking it (If it is O's turn and X has already been placed in the index O is trying to move to, it just overwrites it). I have tried hard coding the check for 'X' and 'O' instead of player.player as well but can't seem to figure it out. Does it have to do something with how Python works or am I implementing it wrong?
class Player:
def __init__(self, player):
self.player = player
class Board:
def __init__(self):
self.board = [[' ' for i in range(3)] for j in range(3)]
def display_board(self):
print('---------')
for row in self.board:
print('| ', end='')
for col in row:
print(f'{col} ', end='')
print('|')
print('---------')
def move_player(self, player):
try:
p1 = Player('X')
p2 = Player('O')
coordinates = [int(i) for i in input("Enter coordinates for move: ").split()]
xCoordinate = coordinates[0]
yCoordinate = coordinates[1]
if ((self.board[xCoordinate][yCoordinate] == p1.player) or
(self.board[xCoordinate][yCoordinate] == p2.player)):
print("That space is occupied, please choose another one.")
self.move_player(player)
else:
self.board[xCoordinate - 1][yCoordinate - 1] = player.player
except (ValueError, IndexError):
print("Please only enter numbers between 1 and 3.")
self.move_player(player)
def has_won(self, player):
if self.check_diagonal(player):
return True
elif self.check_across(player):
return True
elif self.check_down(player):
return True
return False
if __name__ == '__main__':
board = Board()
player1 = Player('X')
player2 = Player('O')
player = player1
while True:
board.display_board()
board.move_player(player)
if board.has_won(player):
board.display_board()
print(f'{player.player} wins!!!')
break
if player == player1:
player = player2
else:
player = player1
The code is very convoluted but from what I can see:
if ((self.board[xCoordinate][yCoordinate] == p1.player) or
(self.board[xCoordinate][yCoordinate] == p2.player)):
...
self.board[xCoordinate - 1][yCoordinate - 1] = player.player
You are checking [x,y] but assigning to [x-1,y-1].
Python beginner here--working on a Battleship project for a class. My program will loop through the first player to place their ships. The grid does successfully print the visual ships on the board, but once i get to player two, the ships are overlapping with player one. (also note there is some validation work that still needs to be done).
I think the issue is that maybe I'm storing both coordinates for each player in the same list. So my question is how do I store the values for each player so that I can get the board to print ships only applicable to each player?
Here are my classes:
BOARD_SIZE = 10
class Ship:
def __init__(self, ship_name, size, coords, player, direction):
self.ship_name = ship_name
self.size = size
self.player = player
self.coords = coords
self.direction = direction
class Board:
def __init__(self):
self.board = []
self.guesses = []
board = [['O']*BOARD_SIZE for _ in range(BOARD_SIZE)]
def add_ship(self, name, size, player, coords, direction):
for coord in coords:
# convert string like "a1" to x,y coordinates
y = ord(coord[0])-ord('a')
x = int(coord[1:])-1
# update the board at this position
self.board = board[x][y]
print(" " + " ".join([chr(c) for c in range(ord('A'), ord('A') + BOARD_SIZE)]))
row_num = 1
for row in board:
print(str(row_num).rjust(2) + " " + (" ".join(row)))
row_num += 1
self.board.append(Ship(coords,player,name,size,direction))
def print_board_heading(self):
print(" " + " ".join([chr(c) for c in range(ord('A'), ord('A') + BOARD_SIZE)]))
def print_board(self):
board = [['O']*BOARD_SIZE for _ in range(BOARD_SIZE)]
print_board_heading()
row_num = 1
for row in board:
print(str(row_num).rjust(2) + " " + (" ".join(row)))
row_num += 1
def print_updated_board(coords, direction, board, player):
for coord in coords:
# convert string like "a1" to x,y coordinates
y = ord(coord[0])-ord('a')
x = int(coord[1:])-1
# update the board at this position
board[x][y] = '|' if direction == 'v' else '-'
print(" " + " ".join([chr(c) for c in range(ord('A'), ord('A') + BOARD_SIZE)]))
row_num = 1
for row in board:
print(str(row_num).rjust(2) + " " + (" ".join(row)))
row_num += 1
class Player():
def __init__(self,name):
self.name = name
self.board = Board()
self.ships = []
self.guesses = []
And the battleship game file:
from ship import Ship, Player, Board
SHIP_INFO = [
("Aircraft Carrier", 5),
("Battleship", 4),
("Submarine", 3),
("Cruiser", 3),
("Patrol Boat", 2)
]
BOARD_SIZE = 10
VERTICAL_SHIP = '|'
HORIZONTAL_SHIP = '-'
EMPTY = 'O'
MISS = '.'
HIT = '*'
SUNK = '#'
board = [['O']*BOARD_SIZE for _ in range(BOARD_SIZE)]
def print_board_heading():
print(" " + " ".join([chr(c) for c in range(ord('A'), ord('A') + BOARD_SIZE)]))
def print_board():
board = [['O']*BOARD_SIZE for _ in range(BOARD_SIZE)]
print_board_heading()
row_num = 1
for row in board:
print(str(row_num).rjust(2) + " " + (" ".join(row)))
row_num += 1
def print_updated_board(coords, direction,board):
# create an empty board
# board = [['O']*BOARD_SIZE for _ in range(BOARD_SIZE)]
# at each coordinate, draw a ship
for coord in coords:
# convert string like "a1" to x,y coordinates
y = ord(coord[0])-ord('a')
x = int(coord[1:])-1
# update the board at this position
board[x][y] = '|' if direction == 'v' else '-'
print_board_heading()
row_num = 1
for row in board:
print(str(row_num).rjust(2) + " " + (" ".join(row)))
row_num += 1
def clear_screen():
print("\033c", end="")
def get_coordinates(ship):
while True:
print("\n")
coordinate = input("Where do you want the " + ship + "(example: A1)?: ")
coords_strip = coordinate.strip()
coords_lower = coords_strip.lower()
x = coords_lower[0]
y = coords_lower[1:]
if (len(x)+len(y)) in range(2,4):
if x not in 'abcdefghij' or y not in '1,2,3,4,5,6,7,8,9,10':
print("Oops! That was not a valid entry. Try again...")
continue
else:
return x, y
else:
if len(coords_lower) < 2 or len(coords_lower) > 3:
print("Oops! That's too not the right amount of characters. Please try again...")
continue
def get_direction():
while True:
dir = input("[H]orizontal or [V]ertical?: ")
dir_strip = dir.strip()
direction = dir_strip.lower()
if direction not in 'hv':
print("Oops! That was not a valid entry. Try again...")
continue
else:
return direction
def create_ship_coordinates(x, y, size, direction):
ship_col = ord(x)
ship_row = int(y)
if direction == 'v':
# ship runs vertically DOWN from coordinate
coords = [chr(ship_col) + str(r) for r in range(ship_row, ship_row + size)]
return coords
else:
# ship runs horizontally RIGHT from coordinate
coords = [chr(col) + str(ship_row) for col in range(ship_col, ship_col + size)]
return coords
def place_user_ships(player):
ships = []
print_board()
print("\n")
print("Let's go " + player + " !")
for ship, size in SHIP_INFO:
while True:
# ask for starting coordinate
x, y = get_coordinates(ship)
# ask for vertical or horizontal direction
direction = get_direction()
# create the coordinates for the ship placement
coords = create_ship_coordinates(x, y, size, direction)
# validate the
# new_ship = Board().add_ship(ship, size, coords, direction, player)
# update = Board.print_updated_board(coords,direction,board,player)
break
# create ship from data
# add the ship from above to a player list
# player = Player(board)
# place the ship on the game board
# print out the board to reflect the shp placement
clear_screen()
print("\n")
input("All ships placed for {}. Please hit ENTER to continue....".format(player))
player1 = input("What's Player 1's Name? ")
player2 = input("What's Player 2's Name? ")
# define player one's fleet
place_user_ships(player1)
place_user_ships(player2)
IIRC, in battleship there are really four boards. One is managed by each player with their shots at the enemy, and the other is the player's own ships and incoming shots from the enemy.
The "shot" process is one of notifying the enemy where the shot was taken, the enemy responding with "hit" or "miss", and recording the result on the local player's outgoing-shots board.
The "notification" process is one of receiving a location where an enemy shot was made, looking up the result on the local-ships board, returning "hit" or "miss", and updating the local ships board to indicate the enemy shot.
So you have a Player, with a pair of Boards. You might also have a Game class to marry the two players.
Inputting the ships is going to depend a lot on your actual user interface. Are you doing graphics with a mouse? Are you doing text with a mouse? Text with arrow keys via curses or some such? Simple coordinate inputs?
If you're doing coordinates, you probably want something simple, like x,y,{up,down,left,right} to eliminate having to position every block of the ship.
Again, there is a Board method here - placing a ship. The board can enforce whatever rules you have about placement (ex: can two ships be directly adjacent? Or must there be a one-space gap between?) and reject the inappropriate attempts.
If you put all the wisdom in your Board class, then the Player classes can be simple, with just links to the boards. And the game can manage the players in turn:
def play(self):
p1 = self.player[0]
p2 = self.player[1]
try:
while True:
self.attack(p1, p2)
self.attack(p2, p1)
except Victory v:
print("The winner is", v.player.name)
I notice you doing things like player1 = input("What is player 1's name?"). This is something that should be pushed into the player classes.
Try to design from the top down: game, player, board. And try following the rule, "Tell, don't ask." That is, if something needs to be done, you tell a class to do it, instead of asking the class for data and doing it yourself.
Instead of this:
move = player1.get_move()
if valid_move(move):
...
Do this:
player1.make_move()
And push the logic downwards. Eventually, you get to the place where the knowledge "should be". The player "should" make moves. The board "should" know what is a valid move or not. And every method "should" be given enough data to do its job. ;-)
So, first of all, here's the requirements:
user picks 3 shapes from a list of 6;
user chooses size, fill color, and line color;
user cannot pick the same shape twice
shapes should be drawn evenly spaced, taking up 1/3 of the screen each
Here's my code so far:
import turtle
turtle = turtle.Screen()
def circle():
def triangle():
def square():
def pentagon():
def hexagon():
def heptagon():
for list in ["1.Circle","2.Triangle","3.Square","4.Pentagon","5.Hexagon","6.Heptagon"]:
print(list)
shape1 = input("Choose one number from the following:")
if shape1 == "1":
for list in ["2.Triangle","3.Square","4.Pentagon","5.Hexagon","6.Heptagon"]:
print(list)
shape2 = input("Choose one number from the following:")
if shape2 == "2":
elif shape2 == "3":
elif shape2 == "4":
elif shape2 == "5":
elif shape2 == "6":
else:
print("Incorrect input. Please try again.")
if shape1 == "2":
if shape1 == "3":
if shape1 == "4":
if shape1 == "5":
if shape1 == "6":
else:
print("Incorrect input. Please try again.")
Basically, I'm terribly confused. The only way I can find to draw three shapes in a row of the user's choosing is to do every possible outcome - 123, 124, 125, 126, 132, 134...etc etc, which would take forever, look horrible, and then I would have to write the turtle commands each time. As you can see, I tried playing around with def, but in my smaller test code it didn't work at all, so I'm not sure I understand it correctly either.
In addition to all of that, how would I ensure that all of the shapes or where they should be? The only way I can see it is to write separate code for each outcome with different "goto"s.
Is there a way to have the user put all three options at once ("123", "231", etc) and then for the program to go through each number and draw it in turn? Is there a way to assign each number to a set of code drawing the shape? I'm pretty new at all of this. I appreciate any help you can give me. Thank you!
Below is an example framework that prompts the user from (a diminishing) list of shapes, divides the canvas and draws them. It only implements circles, you need to fill in the other shapes, and it's far from finished code, you need to add error checking and other finishing touches:
import turtle
CANVAS_WIDTH = 900
CANVAS_HEIGHT = 600
CHROME_WIDTH = 30 # allow for window borders, title bar, etc.
SHAPE_CHOICES = 3
def circle(bounds):
turtle.penup()
center_x = bounds['x'] + bounds['width'] // 2
bottom_y = bounds['y']
turtle.setposition(center_x, bottom_y)
turtle.pendown()
turtle.circle(min(bounds['width'], bounds['height']) // 2)
def triangle(bounds):
circle(bounds)
def square(bounds):
circle(bounds)
def pentagon(bounds):
circle(bounds)
def hexagon(bounds):
circle(bounds)
def heptagon(bounds):
circle(bounds)
DESCRIPTION, FUNCTION = 0, 1
shapes = [("Circle", circle), ("Triangle", triangle), ("Square", square), ("Hexagon", hexagon), ("Heptagon", heptagon)]
choices = []
turtle.setup(CANVAS_WIDTH + CHROME_WIDTH, CANVAS_HEIGHT + CHROME_WIDTH)
for _ in range(SHAPE_CHOICES):
for i, (description, function) in enumerate(shapes):
print("{}. {}".format(i + 1, description))
choice = int(input("Choose one number from the above: ")) - 1
choices.append(shapes[choice][FUNCTION])
del shapes[choice]
x, y = -CANVAS_WIDTH // 2, -CANVAS_HEIGHT // 2
width, height = CANVAS_WIDTH // SHAPE_CHOICES, CANVAS_HEIGHT // SHAPE_CHOICES
# I'm dividing the screen into thirds both horizontally and vertically
bounds = dict(x=x, y=y, width=width, height=height)
for choice in choices:
choice(bounds)
bounds['x'] += width
bounds['y'] += height
turtle.done()
I am trying to implement a simple Battleship game. It is a one player game versus the computer. So far I am only able to input the positions of my ship without my program breaking lol. I am trying to generate random coordinates for the computer, but I can not figure out the logic to place them beside each other (vertical or horizontal) without overlapping them.
I still need conditions for sunken ships and when the game is over, but I don't know how to go about it. My best (and only) process was to loop through the elements of each of the players and computers hit boards (the hits recorded for both computer and player) and count if there is 5 'A', 3 'C', and 2 'D' on the board. If there is, then that player wins.
from random import random, randrange
def emptyBoard():
empBoard = [ ['*','*','*','*','*','*','*'],
['*','*','*','*','*','*','*'],
['*','*','*','*','*','*','*'],
['*','*','*','*','*','*','*'],
['*','*','*','*','*','*','*'],
['*','*','*','*','*','*','*'],
['*','*','*','*','*','*','*']]
return empBoard
def placeMyShips(myBoard):
for a in range(5):
x,y = eval(input('Enter coordinate of Aircarrier: '))
myBoard [x][y] = 'A'
for c in range(3):
x1,y1 = eval(input('Enter coordinate of Cruiser: '))
myBoard [x1][y1] = 'C'
for d in range(2):
x2,y2 = eval(input('Enter coordinate of Destroyer: '))
myBoard [x2][y2] = 'D'
print ('\tMy Fleet')
for i in myBoard:
print (i)
return myBoard
def placeCompShips(compBoard):
for a in range (5):
x= randrange(0,5)
y= x+1
compBoard[x][y]= 'A'
for c in range (3):
x1= randrange(0,5)
y1= x1+1
if compBoard [x1][y1] == '*':
compBoard[x1][y1]= 'C'
for d in range (2):
x2= randrange(0,5)
y2= x2+1
if compBoard [x2][y2] =='*':
compBoard[x2][y2] = 'D'
return compBoard
def myMoves(compBoard,myHitBoard):
x,y = eval(input('Enter your move as coordinate: '))
if compBoard[x][y] == 'A':
myHitBoard[x][y] =='A'
print('Computer: You hit my Aircarrier')
elif compBoard [x][y] == 'C':
myHitBoard[x][y] =='C'
print('Computer: You hit my Cruiser')
elif compBoard [x][y] == 'D':
myHitBoard[x][y] =='D'
print('Computer: You hit my Destroyer')
else:
myHitBoard [x][y] = 'M'
print('Computer: Shot was a miss')
print ('My hits on the computer')
for i in myHitBoard:
print (i)
return myHitBoard
def compMoves(myBoard,compHitBoard):
x,y = eval(input('Enter your move as coordinate '))
if myBoard[x][y] == 'A':
compHitBoard [x][y] = 'A'
print('Player: You hit my Aircarrier')
elif myBoard [x][y] == 'C':
compHitBoard[x][y] =='C'
print('Player: You hit my Cruiser')
elif myBoard [x][y] == 'D':
compHitBoard[x][y] =='D'
print('Player: You hit my Destroyer')
else:
compHitBoard [x][y] = 'M'
print('Player: Shot was a miss')
return compHitBoard
def intro():
print('BATTLESHIP')
print('This is a one player game versus the computer')
def main():
intro()
placeMyShips(emptyBoard())
placeCompShips(emptyBoard())
main()
I think it's unlikely that you're going to get a good answer to this question because of its breadth, however what I THINK you're trying to do with your parameter issue is more like:
def main():
intro()
my_board = placeMyShips(emptyBoard())
my_hit_board = emptyBoard()
comp_board = placeCompShips(emptyBoard())
comp_hit_board = emptyBoard()
myMoves(comp_board, my_hit_board)
Note also my variable names. Functions shouldn't use mixedCase names except where it's already established in that project (e.g. this new project and every other should use lowercase_names) as per PEP8