Battleships game in python with tkinter - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: Homework (https://python-forum.io/forum-9.html) +--- Thread: Battleships game in python with tkinter (/thread-12928.html) |
Battleships game in python with tkinter - Togeh - Sep-19-2018 I am doing my best to create a battleships game in python with tkinter. Currently the board consists of a list with lists of "~" and "around" it is a border of "#". The border is there to check that a ship can be placed on the board and not extend beyond the board. I know this seems redundant, which is why I humbly ask for improvements. I am having two major problems with this though: I have a hunch that I should be implementing classes but I am very new to them so I'd greatly appreciate some guidance. My "AI" function (ai_shoots) is currently shooting on the same field that the player is shooting at, which it obviously shouldn't do. Instead it should shoot on your board. Press the 1 player button to play against the AI. from tkinter import * from tkinter import font import tkinter.messagebox from functools import partial import random import time import sys import os root = Tk() root.wm_title("BATTLESHIPS") root.configure(background='gray19') font1 = font.Font(family='Helvetica', size=12, weight='bold') font_big = font.Font(family='Helvetica', size=16, weight='bold') font_normal = font.Font(family='Helvetica', size=10, weight='normal') ships = {"Aircraft Carrier": 4, "Battleship": 3, "Submarine": 2, "Destroyer": 1} AI = False def restart_program(): python = sys.executable os.execl(python, python, *sys.argv) def player_board(): board = [] t = [] t += (10 + 2) * ['# '] board.append(t) # Övre ram rad = ['# '] # Vänster ram for r in range(0, 10): rad.append("~ ") rad.append('# ') # Höger ram for k in range(0, 10): board.append(list(rad)) board.append(t) # Undre ram return board def place_ship(ship, board): # w = 0 # Håller igång loopen while True: checkcoords = [] x = random.randint(1, 10) # Genererad x-koordinat y = random.randint(1, 10) # Genererad y-koordinat o = random.randint(0, 1) # Väljer placeringssätt if o == 0: ori = "v" # Vertikalt else: ori = "h" # Horisontellt if ori == "v" and y + ships[ship] > 10: pass # w = 0 # Säkerställer att båten kan placeras inom spelplanen elif ori == "h" and x + ships[ship] > 10: pass # w = 0 else: if ori == "v": for i in range(-1, (ships[ship] + 1)): for j in range(-1, 2): checkcoords.append(board[y + i][x + j]) if ': ' not in checkcoords: for i in range(ships[ship]): board[y + i][x] = ': ' break # else: # w = 0 elif ori == "h": for i in range(-1, (ships[ship] + 1)): for j in range(-1, 2): checkcoords.append(board[y + j][x + i]) if ': ' not in checkcoords: for i in range(ships[ship]): board[y][x + i] = ': ' break # else: # w = 0 def place_all_ships(board): for ship in ships: for antal in range(0, (5 - ships[ship])): place_ship(ship, board) def popupwindow(msg): answer = tkinter.messagebox.askquestion("Game Over", msg + " Would you like to play again?") if answer == "yes": restart_program() elif answer == "no": quit() def nr_players(number): global AI if number == 1: player2_or_AI.set("AI") AI = True else: player2_or_AI.set("Player 2") info = StringVar() player2_or_AI = StringVar() def side_labels(): # info = StringVar() Label(root, text="BATTLESHIPS", fg="white", bg="gray19", font=font_big).grid(row=0, column=10, columnspan=9) Label(root, textvariable=info, fg="white", bg="gray19", font=font1).grid(row=12, column=6, columnspan=18) for _ in range(10): Label(root, text=" ", bg="gray19").grid(row=_, column=0) Button(root, width=7, height=1, text="1 Player", font=font1, fg="white", activebackground="gray19", bg="gray19", command=lambda: nr_players(1)).grid(row=2, column=1) Button(root, width=7, height=1, text="2 Players", font=font1, fg="white", activebackground="gray19", bg="gray19", command=lambda: nr_players(2)).grid(row=3, column=1) Label(root, text="Get 20 hits to win", font=font_normal, fg="white", bg="gray19").grid(row=5, column=1) Label(root, text="1 Battleship 4 units", font=font_normal, fg="white", bg="gray19").grid(row=6, column=1) Label(root, text="2 Battleships 3 units", font=font_normal, fg="white", bg="gray19").grid(row=7, column=1) Label(root, text="3 Battleships 2 units", font=font_normal, fg="white", bg="gray19").grid(row=8, column=1) Label(root, text="4 Battleships 1 unit ", font=font_normal, fg="white", bg="gray19").grid(row=9, column=1) for _ in range(10): Label(root, text=" ", bg="gray19").grid(row=_, column=2) for _ in range(10): Label(root, width=20, text=" ", bg="gray19").grid(row=_, column=25) def ai_shoots(y_coord, x_coord, all_buttons, player_1_board, ai_score): # print("yes") if ai_score == 20: popupwindow("The computer has won.") if player_1_board[y_coord][x_coord] == ': ': ai_score += 1 player_1_board[y_coord][x_coord] = 'X ' all_buttons[y_coord - 1][x_coord - 1].configure(text="X", fg="black", bg="red3") if player_1_board[y_coord - 1][x_coord] == ': ': ai_shoots(y_coord - 1, x_coord, all_buttons, player_1_board, ai_score) elif player_1_board[y_coord + 1][x_coord] == ': ': ai_shoots(y_coord + 1, x_coord, all_buttons, player_1_board, ai_score) elif player_1_board[y_coord][x_coord - 1] == ': ': ai_shoots(y_coord, x_coord - 1, all_buttons, player_1_board, ai_score) elif player_1_board[y_coord][x_coord + 1] == ': ': ai_shoots(y_coord, x_coord + 1, all_buttons, player_1_board, ai_score) else: x = random.randint(1, 10) y = random.randint(1, 10) ai_shoots(y, x, all_buttons, player_1_board, ai_score) elif player_1_board[y_coord][x_coord] == 'X ' or player_1_board[y_coord][x_coord] == 'O ': x = random.randint(1, 10) y = random.randint(1, 10) ai_shoots(y, x, all_buttons, player_1_board, ai_score) else: player_1_board[y_coord][x_coord] = 'O ' all_buttons[y_coord - 1][x_coord - 1].configure(text="O", fg="white") def hit_or_miss(a, b, board, all_buttons, info, player, player_1_hits, player_2_hits, ai_score): global AI # print(player) if board[a + 1][b + 1] == 'O ' or board[a + 1][b + 1] == 'X ': # Redan skjutit info.set("You have already fired there, " + player + "!") elif board[a + 1][b + 1] == ': ': # Träff info.set("A hit, nice shot " + player + "!") board[a + 1][b + 1] = 'X ' all_buttons[a][b].configure(text="X", fg="black", bg="red3", activebackground="red3") if player == "player 1": player_1_hits += 1 else: player_2_hits += 1 else: # Miss info.set("Seems like you missed that one, " + player + "!") board[a + 1][b + 1] = 'O ' all_buttons[a][b].configure(text="O", fg="White", activeforeground="white") # print(AI) if AI: x = random.randint(0, 10) y = random.randint(0, 10) ai_shoots(y, x, all_buttons, board, ai_score) if player_1_hits == 20 or player_2_hits == 20: popupwindow(player + " has won!") def side(player, allbuttons): print(player) if player == "player 1": for row in range(10): for column in range(10): allbuttons[row][column].grid(row=1 + row, column=4 + column) label2 = Label(root, text="Player 1", font=font1, fg="white", bg="gray19") label2.grid(row=11, column=4, columnspan=10) else: for row in range(10): for column in range(10): allbuttons[row][column].grid(row=1 + row, column=15 + column) label3 = Label(root, textvariable=player2_or_AI, font=font1, fg="white", bg="gray19") label3.grid(row=11, column=15, columnspan=10) def board_buttons(board, info, player, player_1_hits, player_2_hits, ai_score): allbuttons = [] a = 0 print(AI) for i in range(10): b = 0 buttons = [] for j in range(10): button = Button(root, width=2, height=1, font=font1, bg="sky blue", activebackground="sky blue", command=partial(hit_or_miss, a, b, board, allbuttons, info, player, player_1_hits, player_2_hits, ai_score)) buttons.append(button) b += 1 allbuttons.append(list(buttons)) a += 1 side(player, allbuttons) def middle_board_space(): for _ in range(10): Label(root, text=" ", bg="gray19").grid(row=1 + _, column=14) def main(): player_1_hits = 0 player_2_hits = 0 ai_hits = 0 player_1_board = player_board() player_2_board = player_board() place_all_ships(player_1_board) # Sätter ut alla skeppen place_all_ships(player_2_board) info = StringVar() side_labels() board_buttons(player_1_board, info, "player 1", player_1_hits, player_2_hits, ai_hits) middle_board_space() board_buttons(player_2_board, info, "player 2", player_1_hits, player_2_hits, ai_hits) main() root.mainloop() ############################################ RE: Battleships game in python with tkinter - ThiefOfTime - Sep-19-2018 Hi :) I had do use some different imports for Tkinter to get it running. The problem with the AI was that you passed ai_shoot the same board as you used for player_2. And on top of that the all_button array only holds the buttons from the field where it has been triggered. Since ai_shoot only is triggered when you click a button on the player_2 field, the buttons of that field are used. You can bypass this by using a global array where you store all buttons from both fields. After creation, the buttons of player_1 would be at the first index. You should consider blocking the click event on player_1 field while AI is ingame. Since clicking these buttons still work, they would trigger the AI as well. Objects are the most important part of python. You worked with some objects yourself while programming this game. You can imagine it that way: Objects are build out of classes, like an actual chair is build by using a blueprint. Since there are different kind of chairs, each chair may have different attributes. There are chairs without a back piece or chairs with just 3 legs. There are even chairs with wheels. In your case you could make your players as Objects of the player class. Each player has a score, a name, board and ships. The AI even has the right to act without a human. The overall board itself could be a class which has different methods like: hit_or_miss and attributes like all buttons and a width/height. This book is good and captures everything: http://books.tarsoit.com/Python%203%20Object-oriented%20Programming%20-%20Second%20Edition.pdf (19.09.2018) Though it is quite a lot if you need it asap :D Python2 and Python3 differ in some points but the important things you need right now are identical. These got the essentials: https://www.johnny-lin.com/pyintro/ed01/free_pdfs/ch07.pdf (19.09.2018) https://pdfs.semanticscholar.org/presentation/6ee1/add06c8938ed02a1b4a5d01515c234051677.pdf (19.09.2018) If I may, I would like to give you some programming tips: 1. ALWAYS comment in english. I know that it is quicker and easier to comment in you native language, but sharing the code is quite difficult. The guy on the other end of the screen has to find out what you did. Also not each symbol is used in each language. I for myself had the problem that your comments were not in ascii format. It is also great for improving english skills and writing english commands right away, if you want to work in the IT or CS field. 2. Do yourself a favour, and comment more ;) It is horrible to not look at your own code for some days and when you get back on it you have to figure out what you did. from Tkinter import * from tkFont import Font import tkMessageBox from functools import partial import random import time import sys import os root = Tk() root.wm_title("BATTLESHIPS") root.configure(background='gray19') font1 = Font(family='Helvetica', size=12, weight='bold') font_big = Font(family='Helvetica', size=16, weight='bold') font_normal = Font(family='Helvetica', size=10, weight='normal') ships = {"Aircraft Carrier": 4, "Battleship": 3, "Submarine": 2, "Destroyer": 1} AI = False def restart_program(): python = sys.executable os.execl(python, python, *sys.argv) def player_board(): board = [] t = [] t += (10 + 2) * ['# '] board.append(t) rad = ['# '] for r in range(0, 10): rad.append("~ ") rad.append('# ') for k in range(0, 10): board.append(list(rad)) board.append(t) return board def place_ship(ship, board): # w = 0 while True: checkcoords = [] x = random.randint(1, 10) y = random.randint(1, 10) o = random.randint(0, 1) if o == 0: ori = "v" # Vertikalt else: ori = "h" # Horisontellt if ori == "v" and y + ships[ship] > 10: pass # w = 0 elif ori == "h" and x + ships[ship] > 10: pass # w = 0 else: if ori == "v": for i in range(-1, (ships[ship] + 1)): for j in range(-1, 2): checkcoords.append(board[y + i][x + j]) if ': ' not in checkcoords: for i in range(ships[ship]): board[y + i][x] = ': ' break # else: # w = 0 elif ori == "h": for i in range(-1, (ships[ship] + 1)): for j in range(-1, 2): checkcoords.append(board[y + j][x + i]) if ': ' not in checkcoords: for i in range(ships[ship]): board[y][x + i] = ': ' break # else: # w = 0 def place_all_ships(board): for ship in ships: for antal in range(0, (5 - ships[ship])): place_ship(ship, board) def popupwindow(msg): answer = tkMessageBox.askquestion("Game Over", msg + " Would you like to play again?") if answer == "yes": restart_program() elif answer == "no": quit() def nr_players(number): global AI if number == 1: player2_or_AI.set("AI") AI = True else: player2_or_AI.set("Player 2") info = StringVar() player2_or_AI = StringVar() every_button = [] def side_labels(): # info = StringVar() Label(root, text="BATTLESHIPS", fg="white", bg="gray19", font=font_big).grid(row=0, column=10, columnspan=9) Label(root, textvariable=info, fg="white", bg="gray19", font=font1).grid(row=12, column=6, columnspan=18) for _ in range(10): Label(root, text=" ", bg="gray19").grid(row=_, column=0) Button(root, width=7, height=1, text="1 Player", font=font1, fg="white", activebackground="gray19", bg="gray19", command=lambda: nr_players(1)).grid(row=2, column=1) Button(root, width=7, height=1, text="2 Players", font=font1, fg="white", activebackground="gray19", bg="gray19", command=lambda: nr_players(2)).grid(row=3, column=1) Label(root, text="Get 20 hits to win", font=font_normal, fg="white", bg="gray19").grid(row=5, column=1) Label(root, text="1 Battleship 4 units", font=font_normal, fg="white", bg="gray19").grid(row=6, column=1) Label(root, text="2 Battleships 3 units", font=font_normal, fg="white", bg="gray19").grid(row=7, column=1) Label(root, text="3 Battleships 2 units", font=font_normal, fg="white", bg="gray19").grid(row=8, column=1) Label(root, text="4 Battleships 1 unit ", font=font_normal, fg="white", bg="gray19").grid(row=9, column=1) for _ in range(10): Label(root, text=" ", bg="gray19").grid(row=_, column=2) for _ in range(10): Label(root, width=20, text=" ", bg="gray19").grid(row=_, column=25) def ai_shoots(y_coord, x_coord, player_1_board, ai_score): # print("yes") if ai_score == 20: popupwindow("The computer has won.") if player_1_board[y_coord][x_coord] == ': ': ai_score += 1 player_1_board[y_coord][x_coord] = 'X ' every_button[0][y_coord - 1][x_coord - 1].configure(text="X", fg="black", bg="red3") if player_1_board[y_coord - 1][x_coord] == ': ': ai_shoots(y_coord - 1, x_coord, all_buttons, player_1_board, ai_score) elif player_1_board[y_coord + 1][x_coord] == ': ': ai_shoots(y_coord + 1, x_coord, all_buttons, player_1_board, ai_score) elif player_1_board[y_coord][x_coord - 1] == ': ': ai_shoots(y_coord, x_coord - 1, all_buttons, player_1_board, ai_score) elif player_1_board[y_coord][x_coord + 1] == ': ': ai_shoots(y_coord, x_coord + 1, all_buttons, player_1_board, ai_score) else: x = random.randint(1, 10) y = random.randint(1, 10) ai_shoots(y, x, all_buttons, player_1_board, ai_score) elif player_1_board[y_coord][x_coord] == 'X ' or player_1_board[y_coord][x_coord] == 'O ': x = random.randint(1, 10) y = random.randint(1, 10) ai_shoots(y, x, all_buttons, player_1_board, ai_score) else: player_1_board[y_coord][x_coord] = 'O ' every_button[0][y_coord - 1][x_coord - 1].configure(text="O", fg="white") def hit_or_miss(a, b, board, all_buttons, info, player, player_1_hits, player_2_hits, ai_score, board2): global AI # print(player) if board[a + 1][b + 1] == 'O ' or board[a + 1][b + 1] == 'X ': info.set("You have already fired there, " + player + "!") elif board[a + 1][b + 1] == ': ': info.set("A hit, nice shot " + player + "!") board[a + 1][b + 1] = 'X ' all_buttons[a][b].configure(text="X", fg="black", bg="red3", activebackground="red3") if player == "player 1": player_1_hits += 1 else: player_2_hits += 1 else: # Miss info.set("Seems like you missed that one, " + player + "!") board[a + 1][b + 1] = 'O ' all_buttons[a][b].configure(text="O", fg="White", activeforeground="white") # print(AI) if AI: x = random.randint(0, 10) y = random.randint(0, 10) ai_shoots(y, x, board2, ai_score) if player_1_hits == 20 or player_2_hits == 20: popupwindow(player + " has won!") def side(player, allbuttons): print(player) if player == "player 1": for row in range(10): for column in range(10): allbuttons[row][column].grid(row=1 + row, column=4 + column) label2 = Label(root, text="Player 1", font=font1, fg="white", bg="gray19") label2.grid(row=11, column=4, columnspan=10) else: for row in range(10): for column in range(10): allbuttons[row][column].grid(row=1 + row, column=15 + column) label3 = Label(root, textvariable=player2_or_AI, font=font1, fg="white", bg="gray19") label3.grid(row=11, column=15, columnspan=10) def board_buttons(board, info, player, player_1_hits, player_2_hits, ai_score, board2): allbuttons = [] a = 0 print(AI) for i in range(10): b = 0 buttons = [] for j in range(10): button = Button(root, width=2, height=1, font=font1, bg="sky blue", activebackground="sky blue", command=partial(hit_or_miss, a, b, board, allbuttons, info, player, player_1_hits, player_2_hits, ai_score, board2)) buttons.append(button) b += 1 allbuttons.append(list(buttons)) a += 1 every_button.append(allbuttons) side(player, allbuttons) def middle_board_space(): for _ in range(10): Label(root, text=" ", bg="gray19").grid(row=1 + _, column=14) def main(): player_1_hits = 0 player_2_hits = 0 ai_hits = 0 player_1_board = player_board() player_2_board = player_board() place_all_ships(player_1_board) place_all_ships(player_2_board) info = StringVar() side_labels() board_buttons(player_1_board, info, "player 1", player_1_hits, player_2_hits, ai_hits, player_2_board) middle_board_space() board_buttons(player_2_board, info, "player 2", player_1_hits, player_2_hits, ai_hits, player_1_board) main() root.mainloop() RE: Battleships game in python with tkinter - ichabod801 - Sep-19-2018 If you going to do a GUI you definitely need classes. For games, classes are also very good. For my Battleships game, I have a class for the players and one for the boards. There are some basic class tutorials on the board, see the link in my signature below. RE: Battleships game in python with tkinter - Togeh - Sep-20-2018 @ThiefOfTimes Hi, I've been trying to implement the tips you gave me but to no avail. How would you do it? RE: Battleships game in python with tkinter - ThiefOfTime - Sep-20-2018 This is how I would do it, using your code. Although the game can not be ended by winning right now. Wrapping your code into classes would mean to refactor your complete code. I'm sorry that I am not doing this now. Grab the books (contained in the links I send) and explore classes and objects. Then I would pack all players (AI as well) in one class and the boards into one class. You can also create a class for the battle ships since they share some attributes. I would create the player_boards in the __init__ method of the board class and save them in variables/attributes. Also create the player objects there. Then take a look which methods fit in which class. Maybe start creating the player class since it would be the smallest :) from Tkinter import * from tkFont import Font import tkMessageBox from functools import partial import random import time import sys import os root = Tk() root.wm_title("BATTLESHIPS") root.configure(background='gray19') font1 = Font(family='Helvetica', size=12, weight='bold') font_big = Font(family='Helvetica', size=16, weight='bold') font_normal = Font(family='Helvetica', size=10, weight='normal') ships = {"Aircraft Carrier": 4, "Battleship": 3, "Submarine": 2, "Destroyer": 1} AI = False def restart_program(): ''' This method restarts the game script ''' python = sys.executable os.execl(python, python, *sys.argv) def player_board(): """ generating a 2 dimensional array representing one players board :return: two dimensional list """ board = [] t = [] # creating the upper bounder t += (10 + 2) * ['# '] board.append(t) # creating one line in the board rad = ['# '] for r in range(0, 10): rad.append("~ ") # inserting the new line into the board rad.append('# ') for k in range(0, 10): board.append(list(rad)) # inserting the lower bounder board.append(t) return board def place_ship(ship, board): """ place ship onto given board :param ship: given ships name :param board: board of given player """ # w = 0 while True: checkcoords = [] x = random.randint(1, 10) y = random.randint(1, 10) o = random.randint(0, 1) if o == 0: ori = "v" # vertical else: ori = "h" # horizontal # if ship would be placed outside of the board skip if (ori == "v" and y + ships[ship] > 10) or (ori == "h" and x + ships[ship] > 10): pass # w = 0 else: if ori == "v": # vertical placement # if no ship is near this position place it for i in range(-1, (ships[ship] + 1)): for j in range(-1, 2): checkcoords.append(board[y + i][x + j]) if ': ' not in checkcoords: for i in range(ships[ship]): board[y + i][x] = ': ' break # else: # w = 0 elif ori == "h": # horizontal placement # if no ship is near this position place it for i in range(-1, (ships[ship] + 1)): for j in range(-1, 2): checkcoords.append(board[y + j][x + i]) if ': ' not in checkcoords: for i in range(ships[ship]): board[y][x + i] = ': ' break # else: # w = 0 def place_all_ships(board): """ Place all ships on the given board :param board: given player board """ for ship in ships: for _ in range(0, (5 - ships[ship])): place_ship(ship, board) def popupwindow(msg): """ Pop up window if game is over :param msg: player name """ answer = tkMessageBox.askquestion("Game Over", msg + " Would you like to play again?") if answer == "yes": restart_program() elif answer == "no": quit() def nr_players(number): """ Set number of players :param number: number of needed players """ global AI # activate player2 Buttons for bt_list in every_button[1]: for bt in bt_list: bt['state'] = 'normal' # if one player is needed activate AI if number == 1: player2_or_AI.set("AI") AI = True else: # activate player2 Buttons for bt_list in every_button[0]: for bt in bt_list: bt['state'] = 'normal' player2_or_AI.set("Player 2") info = StringVar() player2_or_AI = StringVar() every_button = [] def side_labels(): """ Create Buttons and Labels for the field """ # info = StringVar() Label(root, text="BATTLESHIPS", fg="white", bg="gray19", font=font_big).grid(row=0, column=10, columnspan=9) Label(root, textvariable=info, fg="white", bg="gray19", font=font1).grid(row=12, column=6, columnspan=18) for _ in range(10): Label(root, text=" ", bg="gray19").grid(row=_, column=0) Button(root, width=7, height=1, text="1 Player", font=font1, fg="white", activebackground="gray19", bg="gray19", command=lambda: nr_players(1)).grid(row=2, column=1) Button(root, width=7, height=1, text="2 Players", font=font1, fg="white", activebackground="gray19", bg="gray19", command=lambda: nr_players(2)).grid(row=3, column=1) Label(root, text="Get 20 hits to win", font=font_normal, fg="white", bg="gray19").grid(row=5, column=1) Label(root, text="1 Battleship 4 units", font=font_normal, fg="white", bg="gray19").grid(row=6, column=1) Label(root, text="2 Battleships 3 units", font=font_normal, fg="white", bg="gray19").grid(row=7, column=1) Label(root, text="3 Battleships 2 units", font=font_normal, fg="white", bg="gray19").grid(row=8, column=1) Label(root, text="4 Battleships 1 unit ", font=font_normal, fg="white", bg="gray19").grid(row=9, column=1) for _ in range(10): Label(root, text=" ", bg="gray19").grid(row=_, column=2) for _ in range(10): Label(root, width=20, text=" ", bg="gray19").grid(row=_, column=25) def ai_shoots(y_coord, x_coord, player_1_board, ai_score): """ AI shooting method :param y_coord: y coordinate to shoot at :param x_coord: x coordinate to shoot at :param player_1_board: board to shoot at :param ai_score: score of AI """ # if score is 20, AI has won if ai_score == 20: popupwindow("The computer has won.") # if AI got one hit, destroy complete ship if player_1_board[y_coord][x_coord] == ': ': ai_score += 1 player_1_board[y_coord][x_coord] = 'X ' every_button[0][y_coord - 1][x_coord - 1].configure(text="X", fg="black", bg="red3") # depending of where the rest of the ship is located, shot it if player_1_board[y_coord - 1][x_coord] == ': ': ai_shoots(y_coord - 1, x_coord, player_1_board, ai_score) elif player_1_board[y_coord + 1][x_coord] == ': ': ai_shoots(y_coord + 1, x_coord, player_1_board, ai_score) elif player_1_board[y_coord][x_coord - 1] == ': ': ai_shoots(y_coord, x_coord - 1, player_1_board, ai_score) elif player_1_board[y_coord][x_coord + 1] == ': ': ai_shoots(y_coord, x_coord + 1, player_1_board, ai_score) else: # shot some random position if ship is destroyed x = random.randint(1, 10) y = random.randint(1, 10) ai_shoots(y, x, player_1_board, ai_score) elif player_1_board[y_coord][x_coord] == 'X ' or player_1_board[y_coord][x_coord] == 'O ': # if position was already shoot at, try a new position x = random.randint(1, 10) y = random.randint(1, 10) ai_shoots(y, x, player_1_board, ai_score) else: # if water was hit just change the button player_1_board[y_coord][x_coord] = 'O ' every_button[0][y_coord - 1][x_coord - 1].configure(text="O", fg="white") def hit_or_miss(a, b, board, all_buttons, info, player, player_1_hits, player_2_hits, ai_score, board2): """ check if there was a hit or a missed done by the player :param a: clicked y position :param b: clicked x position :param board: opponents player board :param all_buttons: all buttons of the opponent board :param info: write some info to the screen :param player: player name :param player_1_hits: number of player_1_hits :param player_2_hits: number of player_2_hits :param ai_score: number of AI hits :param board2: own players board """ global AI # if a already hit place was clicked again write message if board[a + 1][b + 1] == 'O ' or board[a + 1][b + 1] == 'X ': info.set("You have already fired there, " + player + "!") elif board[a + 1][b + 1] == ': ': # if a ship was hit change the button and the players board info.set("A hit, nice shot " + player + "!") board[a + 1][b + 1] = 'X ' all_buttons[a][b].configure(text="X", fg="black", bg="red3", activebackground="red3") # increase the hit counter and go again if player == "player 1": player_1_hits += 1 else: player_2_hits += 1 else: # in case of a miss change the button and trigger the AI info.set("Seems like you missed that one, " + player + "!") board[a + 1][b + 1] = 'O ' all_buttons[a][b].configure(text="O", fg="White", activeforeground="white") # print(AI) if AI: x = random.randint(0, 10) y = random.randint(0, 10) ai_shoots(y, x, board2, ai_score) if player_1_hits == 20 or player_2_hits == 20: # if one player got 20 hits he won popupwindow(player + " has won!") def side(player, allbuttons): """ order the buttons of each player into a grid :param player: players name :param allbuttons: all buttons of this player """ print(player) col = 4 if player == "player 1" else 15 for row in range(10): for column in range(10): allbuttons[row][column].grid(row=1 + row, column=col + column) if player == "player 1": label2 = Label(root, text="Player 1", font=font1, fg="white", bg="gray19") label2.grid(row=11, column=4, columnspan=10) else: label3 = Label(root, textvariable=player2_or_AI, font=font1, fg="white", bg="gray19") label3.grid(row=11, column=15, columnspan=10) def board_buttons(board, info, player, player_1_hits, player_2_hits, ai_score, board2): """ create all buttons for one player :param board: players board :param info: writing info to the screen :param player: players name :param player_1_hits: number of player 1 hits :param player_2_hits: number of player 2 hits :param ai_score: AI score :param board2: opponents board """ allbuttons = [] a = 0 print(AI) for i in range(10): b = 0 buttons = [] for j in range(10): button = Button(root, width=2, height=1, font=font1, bg="sky blue", activebackground="sky blue", command=partial(hit_or_miss, a, b, board, allbuttons, info, player, player_1_hits, player_2_hits, ai_score, board2), state="disable") buttons.append(button) b += 1 # create a 2 dimensional array with buttons representing the battle field allbuttons.append(list(buttons)) a += 1 # store each button matrix in a list for later and global access every_button.append(allbuttons) side(player, allbuttons) def middle_board_space(): """ Insert the middel space """ for _ in range(10): Label(root, text=" ", bg="gray19").grid(row=1 + _, column=14) def main(): """ primary game method """ player_1_hits = 0 player_2_hits = 0 ai_hits = 0 # initialize the player boards player_1_board = player_board() player_2_board = player_board() # place all ships on the boards place_all_ships(player_1_board) place_all_ships(player_2_board) # instert side labels info = StringVar() side_labels() # create the buttons board_buttons(player_1_board, info, "player 1", player_1_hits, player_2_hits, ai_hits, player_2_board) middle_board_space() board_buttons(player_2_board, info, "player 2", player_1_hits, player_2_hits, ai_hits, player_1_board) main() root.mainloop() RE: Battleships game in python with tkinter - Togeh - Sep-26-2018 @ThiefOfTimes Hi,sorry for asking you over and over. I have read about classes in the books you linked and I think I have a fair understanding now, but I can't figure out how to "translate" my specific code into classes. I've been going at this for days now and I make little to no progress. Could you take a bit of my code and make it into a class (for example the board or something) so I can see and example? With that I could probably figure the rest out. Thanks a bunch. RE: Battleships game in python with tkinter - ThiefOfTime - Sep-26-2018 Yeah sure, no problem mate :) I think the players are great examples. Player: class Player: def __init__(self, board, ships): self.board = board self.op_board = list(board) self.ships = ships self.counter = 0 sef inc_counter(self): self.counter += 1 def place_ships(self): """ Place all ships on the given board """ for ship in self.ships: for _ in range(0, (5 - ships[ship])): while True: checkcoords = [] x = random.randint(1, 10) y = random.randint(1, 10) o = random.randint(0, 1) if o == 0: ori = "v" # vertical else: ori = "h" # horizontal # if ship would be placed outside of the board skip if (ori == "v" and y + self.ships[ship] > 10) or (ori == "h" and x + self.ships[ship] > 10): pass else: if ori == "v": # vertical placement # if no ship is near this position place it for i in range(-1, (self.ships[ship] + 1)): for j in range(-1, 2): checkcoords.append(board[y + i][x + j]) if ': ' not in checkcoords: for i in range(self.ships[ship]): self.board[y + i][x] = ': ' break elif ori == "h": # horizontal placement # if no ship is near this position place it for i in range(-1, (self.ships[ship] + 1)): for j in range(-1, 2): checkcoords.append(self.board[y + j][x + i]) if ': ' not in checkcoords: for i in range(self.ships[ship]): self.board[y][x + i] = ': ' break def get_board(self): return self.board def hit_or_miss(self, a, b, all_buttons, info): """ check if there was a hit or a missed done by the player :param a: clicked y position :param b: clicked x position :param all_buttons: all buttons of the opponent board :param info: write some info to the screen """ global AI # if a already hit place was clicked again write message if self.board[a + 1][b + 1] == 'O ' or self.board[a + 1][b + 1] == 'X ': info.set("You have already fired there, " + player + "!") return 0 elif self.board[a + 1][b + 1] == ': ': # if a ship was hit change the button and the players board info.set("A hit, nice shot " + player + "!") all_buttons[a][b].configure(text="X", fg="black", bg="red3", activebackground="red3") return 1 else: # in case of a miss change the button and trigger the AI info.set("Seems like you missed that one, " + player + "!") all_buttons[a][b].configure(text="O", fg="White", activeforeground="white") return 2 class AI(Player): def __init__(self, opponent, board, ships): super(AI,self).__init__(board,ships) self.opponent = opponent def shoot(self, every_button, info, x_s=None, y_s=None): if x_s is None or y_s is None: x = random.randint(0, 10) y = random.randint(0, 10) else: x = x_s y = y_s # if AI got one hit, destroy complete ship if self.opponent.hit_or_miss(y, x, every_button, info) == 1: self.inc_score() every_button[0][y- 1][x - 1].configure(text="X", fg="black", bg="red3") # depending of where the rest of the ship is located, shot it if self.opponent.getBoard()[y - 1][x] == ': ': ai_shoots(every_button, info, y - 1, x) elif self.opponent.getBoard()[y + 1][x] == ': ': ai_shoots(every_button, info, y + 1, x) elif player_1_board[y_coord][x_coord - 1] == ': ': ai_shoots(every_button, info, y, x - 1) elif player_1_board[y_coord][x_coord + 1] == ': ': ai_shoots(every_button, info, y, x + 1) else: # shot some random position if ship is destroyed x = random.randint(1, 10) y = random.randint(1, 10) ai_shoots(every_button, info, y, x) elif self.opponent.hit_or_miss(y, x, every_button, info) == 0: # if position was already shoot at, try a new position x = random.randint(1, 10) y = random.randint(1, 10) ai_shoots(every_button, info, y, x) else: # if water was hit just change the button every_button[0][y - 1][x - 1].configure(text="O", fg="white")I hope I haven't forgot anything, the problem is, that I can't test it right now. But this is an example of how the players could be implemented as classes accourding to your code. Note that the way you used the methods before has changed a little bit and there still can be made adjustments. Hope this example helps :) The next step would be the board. |