I am currently making a simple Battleships game using Python 3, but I can't seem to get the board to display. Here is my code;
# Battleships
def main():
pass
if __name__ == '__main__':
main()
from random import randint
# this initialises the board
board = []
for x in range(5):
board.append(["O"] * 5)
def print_board(board):
for row in board:
print (" ".join(row))
# this starts the game and prints the board
print ("Let's play Battleship!")
print_board(board)
# defines the location of the ship
def random_row(board):
return randint(0, len(board) - 1)
def random_col(board):
return randint(0, len(board[0]) - 1)
ship_row = random_row(board)
ship_col = random_col(board)
# asks the player to make a guess
for turn in range(5):
guess_row = int(input("Guess Row:"))
guess_col = int(input("Guess Col:"))
# if the player guesses correctly, then the game ends cleanly
if guess_row == ship_row and guess_col == ship_col:
print ("Congratulations! You sunk my battleship!")
else:
# if the player guesses outside the board, then the following message appears
if (guess_row < 0 or guess_row > 4) or (guess_col < 0 or guess_col > 4):
print ("Oh dear, you've hit an island!")
# a warning if the guess has already been made by the player
elif(board[guess_row][guess_col] == "X"):
print ("That guess has already been made.")
# if the guess is wrong, then the relevant board place is marked with an X
else:
print ("You've missed my battleship!")
board[guess_row][guess_col] = "X"
# prints the turn and updates the board accordingly
print ("Turn " + str(turn+1) + " out of 5.")
print_board(board)
# if the user has had 5 guesses, it's game over
if turn >= 3:
print ("You sunk my battleship! We're gonna need a bigger boat.")
The game accepts the co-ordinates, but doesn't print anything to do with the board or if the player makes a repeated guess or one that's outside the field of play.
Any help would be much appreciated!
Your code asks for 5 sets of guesses before it does anything with them, because the code to respond to a guess is outside of the loop asking for the guesses. I'm, ahem, guessing that in your testing you never entered enough guesses to get past that loop. Move the guess-processing code into the loop, and you should at least see reactions to those guesses.
You are iterating over the loop THEN all the if statements. Put all the if statements inside the for loop. Add a counter saying if you hit my ship add one point (score += 1) then
if score >= 3:
print ("You sunk my battleship! We're gonna need a bigger boat.")
import random
from datetime import date
grid = []
def createGrid():
global grid
grid = []
for i in range(0,10):
grid.append([])
for j in range(0,10):
grid[i].append("W")
def renderGrid():
global grid
for i in range(0,10):
for j in range(0,10):
block = grid[i][j]
if block == "s": block = "W"
print(block,end=" ")
print()
print()
def placeGrid():
xsize = 10
ysize = 10
shipBlocks = 17
length = 2
submarineException = True
while shipBlocks > 0:
x = random.randint(0,xsize-1)
y = random.randint(0,ysize-1)
value = 1
cx = 0
cy = 0
if random.randint(0,1) == 1:
value = -value
if random.randint(0,1) == 1:
cx = value
else:
cy = value
broken = False
for b in range(0,length):
xpos = x+cx*b
ypos = y+cy*b
if xpos<0 or xpos>xsize-1 or ypos<0 or ypos>ysize-1: broken = True
if broken: continue
for b in range(0,length):
grid[x+cx*b][y+cy*b] = "s"
shipBlocks = shipBlocks - length
if length == 3:
if submarineException:
submarineException = False
else:
length+=1
else:
length+=1
def runGame():
name = input("Enter your username: ")
global grid
createGrid()
placeGrid()
hits = 0
while True:
won = True
for row in grid:
for character in row:
if character == "s":
won = False
if won:
print("You have won the game in "+str(hits)+" hits!")
renderGrid()
y = input("Hit X: ")
x = input("Hit Y: ")
try:
x = int(x)-1
y = int(y)-1
if x < 0 or y < 0:
raise
if grid[x][y] == "s":
grid[x][y] = "S"
print("Ship hit.")
elif grid[x][y] == "S":
print("You already hit here.")
continue
hits+=1
except Exception as e:
print("Error, number from 1 to 10 please.")
#stackoverflow saves lives
runGame()
Related
I'm making a 2-play Battleship game in python and have been struggling with this for a while now:
I apologise if the question is poorly worded but I was to know how I can make my game log the match score at the end of the three games with something like:
print('Match score is' + score + 'Player' + (whoever) + 'wins!)
I'm not entirely sure how to implement this myself I have a range for games in range(3), but I don't know how to log the final score.
Also, how can I change the symbol for player_two so that I am not using an 'X' for both players? I've tried changing the input_check() but I get more errors than I did before.
from random import randint
game_board = []
player_one = {
"name": "Player 1",
"wins": 0,
"lose": 0
}
player_two = {
"name": "Player 2",
"wins": 0,
"lose": 0
}
# Building our 5 x 5 board
def build_game_board(board):
for item in range(5):
board.append(["O"] * 5)
def show_board(board):
print("Find and sink the ship!")
for row in board:
print(" ".join(row))
# Defining ships locations
def load_game(board):
print("WELCOME TO BATTLESHIP!")
print("START")
del board[:]
build_game_board(board)
show_board(board)
ship_col = randint(1, len(board))
ship_row = randint(1, len(board[0]))
return {
'ship_col': ship_col,
'ship_row': ship_row,
}
ship_points = load_game(game_board)
# Players will alternate turns.
def player_turns(total_turns):
if total_turns % 2 == 0:
total_turns += 1
return player_one
else:
return player_two
# Allows new game to start
def play_again():
global ship_points
answer = input("Would you like to play again? ")
if answer == "yes" or answer == "y":
ship_points = load_game(game_board)
else:
print("Thanks for playing!")
exit()
# What will be done with players guesses
def input_check(ship_row, ship_col, player, board):
guess_col = 0
guess_row = 0
while True:
try:
guess_row = int(input("Guess Row:")) - 1
guess_col = int(input("Guess Col:")) - 1
except ValueError:
print("Enter a number only: ")
continue
else:
break
match = guess_row == ship_row - 1 and guess_col == ship_col - 1
not_on_game_board = (guess_row < 0 or guess_row > 4) or (guess_col < 0 or guess_col > 4)
if match:
player["wins"] += 1
print("Congratulations! You sunk my battleship!")
print("Thanks for playing!")
play_again()
elif not match:
if not_on_game_board:
print("Oops, that's not even in the ocean.")
elif board[guess_row][guess_col] == "X":
print("You guessed that one already.")
else:
print("You missed my battleship!")
board[guess_row][guess_col] = "X"
show_board(game_board)
else:
return 0
def main():
begin = input('Type \'start\' to begin: ')
while (begin != str('start')):
begin = input('Type \'start\' to begin: ')
for games in range(3):
for turns in range(6):
if player_turns(turns) == player_one:
# print(ship_points)
print("Player One")
input_check(
ship_points['ship_row'],
ship_points['ship_col'],
player_one, game_board
)
elif player_turns(turns) == player_two:
print("Player Two")
input_check(
ship_points['ship_row'],
ship_points['ship_col'],
player_two, game_board
)
if turns == 5:
print("The game is a draw")
play_again()
if __name__ == "__main__":
main()
You can use style string formatting to print the log.
print('Match score is %d : %d(Player1 : Player2)' % (player_one["wins"], player_two["wins"]))
For more information about string formatting, check this link.
To change the symbol for Player 2, you can change the following code.
elif board[guess_row][guess_col] == "X" or board[guess_row][guess_col] == "Y":
print("You guessed that one already.")
else:
print("You missed my battleship!")
if player == player_one:
board[guess_row][guess_col] = "X"
else:
board[guess_row][guess_col] = "Y"
I'm making a 2-player battleship game in python. I've made it so that each 'game' allows a total of 6 turns (3 from each player), after which a message will appear saying 'The number of turns has ended'.
Once this happens, they will be asked to play again. If they answer 'yes' or 'y', the game should reload. However it doesn't. The board loads but the program then exits. I believe the issue lies with my play_again() function but I'm not quite sure what it is.
I want to make it so that the players can play as many games as they want until they decide to answer 'no' or 'n'. How do I go about implementing this?
from random import randint
game_board = []
player_one = {
"name": "Player 1",
"wins": 0,
}
player_two = {
"name": "Player 2",
"wins": 0,
}
colors = {"reset":"\033[00m",
"red":"\033[91m",
"blue":"\033[94m",
"cyan":"\033[96m"
}
# Building our 5 x 5 board
def build_game_board(board):
for item in range(5):
board.append(["O"] * 5)
def show_board(board):
for row in board:
print(" ".join(row))
# Defining ships locations
def load_game(board):
print("WELCOME TO BATTLESHIP!")
print("Find and sink the ship!")
del board[:]
build_game_board(board)
print(colors['blue'])
show_board(board)
print(colors['reset'])
ship_col = randint(1, len(board))
ship_row = randint(1, len(board[0]))
return {
'ship_col': ship_col,
'ship_row': ship_row,
}
ship_points = load_game(game_board)
# Players will alternate turns.
def player_turns(total_turns):
if total_turns % 2 == 0:
total_turns += 1
return player_one
return player_two
# Allows new game to start
def play_again():
positive = ["yes", "y"]
negative = ["no", "n"]
global ship_points
while True:
answer = input("Play again? [Y(es) / N(o)]: ").lower().strip()
if answer in positive:
ship_points = load_game(game_board)
break
elif answer in negative:
print("Thanks for playing!")
exit()
# What will be done with players guesses
def input_check(ship_row, ship_col, player, board):
guess_col = 0
guess_row = 0
while True:
try:
guess_row = int(input("Guess Row:")) - 1
guess_col = int(input("Guess Col:")) - 1
except ValueError:
print("Enter a number only: ")
continue
else:
break
match = guess_row == ship_row - 1 and guess_col == ship_col - 1
not_on_game_board = (guess_row < 0 or guess_row > 4) or (guess_col < 0 or guess_col > 4)
if match:
player["wins"] += 1
print("Congratulations! You sunk my battleship!")
print('The current match score is %d : %d (Player1 : Player2)' % (player_one["wins"], player_two["wins"]))
print("Thanks for playing!")
play_again()
elif not match:
if not_on_game_board:
print("Oops, that's not even in the ocean.")
elif board[guess_row][guess_col] == "X" or board[guess_row][guess_col] == "Y":
print("You guessed that one already.")
else:
print("You missed my battleship!")
if player == player_one:
board[guess_row][guess_col] = "X"
else:
board[guess_row][guess_col] = "Y"
print(colors['cyan'])
show_board(game_board)
print(colors['reset'])
else:
return 0
def main():
begin = input('Type \'start\' to begin: ')
while (begin != str('start')):
begin = input('Type \'start\' to begin: ')
for turns in range(6):
if player_turns(turns) == player_one:
print(ship_points)
print("Player One")
input_check(
ship_points['ship_row'],
ship_points['ship_col'],
player_one, game_board
)
elif player_turns(turns) == player_two:
print("Player Two")
input_check(
ship_points['ship_row'],
ship_points['ship_col'],
player_two, game_board
)
if turns == 5:
print("The number of turns has ended.")
print(colors['red'])
show_board(game_board)
print(colors['reset'])
print('The current match score is %d : %d (Player1 : Player2)' % (player_one["wins"], player_two["wins"]))
play_again()
if __name__ == "__main__":
main()
It also worked for me when I added an invocation to main in your play_again() function:
# Allows new game to start
def play_again():
positive = ["yes", "y"]
negative = ["no", "n"]
global ship_points
while True:
answer = input("Play again? [Y(es) / N(o)]: ").lower().strip()
if answer in positive:
ship_points = load_game(game_board)
main()
break
elif answer in negative:
print("Thanks for playing!")
exit()
Try modifying main with:
turns = 0
while turns < 6:
# Process turn...
if turns == 5:
# Show endgame board
if play_again():
turns = -1
turns += 1
And have play_again return True on positive input ['y', 'yes'] and False otherwise.
The problem is that your play_again() call, upon receiving "Y" as answer, loads the board, but then simply returns. Where? Well, to the place it was called from - the for loop in main(). And unfortunately, it is the last iteration of said for loop, so the loop then ends and the program exits.
You should've put another loop around the for loop:
while True:
for turns in range(6):
...
I want to give the user the choice of whether they want to have the coordinates randomized or whether they want to input them for a battleships game on Python. It should be noted i'm using a portable application of PyScripter to build this.
Randomized Version
from random import randint
Battleship_Board =[]
for x in range (0,5):
Battleship_Board.append(["O"] * 5)
def print_Battleship_Board(Battleship_Board):
for row in Battleship_Board:
print (" ".join(row))
print ("Let's play Battleships!")
print_Battleship_Board(Battleship_Board)
def random_row(Battleship_Board):
return randint(0, len(Battleship_Board) - 1)
def random_col(Battleship_Board):
return randint(0, len(Battleship_Board[0]) - 1)
Battleship_Row = random_row(Battleship_Board)
Battleship_Column = random_col(Battleship_Board)
for turn in range(5):
Guess_Board_Row = int(input("Guesss the X value"))
Guess_Board_Column = int(input("Guess the Y value"))
if Guess_Board_Row == Battleship_Row and Guess_Board_Column == Battleship_Column:
print("You sunk my battleship!")
break
else:
if (Guess_Board_Row < 1 or Guess_Board_Row > 5) or (Guess_Board_Column < 1 or Guess_Board_Column > 5):
print("Apologies, that's not on the grid")
elif(Battleship_Board[Guess_Board_Row][Guess_Board_Column] == "X"):
print("You already guessed that value")
else:
print("You missed my battleship")
Battleship_Board[Guess_Board_Row][Guess_Board_Column] = "X"
print("Turn" + str(turn+1) + " out of 4.")
print_Battleship_Board(Battleship_Board)
if turn >=4:
print("Game Over")
As you can see I'm letting the user play the game based on a randomized value for the column and row.
Inputted Version
Battleship_Board =[]
for x in range (0,5):
Battleship_Board.append(["O"] * 5)
def print_Battleship_Board(Battleship_Board):
for row in Battleship_Board:
print (" ".join(row))
print ("Let's play Battleships!")
print_Battleship_Board(Battleship_Board)
Battleship_Row = int(input("Please enter a X value"))
Battleship_Column = int(input("Please enter a Y value"))
if (Battleship_Row < 1 or Battleship_Row > 5) or (Battleship_Column < 1 or Battleship_Row > 5):
print("Apologies, that's not on the grid")
for turn in range(5):
Guess_Board_Row = int(input("Guess the X value"))
Guess_Board_Column = int(input("Guess the Y value"))
if Guess_Board_Row == Battleship_Row and Guess_Board_Column == Battleship_Column:
print("You sunk my battleship!")
print("My Ship was here: [" + str(Battleship_Row) + "][" + str(Battleship_Column) + "]")
break
else:
if turn == 5:
Battleship_Board[Battleship_Row][Battleship_Column] = "X"
print_Battleship_Board(Battleship_Board)
print("Game Over")
print("My Ship was here: [" + str(Battleship_Row) + "][" + str(Battleship_Column) + "]")
else:
if (Guess_Board_Row < 1 or Guess_Board_Row > 5) or (Guess_Board_Column < 1 or Guess_Board_Column > 5):
print("Apologies, that's not on the grid")
elif(Battleship_Board[Guess_Board_Row][Guess_Board_Column] == "X"):
print("You already guessed that value")
else:
print("You missed my battleship!")
Battleship_Board[Guess_Board_Row][Guess_Board_Column] = "X"
print("Turns taken out of 5:", turn + 1)
print_Battleship_Board(Battleship_Board)
Here is the one where the user gets to input the values.
I want to establish option between these two versions for the user to pick when starting up the application. How can I do that?
You can use command-line arguments that allow the user to choose the mode while he fires the game up:
import sys
if len(sys.argv) > 1 and sys.argv[1] == '<some-value>':
# Randomize
else:
# Prompt user for input
More about command-line arguments here. For user-friendlier (read fancier) command-line options, check out argparse.
This is the "Battleship!" problem that is covered in Codecademy (Python) I want to put a condition wherein the number of turns does not get incremented in the case that the user enterers a value of row/column that is repeated or outside limits. I can't figure out what the problem is in this code:
from random import randint
board = []
for x in range(5):
board.append(["O"] * 5)
def print_board(board):
for row in board:
print " ".join(row)
print "Let's play Battleship!"
print_board(board)
def random_row(board):
return randint(0, len(board) - 1)
def random_col(board):
return randint(0, len(board[0]) - 1)
ship_row = random_row(board)
ship_col = random_col(board)
print ship_row
print ship_col
# Everything from here on should go in your for loop!
for turn in range(4):
# Be sure to indent four spaces!
print "Turn", turn + 1
guess_row = int(raw_input("Guess Row:"))
guess_col = int(raw_input("Guess Col:"))
if guess_row == ship_row and guess_col == ship_col:
print "Congratulations! You sunk my battleship!"
break
else:
if (guess_row < 0 or guess_row > 4) or (guess_col < 0 or guess_col > 4):
print "Oops, that's not even in the ocean."
print "Please try again."
# turn -= 1 Why doesn't this work? The "Game Over" message does not get displayed at the end of the game if such a case arises (but the game still ends!), which means the value of turn does not reach 3. But still when 'turn + 1' is printed, the value gets incremented even if such a condition is encountered.
elif(board[guess_row][guess_col] == "X"):
print "You guessed that one already."
print "Please try again."
# turn -= 1 Same as last message.
else:
print "You missed my battleship!"
board[guess_row][guess_col] = "X"
if turn == 3:
print "Game Over"
# Print (turn + 1) here!
print_board(board)
There is only a very small error in your code, from what I can see. The last if statement, which includes your "Game Over" string, is indented incorrectly. Move it left one block:
else:
print "You missed my battleship!"
board[guess_row][guess_col] = "X"
if turn == 3:
print "Game Over"
# Print (turn + 1) here!
print_board(board)
Here is my complete code from that exercise:
from random import randint
board = []
for x in range(5):
board.append(["O"] * 5)
def print_board(board):
for row in board:
print " ".join(row)
print "Let's play Battleship!"
print_board(board)
def random_row(board):
return randint(0, len(board) - 1)
def random_col(board):
return randint(0, len(board[0]) - 1)
ship_row = random_row(board)
ship_col = random_col(board)
print ship_row
print ship_col
for turn in range(4):
print "Turn", turn + 1
guess_row = int(raw_input("Guess Row:"))
guess_col = int(raw_input("Guess Col:"))
if guess_row == ship_row and guess_col == ship_col:
print "Congratulations! You sunk my battleship!"
else:
if (guess_row < 0 or guess_row > 4) or (guess_col < 0 or guess_col > 4):
print "Oops, that's not even in the ocean."
elif(board[guess_row][guess_col] == "X"):
print "You guessed that one already."
else:
print "You missed my battleship!"
board[guess_row][guess_col] = "X"
print_board(board)
if turn == 3:
print "Game Over"
A for turn in range(4): loop doesn't work the way you think it does.
It's equivalent to this:
_range = [0, 1, 2, 3]
_it = iter(_range)
while True:
try:
turn = next(_it)
except StopIteration:
break
# your code here
You don't have to understand all of the details there, but they key point is that, each time through the loop, it's assigning a new value to turn, which comes straight out of the iterator, and has nothing to do with the old value of turn. So, your changes to turn are irrelevant.
So, how do you fix it?
One way is to replace the for loop with a while loop that explicitly maintains turn, so you can explicitly decrement it—or, better, just not increment it. For example:
turn = 0
while turn < 4:
# your code, slightly modified
# do turn += 1 only when the turn is valid
# don't do turn += 1 when the turn is invalid
The other way is to put another loop inside this for loop that just repeats until the player makes a valid turn:
for turn in range(4):
while True:
# your code, slightly modified
# do break only when the turn is valid
# do nothing, or continue, when the turn is invalid
While I'm at it, there's another problem in your code.
That if turn == 3 part is either wrong, or unnecessary. The game is over when the player is out of turns. You know the player is out of turns when you finish the loop. You don't need any extra test for it. So:
for or while or whatever:
# stuff
print "Game Over"
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Bear with me, I'm new to programming and I know for a fact this contains a lot of unnecessary code.
Is there a way to add more ships without the code extending forever?
Also a better way to code the comparisons under my while loop. Thanks for taking the time to read and comment.
from random import randint
board = []
for x in range(10):
board.append(["O"] * 10)
# creating the "map" of "O"'s for an ocean - 10x10
def print_board(board):
for row in board:
print " ".join(row)
print "Let's play Battleship!"
print_board(board)
# random number for row from 0 to length of board (9) in this case
def random_row(board):
return randint(0, len(board) - 1)
# random number for column from 0 to length of board (9) in this case
def random_col(board):
return randint(0, len(board[0]) - 1)
# 1st ship, size = 1x1
ship_row = random_row(board)
ship_col = random_col(board)
# 2nd ship, size = 1x2
ship_row2 = random_row(board)
if ship_row2 == ship_row: #Did not want a ship coordinate to fall onto a previous ship
ship_row2 = random_row(board) #so I set it to generate a new number if it did
ship_row2_1 = ship_row2 - 1 #2nd part of this ship, needs to be adjacent so I set - 1 (could be +1)
if not ship_row2_1 >= 0: # if first part is 0, then ship_row2_1 would be off the "map",
ship_row2_1 += 2 #so I added 2 to bring it to a positive number
ship_col2 = random_col(board)#same things as above for the column code
if ship_col2 == ship_col:
ship_col2 = random_col(board)
ship_col2_1 = ship_col2
turn = 0
ships_sunk = 0
while True:
try:
guess_row = int(raw_input("Guess Row:"))
guess_col = int(raw_input("Guess Col:"))
# so my code here basically says if you hit the 1x1 ship it should turn it to an X,
#and not be able to hit it again.
if (guess_row == ship_row and guess_col == ship_col) and (board[guess_row][guess_col] != "X"):
print "\nCongratulations! You sunk a battleship!"
print "One more to go!\n"
board[guess_row][guess_col] = "X"
print_board(board)
ships_sunk += 1
if ships_sunk == 2:
print "\n You got them all! Pokemon!"
break
# here is the same but for the 1x2 ship, I had to turn them all to X to prevent user,
# from hitting the same part of the "ship".
elif ((guess_row == ship_row2 and guess_col == ship_col2) or \
(guess_row == ship_row2_1 and guess_col == ship_col2_1)) and (board[guess_row][guess_col] != "X"):
print "\nCongratulations! You sunk a battleship!"
print "One more to go!\n"
board[guess_row][guess_col] = "X"
board[ship_row2][ship_col2] = "X"
board[ship_row2_1][ship_col2_1] = "X"
print_board(board)
ships_sunk += 1
if ships_sunk == 2:
print "\n You got them all! Pokemon!"
break
else:
if (guess_row < 0 or guess_row > (len(board) -1 )) or (guess_col < 0 or guess_col > (len(board[0]) - 1)):
print "\nOops, that's not even in the ocean."
elif(board[guess_row][guess_col] == "X"):
print "\nYou guessed that one already."
elif type(guess_row) is not int or type(guess_col) is not int:
print "Type a number!"
else:
print "\nYou missed my battleship!"
board[guess_row][guess_col] = "X"
turn += 1
print_board(board)
if turn == 4:
print "Game Over"
break
except ValueError:
print "Please type a number!"
You need to store the "game state" in a more flexible way. The same thing goes for the logic that determines when a player has won. One way of doing this would be to break down your application into classes, maybe something like:
Battle class: contains ships for each side, scoring methods, dimensions for the battle area
Ship class: size of the ship, amount of damage ship has sustained, ship's location
Whenever making a new Battle class, you could pass it an initial list of Ships for each side. These lists could be as long as you want (provided the ships can fit into the battle area without overlapping).