Making simple game of Battleship - python

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

Related

List value being overwritten even though I am checking for it

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

Program will not stop when the conditions are passed

I'm writing a sum up game where two players will take turns picking a random number in the range (1,9), no repeated number allowed. If the first player picks [7, 2, 3, 5], he will win because 7+3+5 = 15
So my question is why doesn't the program stop when first_player has a sum of inputs that == 15
Below is the readme file
The game doesn't stop when first player's inputs equal 15 because you ask for second player's input regardless of whether the first player won. You can see this in your testing code, where you have two while statements for each player's input. If you complete that round with second player's input, your program works and stops there. To stop when a player wins on input, just add the conditional check to break out of main loop before asking for next player's input.
Your script is too verbose. If you made it more dynamic, with reusable logic, it becomes much easier to work with. I rewrote your game as an example.
notes:
All the game states are reused in fstrings, as dict keys, and even to represent the player
The game loop (update()) represents a single turn, and the player that turn corresponds to is toggled at the end of the loop
make_move also represents one turn
the entire game is contained in the class
reset() is used to clear the window, reset all the game properties, and start the loop, but the very first time it is called it acts as an initializer for all of the game properties.
There is never going to be an instance where both players have 15 points
import os
UNFINISHED = "unfinished"
DRAW = "draw"
FIRST_WON = "First"
SECOND_WON = "Second"
CLEAR = lambda: os.system('cls') #windows only
class AddThreeGame:
#property
def current_state(self):
return self.__state
#property
def player(self):
return self.__rotation[self.__player]
def __init__(self):
self.__rotation = [FIRST_WON, SECOND_WON]
self.__states = {
UNFINISHED:'We have unfinished business, come back for more\n',
DRAW:'Draw game\n',
FIRST_WON:'First player won this game!!!\n',
SECOND_WON:'Second player won this game!!!\n',
}
self.reset()
def make_move(self, player, number):
if number not in range(1, 10) or number in self.__input:
return False
self.__input.append(number)
self.__players[self.player].append(number)
if len(self.__players[self.player]) >= 3:
L = self.__players[self.player]
for i in range(0, len(L)-2):
for j in range(i+1, len(L)-1):
for k in range(j+1, len(L)):
if (L[i] + L[j] + L[k]) == 15:
self.__state = player
return True
if len(self.__input) == 9:
self.__state = DRAW
return True
def update(self):
while True:
num = int(input(f'{self.player} player please enter a number from 1 to 9: '))
while True:
if self.make_move(self.player, num):
break
else:
num = int(input("Wrong input, please try a different number: "))
if self.current_state == UNFINISHED:
if self.__player == 1: #technically, this is player 2
print(self.__states[self.current_state])
#next player
self.__player = (self.__player + 1) % 2
else:
print(self.__states[self.current_state])
break
if input('Play Again? (y or n): ') == 'y':
self.reset()
def reset(self):
CLEAR()
self.__player = 0
self.__input = []
self.__state = UNFINISHED
self.__players = {
FIRST_WON:[],
SECOND_WON:[],
}
self.update()
if __name__ == '__main__':
AddThreeGame()

I'm stuck in the creating of a Board game in python

