from tkinter import *
import random
tk = Tk()
tk.wm_title("Battleship")
switch = True
game_over = False
labels = []
class player:
def __init__(self):
self.switchuser = False
self.placedships = []
self.bombed = []
self.sunk = []
self.ship_sizes = [5, 4, 3, 3, 2]
self.direction = 'v'
self.player_ocean = []
temp = []
for i in range(10):
for y in range(10):
temp += [0]
self.player_ocean += [temp]
temp = []
self.selectedCoord = [0, 0] # [0] = x coord, [1] = y coord
self.attack_selection = [0, 0]
self.hits = []
self.misses = []
def selectPlacement(self, event, key):
'''
initialise column and row index
condition for different directions
check if ship placed is off grid or clashes with another ship
place ship
add to self.placedships
remove ship from availiable ships to cycle to next ship
'''
clear = True
col = self.selectedCoord[0]
row = self.selectedCoord[1]
print(self.selectedCoord)
if self.direction == 'v':
v_range_start = row - self.ship_sizes[0] + 1
if v_range_start >= 0: # check if ship will be off the grid
for cell in range(v_range_start, row + 1): # check if the ship clashes with existing ships
if [cell, col] in self.placedships:
clear = False
break
if clear == True:
for y in range(v_range_start, row + 1):
self.player_ocean[y][col] = 1
self.placedships.append([y, col])
self.ship_sizes.remove(self.ship_sizes[0])
refresh_ocean('place')
elif self.direction == 'h':
h_range_end = col + self.ship_sizes[0]
if 10 > h_range_end:
for cell in range(col, h_range_end):
if [row, cell] in self.placedships:
clear = False
break
if clear == True:
for x in range(col, h_range_end):
self.player_ocean[row][x] = 1
self.placedships.append([row, x])
self.ship_sizes.remove(self.ship_sizes[0])
refresh_ocean('place')
def selectAttack(self, event):
col = self.attack_selection[0]
row = self.attack_selection[1]
if [row, col] in ai.ai_placedships:
if [row, col] not in self.hits:
self.hits.append([row, col])
print('hit')
else:
if [row, col] not in self.misses:
self.misses.append([row, col])
# if str(type(event)) == 'tkinter.Event':
# return True
refresh_ocean('attackselection')
ai.ai_attack()
# forming tkinter window
def baseGrid():
gridLabel_player = Label(tk,
text="Your grid \nA B C D E F G H I J ")
gridLabel_player.grid(row=0, column=0)
gridLabel_ai = Label(tk,
text="AI's grid \nA B C D E F G H I J ")
gridLabel_ai.grid(row=0, column=1)
tk.player_canvas = Canvas(tk, height=300, width=300, highlightbackground='black', highlightthickness=0.5)
tk.ai_canvas = Canvas(tk, height=300, width=300, highlightbackground='black', highlightthickness=0.5)
tk.player_canvas.grid(row=1, column=0, padx=50)
tk.ai_canvas.grid(row=1, column=1, padx=50)
for x in range(10):
for y in range(10):
tk.player_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')
tk.ai_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')
def moveShip(event, key):
print(player1.selectedCoord)
if event.keysym == 'Down':
if key == 'place':
if player1.selectedCoord[1] != 9:
player1.selectedCoord[1] += 1
elif key == 'attackselection':
if player1.attack_selection[1] != 9:
player1.attack_selection[1] += 1
elif event.keysym == 'Up':
if key == 'place':
if player1.selectedCoord[1] != 0:
player1.selectedCoord[1] -= 1
elif key == 'attackselection':
if player1.attack_selection[1] != 0:
player1.attack_selection[1] -= 1
elif event.keysym == 'Left':
if key == 'place':
if player1.selectedCoord[0] != 0:
player1.selectedCoord[0] -= 1
elif key == 'attackselection':
if player1.attack_selection[0] != 0:
player1.attack_selection[0] -= 1
elif event.keysym == 'Right':
if key == 'place':
if player1.selectedCoord[0] != 9:
player1.selectedCoord[0] += 1
elif key == 'attackselection':
if player1.attack_selection[0] != 9:
player1.attack_selection[0] += 1
for y in range(10):
for x in range(10):
if key == 'place':
if [y, x] == player1.selectedCoord or [x, y] in player1.placedships:
player1.player_ocean[x][y] = 1
else:
player1.player_ocean[x][y] = 0
# elif key == 'attackselection':
# if [y,x] == player1.attack_selection or [x,y] in player1.hits:
# ai.ai_ocean[x][y] = 1
# else:
# ai.ai_ocean[x][y] = 0
refresh_ocean(key)
def changedir(event):
if player1.direction == 'v':
player1.direction = 'h'
elif player1.direction == 'h':
player1.direction = 'v'
def refresh_ocean(key):
print('function call')
for y in range(10):
for x in range(10):
colour = 'white'
if key == 'place':
if [y, x] in player1.placedships:
colour = 'green'
if [x, y] == player1.selectedCoord:
colour = 'yellow'
tk.player_canvas.itemconfig(
tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30, fill=colour))
elif key == 'attackselection':
# print('miss',ai.AI_miss,'\nhits',ai.destroyed_cords,'\nships',player1.placedships)
if [y, x] in player1.placedships:
tk.player_canvas.itemconfig(
tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30), fill='green')
if [y, x] in ai.AI_miss:
tk.player_canvas.itemconfig(
tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30), fill='gray')
if [y, x] in ai.destroyed_cords:
tk.player_canvas.itemconfig(
tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30), fill='red')
if [y, x] in player1.hits:
colour = 'red'
if [y, x] in player1.misses:
colour = 'gray'
if [x, y] == player1.attack_selection:
colour = 'yellow'
tk.ai_canvas.itemconfig(
tk.ai_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30), fill=colour)
# else:
# tk.player_canvas.itemconfig(
# tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30, fill='white'))
def attackGui():
tk.bind("<Key>", lambda event: moveShip(event, 'attackselection'))
tk.bind("<Return>", lambda event: player1.selectAttack(event))
class Ai(player):
def __init__(self):
# = [[[9,0], [9, 1], [9, 2], [9, 3], [9, 4]], [[9, 5], [9, 6]]]
# player1.placedships = [[[9, 0], [8, 0], [7, 0], [6, 0], [5, 0]], [[4, 0], [3, 0]]]
self.destroyed_ships = []
self.destroyed_cords = []
self.AI_miss = []
self.fmove_check = True
self.mdirection = 1
self.ai_placedships = []
self.directions = ['v', 'h']
self.ship_sizes = [5, 4, 3, 3, 2]
self.currentcoord = [0,0]
def ai_attack(self):
def first_move(self):
self.missed = 0
self.AIx = random.randint(0, 9)
self.AIy = random.randint(0, 9)
self.AIsel_cords = [self.AIy, self.AIx]
while self.AIsel_cords in self.AI_miss or self.AIsel_cords in self.destroyed_cords:
self.AIx = random.randint(0, 9)
self.AIy = random.randint(0, 9)
self.AIsel_cords = [self.AIy, self.AIx]
self.currentcoord = self.AIsel_cords
if self.AIsel_cords in player1.placedships:
# self.ship_check = ship
self.destroyed_cords.append(player1.placedships.pop(player1.placedships.index(self.AIsel_cords)))
self.fmove_check = False
else:
self.AI_miss.append(self.AIsel_cords)
def fol_move(self):
checked = False
self.entered = False
# direction check
if self.mdirection > 4:
self.mdirection = 1
# up
elif self.mdirection == 1 and self.AIy - 1 >= 0:
self.entered = True
self.AIy -= 1
self.currentcoord[0] -= 1
# to find whether the cords are part of a ship
if [self.AIy, self.AIx] in player1.placedships:
# if [self.AIx, self.AIy] in self.ship_check:
# self.destroyed_cords.append(ship.pop(ship.index([self.AIx, self.AIy])))
# else:
# self.destroyed_cords +=
self.destroyed_cords.append(
player1.placedships.pop(player1.placedships.index([self.AIy, self.AIx])))
checked = True
# add the cords that are not part of a ship into AI_miss
else:
self.AI_miss.append([self.AIy, self.AIx])
self.AIy, self.AIx = self.AIsel_cords[0], self.AIsel_cords[1]
self.mdirection += 1
self.missed += 1
# left
elif self.mdirection == 2 and self.AIx - 1 >= 0:
self.entered = True
self.AIx -= 1
self.currentcoord[1] -= 1
# to find whether the cords are part of a ship
if [self.AIy, self.AIx] in player1.placedships:
self.destroyed_cords.append(
player1.placedships.pop(player1.placedships.index([self.AIy, self.AIx])))
checked = True
# add the cords that are not part of a ship into AI_miss
else:
self.AI_miss.append([self.AIy, self.AIx])
self.AIy, self.AIx = self.AIsel_cords[0], self.AIsel_cords[1]
self.mdirection += 1
self.missed += 1
# down
elif self.mdirection == 3 and self.AIy + 1 <= 9:
self.entered = True
self.AIy += 1
self.currentcoord[0] += 1
# to find whether the cords are part of a ship
if [self.AIy, self.AIx] in player1.placedships:
self.destroyed_cords.append(
player1.placedships.pop(player1.placedships.index([self.AIy, self.AIx])))
checked = True
# add the cords that are not part of a ship into AI_miss
else:
self.AI_miss.append([self.AIy, self.AIx])
self.AIy, self.AIx = self.AIsel_cords[0], self.AIsel_cords[1]
self.mdirection += 1
self.missed += 1
# right
elif self.mdirection == 4 and self.AIx + 1 <= 9:
self.entered = True
self.AIx += 1
self.currentcoord[1] += 1
# to find whether the cords are part of a ship
if [self.AIy, self.AIx] in player1.placedships:
self.destroyed_cords.append(
player1.placedships.pop(player1.placedships.index([self.AIy, self.AIx])))
checked = True
# add the cords that are not part of a ship into AI_miss
else:
self.AI_miss.append([self.AIy, self.AIx])
self.AIy, self.AIx = self.AIsel_cords[0], self.AIsel_cords[1]
self.mdirection += 1
self.missed += 1
elif not self.entered:
self.AIy, self.AIx = self.AIsel_cords[0], self.AIsel_cords[1]
self.mdirection += 1
if self.missed == 2:
self.missed = 0
self.fmove_check = True
if self.fmove_check:
first_move(self)
elif not self.fmove_check:
fol_move(self)
if not self.entered:
fol_move(self)
# print('\n', self.destroyed_cords)
# print(player1.placedships)
# print(self.AI_miss)
def ai_place(self):
print(len(ai.ship_sizes))
ai_dir = random.choice(self.directions)
col = random.randint(0, 9)
row = random.randint(0, 9)
clear = True
if ai_dir == 'v':
v_range_start = row - self.ship_sizes[0] + 1
if v_range_start >= 0: # check if ship will be off the grid
for cell in range(v_range_start, row + 1): # check if the ship clashes with existing ships
if [cell, col] in self.ai_placedships:
clear = False
break
if clear == True:
for y in range(v_range_start, row + 1):
self.ai_placedships.append([y, col])
self.ship_sizes.remove(self.ship_sizes[0])
elif ai_dir == 'h':
h_range_end = col + self.ship_sizes[0]
if 10 > h_range_end:
for cell in range(col, h_range_end):
if [row, cell] in self.ai_placedships:
clear = False
break
if clear == True:
for x in range(col, h_range_end):
self.ai_placedships.append([row, x])
self.ship_sizes.remove(self.ship_sizes[0])
attackinstructionLabel = Label(tk, text="Arrow keys to move selection"
"\nEnter to shoot at selected cell"
"\nGrey cells are missed ships"
"\nRed cells are hit ships")
attackinstructionLabel.grid(row=2)
instructionLabel = Label(tk, text="Arrow keys to move selection"
"\nRight shift to change ship orientation"
"\nEnter to place ship"
"\nYellow cells means that you are selecting a cell to place the next ship in"
"\nGreen cells show placed ships")
instructionLabel.grid(row=2)
tk.bind("<Key>", lambda event: moveShip(event, 'place'))
tk.bind("<Shift_R>", changedir)
tk.bind("<Return>", lambda event: player1.selectPlacement(event, 'place'))
base = baseGrid()
player1 = player()
ai = Ai()
while True:
tk.update()
tk.update_idletasks()
if len(player1.ship_sizes) != 0:
if len(ai.ship_sizes) != 0:
ai_place = ai.ai_place()
refresh_ocean('place')
else:
if (sorted(player1.hits) != sorted(ai.ai_placedships)) and len(player1.placedships) != 0:
attack = attackGui()
instructionLabel.destroy()
refresh_ocean('attackselection')
else:
popup = Tk()
p_label = Label(popup,text='GAME OVER')
popup.after(5000,p_label.destroy())
tk.destroy()
我尝试取出在while循环中运行的所有代码,这些代码在程序中创建了其他内容,但仍然明显滞后。我现在唯一可以识别的问题可能是refresh_ocean
函数,它是在while循环中处理gui的唯一事物,但是它使用了itemconfig方法,该方法不应在gui <上添加任何内容/ p>
答案 0 :(得分:0)
我认为您正在使用:
tk.player_canvas.itemconfig不好。
tk.player_canvas.itemconfig(
tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30), fill='green')
您正在创建越来越多的矩形。 这是我在tkinter画布上处理网格的常用方法
grid = [[0 for x in range(10)] for y in range(10)]
for x in range(10):
for y in range(10):
grid[x][y] = tk.player_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')
tk.player_canvas.itemconfig( grid[x][y], fill="blue")