So I've been going through Codecademy's Python lessons. I enjoyed the Battleship game I created in one of the lessons, but one thing annoyed me. The player has to constantly keep in mind that the rows and columns count 0-4 rather than 1-5. I've already made an attempt to fix this, but I'm not sure if it's messing with my ship placement.
Here's my original code:
from random import randint
#Create 5x5 game board
board = []
for x in range(5):
board.append(["O"] * 5)
def print_board(board):
for row in board:
print " ".join(row)
#Start game
print "Let's play Battleship!"
print_board(board)
#Randomly place 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)
#Process player guesses max 4 turns
for turn in range(4):
print "Turn: %d" % (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_board(board)
elif(board[guess_row][guess_col] == "X"):
print "You guessed that one already."
print_board(board)
else:
print "You missed my battleship!"
board[guess_row][guess_col] = "X"
print_board(board)
if turn > 2:
print "Game Over"
Here's my attempt to change the board count:
from random import randint
#Create 5x5 game board
board = ['dummy']
for x in range(5):
board.append(["O"] * 6)
def print_board(board):
for row in board:
print " ".join(row[1:])
#Start game
print "Let's play Battleship!"
print_board(board[1:])
#Randomly place ship
def random_row(board):
return randint(1, len(board[1:]) - 1)
def random_col(board):
return randint(1, len(board[1:]) - 1)
ship_row = random_row(board[1:])
ship_col = random_col(board[1:])
print "%d,%d" % (ship_row, ship_col)
#Process player guesses max 4 turns
for turn in range(4):
print "Turn: %d" % (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 < 1 or guess_row > 5) or (guess_col < 1 or guess_col > 5):
print "Oops, that's not even in the ocean."
print_board(board[1:])
elif(board[guess_row][guess_col] == "X"):
print "You guessed that one already."
print_board(board[1:])
else:
print "You missed my battleship!"
board[guess_row][guess_col] = "X"
print_board(board[1:])
if turn > 2:
print "Game Over"
The print "%d,%d" % (ship_row, ship_col) is only in there so I can test the ship placement. I haven't seen a ship placed in a position higher than 3 on rows or columns. Not sure if I screwed the code or if it's just dumb luck. Any insight is appreciated and if you know an easier to accomplish this please let me know. I've been thinking guess_row = int(raw_input("Guess Row:")) - 1 but haven't tested it yet.
Well sometimes the obvious answer is the right one.
I changed:
for turn in range(4):
print "Turn: %d" % (turn + 1)
guess_row = int(raw_input("Guess Row:"))
guess_col = int(raw_input("Guess Col:"))
To:
for turn in range(4):
print "Turn: %d" % (turn + 1)
guess_row = int(raw_input("Guess Row:")) - 1
guess_col = int(raw_input("Guess Col:")) - 1
This allows the player to enter a choice of 1-5 rather than 0-4
Related
I'm nearing the end of a lesson on creating a very simple battleship game. Basically you get 4 chances to guess the location of the ship. if you lose: game over. If you win before all 4 chances you're supposed to end the game using a "break" function.
Problem is: After inserting "break", I get an error msg reading:
File "python", line 33
SyntaxError: 'break' outside loop
Here is my code, please and thank you for any help it is much appreciated:
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
turn = 1
for turn in range(4):
print turn
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."
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 turn + 1
print_board(board)
if turn == 3:
print "Game Over"
Your break is outside the loop indeed. Try to fix indentation in if-else statement on line 31 like this:
for turn in range(4):
...
if guess_row == ship_row and guess_col == ship_col:
print "Congratulations! You sunk my battleship!"
break
else:
...
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()
This question already has answers here:
How can I read inputs as numbers?
(10 answers)
Closed 7 years ago.
I'm having issues with this code, when i run the code, it always prints "Oops, that's not even in the ocean." no matter what i type. Also if i write letters the code crashes. How can i add a typo check fonction that could solve the crash and make the code resistant from typos from the user. Thank you in advance !
from random import randint
#initializing board + this is my list
board = []
for x in range(5):
board.append(["O"] * 5)
def print_board(board):
for row in board:
print " ".join(row)
#starting the game and printing the board
print "Let's play Battleship!"
print_board(board)
#defining where the ship is
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)
#asking the user for a guess
for turn in range(4):
guess_row = raw_input("Guess Row:")
guess_col = raw_input("Guess Col:")
# if the user's right, the game ends
if guess_row == ship_row and guess_col == ship_col:
print "Congratulations! You sunk my battleship!"
break
else:
#warning if the guess is out of the board
if (guess_row < 0 or guess_row > 5) or (guess_col < 0 or guess_col > 5):
print "Oops, that's not even in the ocean."
#warning if the guess was already made
elif(board[guess_row][guess_col] == "X"):
print "You guessed that one already."
#if the guess is wrong, mark the point with an X and start again
else:
print "You missed my battleship!"
board[guess_row][guess_col] = "X"
# Print turn and board again here
print "Turn " + str(turn+1) + " out of 4."
print_board(board)
#if the user have made 4 tries, it's game over
if turn >= 3:
print "Game Over"
Your problem lies in the fact that raw_input returns a string, you need to cast it to an integer like this:
guess_row = int(raw_input("Guess Row:"))
guess_col = int(raw_input("Guess Col:"))
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).