I have an excercise to do and I'm stuck. It's the board game Alak, not much known, that I have to code in python. I can link the execrcise with the rules so you can help me better. The code has the main part and the library with all the procedures and function.
from Library_alak import *
n = 0
while n < 1:
n = int(input('Saisir nombre de case strictement positif : '))
loop = True
player = 1
player2 = 2
removed = [-1]
board = newboard(n)
display(board, n)
while loop:
i = select(board, n, player, removed)
print(i)
board = put(board, player, i)
display(board, n)
capture(board, n, player, player2)
loop = True if again(board, n, player, removed) is True else False
if player == 1 and loop:
player, player2 = 2, 1
elif player == 2 and loop:
player, player2 = 1, 2
win(board, n)
print(win(board, n))
And here is the library:
def newboard(n):
board = ([0] * n)
return board
def display(board, n):
for i in range(n):
if board[i] == 1:
print('X', end=' ')
elif board[i] == 2:
print('O', end=' ')
else:
print(' . ', end=' ')
def capture(board, n, player, player2):
for place in range(n):
if place == player:
place_beginning = place
while board[place] != player:
place_end = place
if board[place + x] == player:
return board
else:
return board
def again(board, n, player, removed):
for p in board(0):
if p == 0:
if p not in removed:
return True
else:
return False
def possible(n, removed, player, i, board):
for p in range(n + 1):
if p == 1:
if board[p-1] == 0:
if p not in removed:
return True
else:
return False
def win(board, n):
piecesp1 = 0
piecesp2 = 0
for i in board(0):
if i == 1:
piecesp1 += 1
else:
piecesp2 += 1
if piecesp1 > piecesp2:
print('Victory : Player 1')
elif piecesp2 > piecesp1:
print('Victory : Player 2')
else:
return 'Equality'
def select(board, n, player, removed):
loop = True
while loop:
print('player', player)
i = int(input('Enter number of boxes : '))
loop = False if possible(n, removed, player, i, board)is True else True
return i
def put(board, player, i):
i -= 1
if board[i] == 0:
if player == 1:
board[i] = 1
return board
else:
board[i] = 2
return board
else:
put(board, player, i)
So my problems here are that I have few errors, the first one is that when I enter the number '1' when asked to enter a number of boxes ( which is the place to play on ) nothing happens. Then when entering any other number, either the error is : if board[place + x] == player:
NameError: name 'x' is not defined
or there seems to be a problem with the : if board[place + x] == player:
NameError: name 'x' is not defined
I would appreciate a lot if anyone could help me. I'm conscious that it might not be as detailed as it should be and that you maybe don't get it all but you can contact me for more.
Rules of the Alak game:
Black and white take turns placing stones on the line. Unlike Go, this placement is compulsory if a move is available; if no move is possible, the game is over.
No stone may be placed in a location occupied by another stone, or in a location where a stone of your own colour has just been removed. The latter condition keeps the game from entering a neverending loop of stone placement and capture, known in Go as ko.
If placing a stone causes one or two groups of enemy stones to no longer have any adjacent empty spaces--liberties, as in Go--then those stones are removed. As the above rule states, the opponent may not play in those locations on their following turn.
If placing a stone causes one or two groups of your own colour to no longer have any liberties, the stones are not suicided, but instead are safe and not removed from play.
You shouldn't use "player2" as a variable, there's an easier way, just use "player" which take the value 1 or 2 according to the player. You know, something like that : player = 1 if x%2==0 else 2
and x is just a increasing int from 0 until the end of the game.

For loop over dict.items() in battleships python game

I am making the game battleships in Python and have gotten stuck on a piece of code. I have made a 10x10 grid board where the player/computer will place 5 ships with different sizes. The ships are stored in a dictionary.
I have #hastagged the spot where I am stuck. When the player tries to place a ship that a spot which is not available, it prints "invalid choice" and the player should be able to place it again. But the loop continues and therefore skips placing that ship. I've tried calling the function "player_place_ships" but then it starts all over and places duplicates of the ships that are already placed.
I was thinking of creating a count in the for loop and starting the loop again from where it left off before the "invalid choice" but unsure if it's doable to start a for loop from dict.items at a specific spot?
Hoping there is a kind soul out there with some advice, I'm rather new at python so might be using bad/unorthodox codes here.
Here is the code:
#Dictionary for ships
ships = {'A': 5, 'B': 4, 'C': 3, 'S': 3, 'D': 2}
#Create player board
player_board = []
for player_row in range(10):
player_board.append([])
for player_col in range(10):
player_board[player_row].append('.')
#Print player board
def print_player_board(player_board):
for player_row in player_board:
print(" ".join(player_row))
def player_place_ships(player_board, ships):
for i, j in ships.items():
ori = input('Enter orientation, v or h: ')
x = int(input('Enter row: '))
y = int(input('Enter col: '))
place = x,y
placement = player_board[x][y]
if ori == 'v' and placement == '.':
for k in range(j):
player_board[x][y] = i
player_board[x+k][y] = i
elif ori == 'h' and placement == '.':
player_board[x][y] = i
player_board[x][y+k] = i
elif ori != 'v' or 'h' and placement != '.':
print('Invalid choice, please try again.') #This is where I'm stuck
player_place_ships(player_board, ships)
print_player_board(player_board)
Here is a screenshot of the output so you know what I mean:
You might fix your issue with a while ship_not_placed
def player_place_ships(player_board, ships):
for i, j in ships.items():
ship_not_place = true
while ship_not_placed :
ori = input('Enter orientation, v or h: ')
x = int(input('Enter row: '))
y = int(input('Enter col: '))
place = x,y
placement = player_board[x][y]
if ori == 'v' and placement == '.':
for k in range(j):
player_board[x][y] = i
player_board[x+k][y] = i
ship_not_place = false
elif ori == 'h' and placement == '.':
player_board[x][y] = i
player_board[x][y+k] = i
ship_not_place = false
elif ori != 'v' or 'h' and placement != '.':
print('Invalid choice, please try again.')
or just with a while true and break out of the while instead of changing ship_not_placed (I never understood what was the best practice between the two)

Little assistance with my tic-tac-toe program

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!")

Categories

Resources