why is my tkinter window getting laggier as time passes - python

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()
i tried taking out all the code run during the while loop that creates additional things in the program but it still gets noticeably laggy. the only thing i can identify right now which may be the problem is the refresh_ocean function which is the only thing that deals with the gui in the while loop but it uses the itemconfig method which shouldnt add on anything to the gui

I think you are using:
tk.player_canvas.itemconfig in bad way.
tk.player_canvas.itemconfig(
tk.player_canvas.create_rectangle(x * 30, y * 30, (x + 1) * 30, (y + 1) * 30), fill='green')
You are creating more and more rectangles.
This is my usual way of handling an a grid on tkinter canvas
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")

Related

Mapping Grid Position To Matrix Position

I needed help, I was trying to map the position of a ghost in its current position such as (225, 175) to its position on the matrix (7,9), not sure what the math is to calculate its relative position, the reason why im asking is because it makes it easier to detect if theres a wall in matrix position as opposed to current position. I want to be able to do this so I can decide its next move at an intersection.
import pygame
import time
import random
import pickle
import math
pygame.init()
pygame.mixer.init()
pygame.display.set_caption("Pac-Man")
# Sets the size of the screen via (WIDTH, HEIGHT)
SCREEN_WIDTH = 478
SCREEN_HEIGHT = 608
# Speed of Characters
SPEED = 1
# Frames per second, how fast the game runs
FPS = 50
# Colors (RED,GREEN,BLUE)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
YELLOW = (255, 255, 0)
BLUE = (0, 0, 255)
# Sets the WIDTH and HEIGHT of the window
WINDOW = (SCREEN_WIDTH, SCREEN_HEIGHT)
# Displays the screen
SCREEN = pygame.display.set_mode(WINDOW)
CLOCK = pygame.time.Clock()
PacManStartSurface = pygame.transform.scale(pygame.image.load
("PacManStart.png"), (23, 23))
PacManStartSurface.convert()
PacManStartRect = PacManStartSurface.get_rect(topleft =
(((SCREEN_WIDTH - 25) // 2),
(SCREEN_HEIGHT + 144) // 2))
PacManSurface = pygame.transform.scale(pygame.image.load
("PacManRight.png"), (23, 23))
PacManSurface.convert()
PacManRect = PacManStartSurface.get_rect(topleft =
(((SCREEN_WIDTH - 125) // 2),
(SCREEN_HEIGHT + 144) // 2))
CurrentSurface = PacManStartSurface
CurrentRect = PacManStartRect
BackgroundSurface = pygame.image.load("Background.png").convert()
PinkGhostSurface = pygame.transform.scale(pygame.image.load("PinkGhost.png")
.convert(), (23, 23))
PinkGhostRect = PinkGhostSurface.get_rect()
YellowGhostSurface = pygame.transform.scale(pygame.image.load
("YellowGhost.png")
.convert(), (23, 23))
YellowGhostRect = YellowGhostSurface.get_rect()
RedGhostSurface = pygame.transform.scale(pygame.image.load("RedGhost.png")
.convert(), (23, 23))
RedGhostRect = RedGhostSurface.get_rect()
BlueGhostSurface = pygame.transform.scale(pygame.image.load("BlueGhost.png")
.convert(), (23, 23))
BlueGhostRect = BlueGhostSurface.get_rect()
pygame.mixer.music.load('power_pellet.wav')
Font = pygame.font.Font("emulogic.ttf", 15)
class PacMan():
def __init__(self):
self.LIVES = 3
class Maze():
def __init__(self):
self.DOTS = []
self.WALLS = []
self.ENERGIZER = []
self.GHOSTS = []
self.WALLS_XY = []
self.BLOCK_WIDTH = 25
self.BLOCK_HEIGHT = 25
self.MAZE_OFFSET_X = 0
self.MAZE_OFFSET_Y = 50
# 0 - Dots
# 1 - Walls
# 2 - Empty Spaces
# 3 - Energizers
# 4 - Ghosts
self.MATRIX = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], \
[1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1], \
[1,3,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,3,1], \
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], \
[1,0,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,0,1], \
[1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1], \
[1,1,1,1,0,1,1,1,2,1,2,1,1,1,0,1,1,1,1], \
[2,2,2,1,0,1,2,2,2,4,2,2,2,1,0,1,2,2,2], \
[1,1,1,1,0,1,2,1,1,1,1,1,2,1,0,1,1,1,1], \
[0,0,0,0,0,2,2,1,4,4,4,1,2,2,0,0,0,0,0], \
[1,1,1,1,0,1,2,1,1,1,1,1,2,1,0,1,1,1,1], \
[2,2,2,1,0,1,2,2,2,2,2,2,2,1,0,1,2,2,2], \
[1,1,1,1,0,1,2,1,1,1,1,1,2,1,0,1,1,1,1], \
[1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1], \
[1,3,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,3,1], \
[1,0,0,1,0,0,0,0,0,2,0,0,0,0,0,1,0,0,1], \
[1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1], \
[1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1], \
[1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1], \
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], \
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
# BackgroundImage(X, Y, WIDTH, HEIGHT)
self.MAZE_X = self.BLOCK_WIDTH * (len(self.MATRIX[0])
+ self.MAZE_OFFSET_X)
self.MAZE_Y = self.BLOCK_HEIGHT * (len(self.MATRIX)
+ self.MAZE_OFFSET_Y)
self.MAZE_WIDTH = self.BLOCK_WIDTH * len(self.MATRIX[0])
self.MAZE_HEIGHT = self.BLOCK_HEIGHT * len(self.MATRIX)
def DrawMaze(self, MazeSurface):
for ROW in range(len(self.MATRIX)):
for COLUMN in range(len(self.MATRIX[0])):
# Saves the position of each dot
if self.MATRIX[ROW][COLUMN] == 0:
self.DOTS.append([(self.BLOCK_WIDTH * COLUMN),
(self.BLOCK_HEIGHT * ROW), 4, 4])
# Saves the position of each wall
if self.MATRIX[ROW][COLUMN] == 1:
self.WALLS.append(pygame.draw.rect(MazeSurface, WHITE,
[((self.BLOCK_WIDTH) * COLUMN),
((self.BLOCK_HEIGHT) * ROW),
self.BLOCK_WIDTH, self.BLOCK_HEIGHT]))
# Saves the position of each Energizer
if self.MATRIX[ROW][COLUMN] == 3:
self.ENERGIZER.append([(self.BLOCK_WIDTH * COLUMN),
(self.BLOCK_HEIGHT * ROW), 14, 14])
if self.MATRIX[ROW][COLUMN] == 4:
self.GHOSTS.append([(self.BLOCK_WIDTH * COLUMN),
(self.BLOCK_HEIGHT * ROW), 23, 23])
for WALL in self.WALLS:
X, Y, WIDTH, HEIGHT = WALL
self.WALLS_XY.append((X, Y))
class Main(Maze):
def __init__(self):
# Inherits Maze class
Maze.__init__(self)
self.TimeBetweenBites = 0.1
self.LastBiteTime = time.time()
self.MouthOpen = False
self.PacManDirection = ""
self.GhostDirection = ""
self.SCORE = 0
self.HIGH_SCORE = 0
self.GridSizeX = SCREEN_HEIGHT // 19
self.GridSizeY = SCREEN_HEIGHT // 32
def PacManMovement(self):
key = pygame.key.get_pressed()
if key[pygame.K_LEFT] and not key[pygame.K_UP] \
and not key[pygame.K_DOWN]:
self.PacManDirection = "LEFT"
elif key[pygame.K_RIGHT] and not key[pygame.K_UP] \
and not key[pygame.K_DOWN]:
self.PacManDirection = "RIGHT"
elif key[pygame.K_UP] and not key[pygame.K_LEFT] \
and not key[pygame.K_RIGHT]:
self.PacManDirection = "UP"
elif key[pygame.K_DOWN] and not key[pygame.K_LEFT] \
and not key[pygame.K_RIGHT]:
self.PacManDirection = "DOWN"
def ContinuePacManMovement(self):
if self.PacManDirection == "LEFT":
CurrentRect.x -= SPEED
self.PacManWallDetection(-1, 0, CurrentRect)
if self.PacManDirection == "RIGHT":
CurrentRect.x += SPEED
self.PacManWallDetection(1, 0, CurrentRect)
if self.PacManDirection == "UP":
CurrentRect.y -= SPEED
self.PacManWallDetection(0, -1, CurrentRect)
if self.PacManDirection == "DOWN":
CurrentRect.y += SPEED
self.PacManWallDetection(0, 1, CurrentRect)
def ContinueGhostMovement(self):
if self.GhostDirection == "LEFT":
PinkGhostRect.x -= SPEED
self.GhostWallDetection(-1, 0, PinkGhostRect)
if self.GhostDirection == "RIGHT":
PinkGhostRect.x += SPEED
self.GhostWallDetection(1, 0, PinkGhostRect)
if self.GhostDirection == "UP":
PinkGhostRect.y -= SPEED
self.GhostWallDetection(0, -1, PinkGhostRect)
if self.GhostDirection == "DOWN":
PinkGhostRect.y += SPEED
self.GhostWallDetection(-1, 0, PinkGhostRect)
def PacManTeleport(self):
if CurrentRect.right < 0:
CurrentRect.right = SCREEN_WIDTH + 20
if CurrentRect.left > SCREEN_WIDTH:
CurrentRect.right = 0
def GhostTeleport(self, Intersection):
if PinkGhostRect.right < 0:
PinkGhostRect.right = SCREEN_WIDTH + 20
Intersection.append("LEFT")
if PinkGhostRect.left > SCREEN_WIDTH:
PinkGhostRect.right = 0
Intersection.append("RIGHT")
def PacManWallDetection(self, x, y, CurrentRect):
CurrentRect.right += x
for WALL in self.WALLS:
COLLIDE = CurrentRect.colliderect(WALL)
if COLLIDE:
if x < 0:
CurrentRect.left = WALL.right
CurrentSurface = pygame.transform.rotate(PacManSurface, 180)
MazeSurface.blit(CurrentSurface, CurrentRect)
if x > 0:
CurrentRect.right = WALL.left
break
CurrentRect.top += y
for WALL in self.WALLS:
COLLIDE = CurrentRect.colliderect(WALL)
if COLLIDE:
if y < 0:
CurrentRect.top = WALL.bottom
if y > 0:
CurrentRect.bottom = WALL.top
break
def GhostWallDetection(self, x, y, PinkGhostRect):
PinkGhostRect.right += x
for WALL in self.WALLS:
COLLIDE = PinkGhostRect.colliderect(WALL)
if COLLIDE:
if x < 0:
PinkGhostRect.left = WALL.right
if random.randrange(0, 100) <= 40:
self.GhostDirection = "RIGHT"
if x > 0:
PinkGhostRect.right = WALL.left
if random.randrange(0, 100) <= 40:
self.GhostDirection = "LEFT"
break
PinkGhostRect.top += y
for WALL in self.WALLS:
COLLIDE = PinkGhostRect.colliderect(WALL)
if COLLIDE:
if y < 0:
PinkGhostRect.top = WALL.bottom
if random.randrange(0, 100) <= 40:
self.GhostDirection = "DOWN"
if y > 0:
PinkGhostRect.bottom = WALL.top
if random.randrange(0, 100) <= 40:
self.GhostDirection = "UP"
break
def GetAvailableMoves(self):
Intersection = []
self.GhostTeleport(Intersection)
print(PinkGhostRect.topleft)
print(self.WALLS_XY)
if ((PinkGhostRect.x - 1, PinkGhostRect.y)) not in self.WALLS_XY:
Intersection.append("LEFT")
if ((PinkGhostRect.x + 1, PinkGhostRect.y)) not in self.WALLS_XY:
Intersection.append("RIGHT")
if ((PinkGhostRect.x, PinkGhostRect.y - 1)) not in self.WALLS_XY:
Intersection.append("UP")
if ((PinkGhostRect.x, PinkGhostRect.y + 1)) not in self.WALLS_XY:
Intersection.append("DOWN")
print(Intersection)
return Intersection
def EatDots(self):
for ROW in range(len(self.MATRIX)):
for COLUMN in range(len(self.MATRIX[0])):
for DOT in self.DOTS:
CHOMP = CurrentRect.colliderect(DOT)
if CHOMP:
Main.PlaySound(self, 0)
self.DOTS.remove(DOT)
self.MATRIX[ROW][COLUMN] = 3
self.SCORE += 10
if self.SCORE > self.HIGH_SCORE:
self.HIGH_SCORE = self.SCORE
return str(self.SCORE), str(self.HIGH_SCORE)
def EatEnergizer(self):
for ROW in range(len(self.MATRIX)):
for COLUMN in range(len(self.MATRIX[0])):
for POWERUP in self.ENERGIZER:
CHOMP = CurrentRect.colliderect(POWERUP)
if CHOMP:
self.ENERGIZER.remove(POWERUP)
self.MATRIX[ROW][COLUMN] = 3
self.SCORE += 50
Main.PlaySound(self, 1)
if self.SCORE > self.HIGH_SCORE:
self.HIGH_SCORE = self.SCORE
return str(self.SCORE), str(self.HIGH_SCORE)
def EatGhosts(self):
pass
def DrawDots(self):
for POSITION in self.DOTS:
X = POSITION[0] + 13
Y = POSITION[1] + 13
WIDTH = POSITION[2]
HEIGHT = POSITION[3]
pygame.draw.circle(MazeSurface, YELLOW, (X, Y),
WIDTH // 2, HEIGHT // 2)
def DrawEnergizer(self):
for POSITION in self.ENERGIZER:
X = POSITION[0] + 13
Y = POSITION[1] + 13
WIDTH = POSITION[2]
HEIGHT = POSITION[3]
pygame.draw.circle(MazeSurface, YELLOW, (X, Y),
WIDTH // 2, HEIGHT // 2)
def DrawGhosts(self):
MazeSurface.blit(PinkGhostSurface, PinkGhostRect)
MazeSurface.blit(YellowGhostSurface, YellowGhostRect)
MazeSurface.blit(RedGhostSurface, RedGhostRect)
MazeSurface.blit(BlueGhostSurface, BlueGhostRect)
def GhostStartPosition(self):
X, Y, WIDTH, HEIGHT = self.GHOSTS[0]
PinkGhostRect.x = X
PinkGhostRect.y = Y
X, Y, WIDTH, HEIGHT = self.GHOSTS[1]
YellowGhostRect.x = X
YellowGhostRect.y = Y
X, Y, WIDTH, HEIGHT = self.GHOSTS[2]
RedGhostRect.x = X
RedGhostRect.y = Y
X, Y, WIDTH, HEIGHT = self.GHOSTS[3]
BlueGhostRect.x = X
BlueGhostRect.y = Y
def PlaySound(self, Track):
if Track == 0:
Eat = pygame.mixer.Sound("pacman_chomp.wav")
Eat.play()
pygame.mixer.fadeout(400)
if Track == 1:
EatPellet = pygame.mixer.Sound("pacman_eatghost.wav")
EatPellet.play()
pygame.mixer.music.play(7)
pygame.mixer.fadeout(400)
def ShowScore(self):
global Font
OneUpText = Font.render("1UP", True, WHITE)
OneUpTextRect = OneUpText.get_rect(center = (70, 10))
# Displays current score
OneUpScoreText = Font.render(str(self.SCORE), True, WHITE)
OneUpScoreRect = OneUpScoreText.get_rect(center =
((SCREEN_WIDTH - 290)
// 2, 26))
HighScoreText = Font.render("High Score", True, WHITE)
HighScoreTextRect = HighScoreText.get_rect(center =
(SCREEN_WIDTH // 2, 10))
# Displays High Score
HighScoreNumber = Font.render(str(self.HIGH_SCORE), True, WHITE)
HighScoreNumberRect = HighScoreNumber.get_rect(center =
((SCREEN_WIDTH + 90)
// 2, 26))
SCREEN.blit(OneUpText, OneUpTextRect)
SCREEN.blit(OneUpScoreText, OneUpScoreRect)
SCREEN.blit(HighScoreText, HighScoreTextRect)
SCREEN.blit(HighScoreNumber, HighScoreNumberRect)
def PacManBite(self):
global CurrentSurface
CurrentTime = time.time()
if CurrentTime - self.LastBiteTime >= self.TimeBetweenBites:
self.LastBiteTime = CurrentTime
if self.MouthOpen:
CurrentSurface = PacManStartSurface
else:
CurrentSurface = PacManSurface
self.MouthOpen = not self.MouthOpen
if self.PacManDirection == "LEFT":
CurrentSurface = pygame.transform.rotate(CurrentSurface, 180)
if self.PacManDirection == "RIGHT":
CurrentSurface = CurrentSurface
if self.PacManDirection == "UP":
CurrentSurface = pygame.transform.rotate(CurrentSurface, 90)
if self.PacManDirection == "DOWN":
CurrentSurface = pygame.transform.rotate(CurrentSurface, 270)
def PacManLives(self):
pass
def Update(self):
Player.PacManTeleport()
Player.ContinuePacManMovement()
Player.ContinueGhostMovement()
Player.GetAvailableMoves()
MazeSurface.blit(BackgroundSurface, BackgroundRect)
Player.DrawDots()
Player.DrawEnergizer()
Player.DrawGhosts()
Player.EatDots()
Player.EatEnergizer()
MazeSurface.blit(CurrentSurface, CurrentRect)
Player.PacManBite()
SCREEN.blit(MazeSurface, MazeRect)
Player.ShowScore()
Player = Main()
BackgroundSurface = pygame.transform.scale(BackgroundSurface,
(Player.MAZE_WIDTH,
Player.MAZE_HEIGHT))
BackgroundRect = BackgroundSurface.get_rect()
MazeSurface = pygame.Surface((Player.MAZE_WIDTH, Player.MAZE_HEIGHT))
MazeRect = MazeSurface.get_rect(topleft = (Player.MAZE_OFFSET_X,
Player.MAZE_OFFSET_Y))
Player.DrawMaze(MazeSurface)
Player.GhostStartPosition()
'''
Before the game starts ...
pregame = True
while pregame:
if key button pressed:
pregame = False
run = True
'''
run = True
while run:
SCREEN.fill(BLACK)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
Player.PacManMovement()
Player.Update()
pygame.display.update()
CLOCK.tick(FPS)
pygame.quit()
You just need to divide the position in the grid by the size of a tile with the // (floor-division) operator:
pos_in_maze = (225, 175)
column = pos_in_maze[0] // Player.BLOCK_WIDTH
row = pos_in_maze[1] // Player.BLOCK_HEIGHT
Since the size of a tile is 25 the results are 9 for the column and 7 for the row.
screen_pos = (225, 175)
column = (screen_pos[0] - Player.MAZE_OFFSET_X) // Player.BLOCK_WIDTH
row = (screen_pos[1] - Player.MAZE_OFFSET_Y) // Player.BLOCK_HEIGHT
Since MAZE_OFFSET_X is 0 and MAZE_OFFSET_Y is 50 the results are 9 for the column and 5 for the row.

I made a minesweeper game with tkinter

I'm a total beginner who just started learning to code with the book "Head First Learn to Code". I've just finished the book and coded a minesweeper game with python3 on my mac. I hope to get some advice on the game I made. If you feel like the code is too long to read, here are some specific questions I'd like to ask:
What does this: flag = flag.resize((12, 12), Image.ANTIALIAS) actually do, why do I need to assign it a variable instead of just doing this: flag.resize((12, 12), Image.ANTIALIAS) as I'd do with other objects
Is there a better way to create a stopwatch? Mine is the function update_time.
Did I make any mistake regarding the conventions of python? Please point out some for me.
Any help would be much appreciated!
Here's my code:
from tkinter import *
import random as rd
from tkinter import messagebox
from PIL import ImageTk, Image
import sys
class GameGrid(Frame): #the game
def __init__(self, master, height, width, mines_count, player):
Frame.__init__(self, master)
self.grid(row=0)
self.master = master
if sys.platform == 'win32': #checking os
self.platform = 'windows'
else:
self.platform = 'macos'
self.height = height #storing height, width, mines_count, and player's name
self.width = width
self.mines_count = mines_count
self.player_name = player
self.play_time = 0 #initiating play_time and other values
self.lost = False
self.won = False
self.notmine = height * width - mines_count #calculate the number of tiles that are not mines
flag = Image.open('flag.png') #creating and storing flag and bomb images
flag = flag.resize((12, 12), Image.ANTIALIAS)
bomb = Image.open('bomb.png')
bomb = bomb.resize((12, 12), Image.ANTIALIAS)
self.flag = ImageTk.PhotoImage(flag)
self.bomb = ImageTk.PhotoImage(bomb)
grid_model = [[0]*width for item in [0]*height] #creating a list to hold 1's and 0's
while mines_count > 0: #1 is mine, 0 is normal
randi = rd.randint(0, height-1) #putting mines into the list by generating random coordinates
randj = rd.randint(0, width-1) #and storing mine in the corresponding place
if grid_model[randi][randj] == 0:
grid_model[randi][randj] = 1
mines_count -= 1
self.tiles = {} #creating Tiles and storing them using dictionary
for i in range(height):
for j in range(width):
if grid_model[i][j] == 1:
self.tiles[i, j] = Tile(self, i, j, True)
else:
mine_neighbors = 0 #counting nearby mines if Tile in creation is not a mine
if i - 1 >= 0:
if grid_model[i-1][j] == 1:
mine_neighbors += 1
if i - 1 >= 0 and j - 1 >= 0:
if grid_model[i-1][j-1] == 1:
mine_neighbors += 1
if i - 1 >= 0 and j + 1 < width:
if grid_model[i-1][j+1] == 1:
mine_neighbors += 1
if j - 1 >= 0:
if grid_model[i][j-1] == 1:
mine_neighbors += 1
if j + 1 < width:
if grid_model[i][j+1] == 1:
mine_neighbors += 1
if i + 1 < height:
if grid_model[i+1][j] == 1:
mine_neighbors += 1
if i + 1 < height and j - 1 >= 0:
if grid_model[i+1][j-1] == 1:
mine_neighbors += 1
if i + 1 < height and j + 1 < width:
if grid_model[i+1][j+1] == 1:
mine_neighbors += 1
self.tiles[i, j] = Tile(self, i, j, False, mine_neighbors)
def reveal_surroundings(self, i, j): #reveal nearby tiles
revealing = []
width = self.width
height = self.height
if i - 1 >= 0:
revealing.append(self.tiles[i-1, j])
if i - 1 >= 0 and j - 1 >= 0:
revealing.append(self.tiles[i-1, j-1])
if i - 1 >= 0 and j + 1 < width:
revealing.append(self.tiles[i-1, j+1])
if j - 1 >= 0:
revealing.append(self.tiles[i, j-1])
if j + 1 < width:
revealing.append(self.tiles[i, j+1])
if i + 1 < height:
revealing.append(self.tiles[i+1, j])
if i + 1 < height and j - 1 >= 0:
revealing.append(self.tiles[i+1, j-1])
if i + 1 < height and j + 1 < width:
revealing.append(self.tiles[i+1, j+1])
for tile in revealing:
tile.reveal()
def lose(self): #show if lost, stop the clock
global stp
stp = True
self.lost = True
if self.platform == 'windows':
for tile in self.tiles:
if self.tiles[tile].mine:
self.tiles[tile].config(bg='red')
else:
for tile in self.tiles:
if self.tiles[tile].mine:
self.tiles[tile].config(image=self.bomb, padx=9, pady=4, bg='red')
self.tiles[tile].unbind('<Button-1>')
self.tiles[tile].unbind('<Button-2>')
messagebox.showerror(message='Boom, Game Over!!')
self.score = ScoreBoard(self.master)
def win(self): #show if won, stop the clock, creating a window recording scores
global mn, sc, stp
stp = True
self.won = True
for tile in self.tiles:
if self.tiles[tile].mine:
self.tiles[tile].config(image=self.bomb, padx=9, pady=4, bg='red')
self.tiles[tile].unbind('<Button-1>')
self.tiles[tile].unbind('<Button-2>')
messagebox.showinfo(message='Congrats, You Survived ;)')
play_time = str(m) + ' mins, ' + str(s) + ' secs'
self.score = ScoreBoard(self.master, self.player_name, play_time)
class ScoreBoard(Toplevel): #for score recording
def __init__(self, master, name=None, time=None):
Toplevel.__init__(self, master)
self.title('Hall of Fame')
fin_text = ''
if name != None: #writing in the record if there is one
self.board = open('ScoreBoard.txt', 'r') #assigning the text inside ScoreBoard.txt to board_text
board_text = '' #and writing it into ScoreBoard.txt
for line in self.board:
board_text = board_text + line
self.board = open('ScoreBoard.txt', 'w')
self.record = name + ' ' + time
self.board.write(board_text + '\n' + self.record)
self.board = open('ScoreBoard.txt', 'r') #reading text in ScoreBoard and put it on the window
for line in self.board:
fin_text = fin_text + line
self.lbl = Label(self, text=fin_text)
self.lbl.pack()
self.geometry('300x300')
self.board.close()
class Tile(Label): #the Tile
def __init__(self, master, i, j, mine, mine_neighbors=None):
Label.__init__(self, master, width=2, relief=RAISED)
self.grid(row=i, column=j)
self.game = master #storing row, column, is mine or not, count of nearby mines
self.mine = mine
self.row = i
self.col = j
self.mine_neighbors = mine_neighbors
self.revealed = False
self.marked = False
self.bind('<Button-1>', self.reveal) #bind Tile: reveal(left click), mark(right click)
self.bind('<Button-2>', self.mark)
def reveal(self, event=None): #revealing tile
if self.mine:
self.game.lose()
return
else:
if not self.revealed:
self.revealed = True
self.mark()
self.unbind('<Button-1>')
self.unbind('<Button-2>')
if self.mine_neighbors == 0: #if no nearby mines, reveal nearby tiles
self.config(text='', relief=SUNKEN, bg='lightgrey', image='', padx=1, pady=1)
self.game.reveal_surroundings(self.row, self.col)
else:
self.config(text=self.mine_neighbors, relief=SUNKEN, bg='lightgrey', image='', padx=1, pady=1)
self.game.notmine -= 1
if self.game.notmine == 0:
self.game.win()
def mark(self,event=None): #marking tile
if self.game.platform == 'windows':
if not self.marked:
self.config(text='*')
self.marked = True
else:
self.config(text='')
self.marked = False
else:
if not self.marked:
self.config(image=self.game.flag, padx=9, pady=4)
self.marked = True
else:
self.config(image='', padx=1, pady=1)
self.marked = False
stp = False #used to stop the clock when lost or won
def update_time(): #a stopwatch
global m, s, timer, stp
if stp != True:
s = s + 1
if s == 60:
m = m + 1
s = 0
mn = str(m) #making the clock look better by adding a 0 when the number
sc = str(s) #of second or minute is just one digit, e.g. 01, 06, 09..
if len(sc) == 1 and len(mn) == 1:
sc = '0' + sc
mn = '0' + mn
timer.config(text=mn+':'+sc)
elif len(mn) == 1 and len(sc) != 1:
mn = '0' + str(m)
timer.config(text=mn+':'+str(s))
elif len(sc) == 1 and len(mn) != 1:
sc = '0' + sc
timer.config(text=mn+':'+sc)
timer.after(1000, update_time)
def play(height, width, mines_count, player): #initiating the game
global s, m, timer
m = 0
s = -1
time = str(m) + ':' + str(s)
root = Tk()
root.title('MineSweeper')
root.resizable(False, False)
timer = Label(root, text='%i:%i'%(m,s)) #creating stopwatch and update it every second
timer.grid(row=1)
update_time()
game = GameGrid(root, height, width, mines_count, player)
root.mainloop()
if __name__ == '__main__':
play(10, 10, 10, 'Harley')

How to call Python code from another .py? (when I press space bar both .py are in the same file)

How to call a code from one .py to run in another .py when I press space bar both .py are in the same file.
I have a code called solve that I want to call by pressing space when running my sudoku code. This is solver.py they are both in a folder called Sudoku solver. I apologize if this is simple; I don't know pygame very well.
def solve(bo):
find = find_empty(bo)
if not find:
return True
else:
row, col = find
for i in range(1,10):
if valid(bo, i, (row, col)):
bo[row][col] = i
if solve(bo):
return True
bo[row][col] = 0
def valid(bo, num, pos):
# check row
for i in range(len(bo[0])):
if bo[pos[0]][i] == num and pos[1] !=i:
return False
# check column
for i in range(len(bo)):
if bo[i][pos[1]] == num and pos[0] !=i:
return False
# check box
box_x = pos[1] // 3
box_y = pos[0] // 3
for i in range(box_y * 3, box_y * 3):
for j in range(box_x * 3, box_x * 3):
if bo[i][j] == num and(i, j) != pos:
return False
return True
def print_board(bo):
for i in range(len(bo)):
if i % 3 == 0 and i !=0:
print("- - - - - - - - - - - - -")
for j in range(len(bo[0])):
if j % 3 == 0 and j != 0:
print(" | ", end="")
if j == 8:
print(bo[i][j])
else:
print(str(bo[i][j]) + " ", end="")
def find_empty(bo):
for i in range (len(bo)):
for j in range(len(bo[0])):
if bo[i][j] == 0:
return (i, j) #(row,column)
return None
this is sudoku
# GUI.py
import pygame
from solver import solve, valid
import time
import solver
pygame.font.init()
class Grid:
board = [
[7, 8, 0, 4, 0, 0, 1, 2, 0],
[6, 0, 0, 0, 7, 5, 0, 0, 9],
[0, 0, 0, 6, 0, 1, 0, 7, 8],
[0, 0, 7, 0, 4, 0, 2, 6, 0],
[0, 0, 1, 0, 5, 0, 9, 3, 0],
[9, 0, 4, 0, 6, 0, 0, 0, 5],
[0, 7, 0, 3, 0, 0, 0, 1, 2],
[1, 2, 0, 0, 0, 7, 4, 0, 0],
[0, 4, 9, 2, 0, 6, 0, 0, 7]
]
def __init__(self, rows, cols, width, height):
self.rows = rows
self.cols = cols
self.cubes = [[Cube(self.board[i][j], i, j, width, height) for j in range(cols)] for i in range(rows)]
self.width = width
self.height = height
self.model = None
self.selected = None
def update_model(self):
self.model = [[self.cubes[i][j].value for j in range(self.cols)] for i in range(self.rows)]
def place(self, val):
row, col = self.selected
if self.cubes[row][col].value == 0:
self.cubes[row][col].set(val)
self.update_model()
if valid(self.model, val, (row,col)) and solve(self.model):
return True
else:
self.cubes[row][col].set(0)
self.cubes[row][col].set_temp(0)
self.update_model()
return False
def sketch(self, val):
row, col = self.selected
self.cubes[row][col].set_temp(val)
def draw(self, win):
# Draw Grid Lines
gap = self.width / 9
for i in range(self.rows+1):
if i % 3 == 0 and i != 0:
thick = 4
else:
thick = 1
pygame.draw.line(win, (0,0,0), (0, i*gap), (self.width, i*gap), thick)
pygame.draw.line(win, (0, 0, 0), (i * gap, 0), (i * gap, self.height), thick)
# Draw Cubes
for i in range(self.rows):
for j in range(self.cols):
self.cubes[i][j].draw(win)
def select(self, row, col):
# Reset all other
for i in range(self.rows):
for j in range(self.cols):
self.cubes[i][j].selected = False
self.cubes[row][col].selected = True
self.selected = (row, col)
def clear(self):
row, col = self.selected
if self.cubes[row][col].value == 0:
self.cubes[row][col].set_temp(0)
def click(self, pos):
"""
:param: pos
:return: (row, col)
"""
if pos[0] < self.width and pos[1] < self.height:
gap = self.width / 9
x = pos[0] // gap
y = pos[1] // gap
return (int(y),int(x))
else:
return None
def is_finished(self):
for i in range(self.rows):
for j in range(self.cols):
if self.cubes[i][j].value == 0:
return False
return True
class Cube:
rows = 9
cols = 9
def __init__(self, value, row, col, width ,height):
self.value = value
self.temp = 0
self.row = row
self.col = col
self.width = width
self.height = height
self.selected = False
def draw(self, win):
fnt = pygame.font.SysFont("comicsans", 40)
gap = self.width / 9
x = self.col * gap
y = self.row * gap
if self.temp != 0 and self.value == 0:
text = fnt.render(str(self.temp), 1, (128,128,128))
win.blit(text, (x+5, y+5))
elif not(self.value == 0):
text = fnt.render(str(self.value), 1, (0, 0, 0))
win.blit(text, (x + (gap/2 - text.get_width()/2), y + (gap/2 - text.get_height()/2)))
if self.selected:
pygame.draw.rect(win, (255,0,0), (x,y, gap ,gap), 3)
def set(self, val):
self.value = val
def set_temp(self, val):
self.temp = val
def redraw_window(win, board, time, strikes):
win.fill((255,255,255))
# Draw time
fnt = pygame.font.SysFont("comicsans", 40)
text = fnt.render("Time: " + format_time(time), 1, (0,0,0))
win.blit(text, (540 - 160, 560))
# Draw Strikes
text = fnt.render("X " * strikes, 1, (255, 0, 0))
win.blit(text, (20, 560))
# Draw grid and board
board.draw(win)
def format_time(secs):
sec = secs%60
minute = secs//60
hour = minute//60
mat = " " + str(minute) + ":" + str(sec)
return mat
def main():
win = pygame.display.set_mode((540,600))
pygame.display.set_caption("Sudoku")
board = Grid(9, 9, 540, 540)
key = None
run = True
start = time.time()
strikes = 0
while run:
play_time = round(time.time() - start)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_1:
key = 1
if event.key == pygame.K_2:
key = 2
if event.key == pygame.K_3:
key = 3
if event.key == pygame.K_4:
key = 4
if event.key == pygame.K_5:
key = 5
if event.key == pygame.K_6:
key = 6
if event.key == pygame.K_7:
key = 7
if event.key == pygame.K_8:
key = 8
if event.key == pygame.K_9:
key = 9
if event.key == pygame.K_SPACE:
solver.solve(bo)
if event.key == pygame.K_DELETE:
board.clear()
key = None
if event.key == pygame.K_RETURN:
i, j = board.selected
if board.cubes[i][j].temp != 0:
if board.place(board.cubes[i][j].temp):
print("Success")
else:
print("Wrong")
strikes += 1
key = None
if board.is_finished():
print("Game over")
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
clicked = board.click(pos)
if clicked:
board.select(clicked[0], clicked[1])
key = None
if board.selected and key != None:
board.sketch(key)
redraw_window(win, board, play_time, strikes)
pygame.display.update()
main()
pygame.quit()
It looks to me like you've already handled the event where space is pressed, you will call solve from the other file. I think you've done it right. However, I think you misdefinied the input parameter for solver.solve(). Looking through your code in GUI.py, there seems to be no variable called bo. By looking at it, I assume the right input parameter should be board.
Could you try changing line 197 from:
solver.solve(bo)
to:
solver.solve(board)
Just an additional comment:
As you used from solver import solve, valid in line 3, you do not need to use solver.solve(bo) in line 197. Instead you can simply use solve(bo). This is not a problem though, the way you used also works as you've used import solver on line 5.

How to correct the following one player tictactoe game?

I have made the following tic tac toe game which reads the current state of the board, stores it in entries, then I read a text file which has data in the format XOXXXO O:6where the part after : is the number of box the AI should choose on the basis of the part before the : so that the AI never loses. For some reason, it kinda stops working after my 3rd input.
main function
global win
global boxsize
entries = [[None] * 3, [None] * 3, [None] * 3]
windowsize = 300
boxsize = 100
win = GraphWin("Tic Tac Toe", windowsize, windowsize, autoflush=False)
for i in range(2):
hline = Line(Point(0, (windowsize / 3) * (i + 1)), Point(windowsize, (windowsize / 3) * (i + 1)))
hline.draw(win)
vline = Line(Point((windowsize / 3) * (i + 1), 0), Point((windowsize / 3) * (i + 1), windowsize))
vline.draw(win)
for i in range(1, 10):
print("Player 1: click a square.")
p1mouse = win.getMouse()
p1x = p1mouse.getX()
p1y = p1mouse.getY()
tic_tac_toe_X(entries, win, p1x, p1y)
if (check(entries) == True):
print("Player 1 is the winner.")
break
tic_tac_toe_O_ai(entries, win)
if (check(entries) == True):
print("Player 2 is the winner.")
break
print("Enter 1 to play again, 0 to Exit : ")
x = int(input())
if (x == 1):
win.close()
main()
else:
sys.exit()
Function that reads the text file and returns the box number move for the AI
Reads the .txt file to get the box number to move to
def ai_move(entries):
df = pd.read_csv("Dataset.txt", sep=":", names=['strings', 'moves'])
a = df[['strings']]
b = df[['moves']]
status = a.to_numpy()
next_move = b.to_numpy()
status = status.flatten()
next_move = next_move.flatten()
str = ""
for i in range(3):
for j in range(3):
if entries[i][j] == 'x':
str += "X"
elif entries[i][j] == 'o':
str += "O"
else:
str += " "
for i in range(2112):
if str == status[i]:
next = int(next_move[i])
return next
function that prints the 'O' for the AI
# Draws the 'O' for the AI
def tic_tac_toe_O_ai(entries, win):
box = ai_move(entries)
if (box == 0):
center = Point(50, 50)
entries[0][0] = 'o'
elif (box == 1):
center = Point(150, 50)
entries[1][0] = 'o'
elif (box == 2):
center = Point(250, 50)
entries[2][0] = 'o'
elif (box == 3):
center = Point(50, 150)
entries[0][1] = 'o'
elif (box == 4):
center = Point(150, 150)
entries[1][1] = 'o'
elif (box == 5):
center = Point(250, 150)
entries[2][1] = 'o'
elif (box == 6):
center = Point(50, 250)
entries[0][2] = 'o'
elif (box == 7):
center = Point(150, 250)
entries[1][2] = 'o'
elif (box == 8):
center = Point(250, 250)
entries[2][2] = 'o'
circle = Circle(center, 50)
circle.setOutline('green')
circle.setWidth(5)
circle.draw(win)

issue with filling the correct grid cell in tkinter

im trying to make a battleship game in python using tkinter,
the minimum reproducible example is:
from tkinter import *
from random import randint
import time
tk = Tk()
class player:
def __init__(self, master):
self.master = master
self.placedships = []
self.bombed = []
self.sunk = []
self.ship_sizes = [5, 4, 3]
self.player_canvas = Canvas(master, height=300, width=300, highlightbackground='black', highlightthickness=0.5)
self.ai_canvas = Canvas(master, height=300, width=300, highlightbackground='black', highlightthickness=0.5)
self.player_canvas.grid(row=1, column=0, padx=50)
self.ai_canvas.grid(row=1, column=1, padx=50)
self.direction = 'v'
self.shipChosen = 0
gridLabel_player = Label(master,text="Your grid \nA B C D E F G H I J ")
gridLabel_player.grid(row=0,column=0)
gridLabel_ai = Label(master,text="AI's grid \nA B C D E F G H I J ")
gridLabel_ai.grid(row=0,column=1)
for x in range(10):
for y in range(10):
self.player_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill = 'white')
self.ai_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill = 'white')
#variables to store data for cells on game grid
# # self.player_ocean = 10 * [10 * [0]]
# # self.ai_ocean = 10 * [10 * [0]]
self.player_ocean = []
self.ai_ocean = []
temp = []
for i in range(10):
for y in range(10):
temp += [0]
self.player_ocean += [temp]
self.ai_ocean += [temp]
temp = []
self.selectedCoord = [0,0] # [0] = x coord, [1] = y coord
def placeShip(self):
def moveShip(event):
if event.keysym == 'Down' and self.selectedCoord[1] != 9:
self.selectedCoord[1] += 1
elif event.keysym == 'Up' and self.selectedCoord[1] != 0:
self.selectedCoord[1] -= 1
elif event.keysym == 'Left' and self.selectedCoord[0] != 0:
self.selectedCoord[0] -= 1
elif event.keysym == 'Right' and self.selectedCoord[0] != 9:
self.selectedCoord[0] += 1
print('selected coord:',self.selectedCoord)
def selectPlacement(event):
col = self.selectedCoord[0]
row = self.selectedCoord[1]
if self.direction == 'v':
v_range_start = row - self.ship_sizes[self.shipChosen] + 1
for y in range(v_range_start, row+1):
'''insert validation to reject ship clashing'''
self.player_ocean[y][col] = 1
self.placedships += [y,col]
self.refresh_ocean()
self.master.bind("<Up>", moveShip)
self.master.bind("<Down>", moveShip)
self.master.bind("<Left>", moveShip)
self.master.bind("<Right>", moveShip)
self.master.bind("<Return>", selectPlacement)
def refresh_ocean(self): # 1s turns to green
for y in range(10):
for x in range(10):
if self.player_ocean[y][x] == 1:
self.player_canvas.itemconfig(self.player_canvas.create_rectangle( (x+1) * 30, (y-1) * 30,x * 30, y * 30, fill='green'))
player1 = player(tk)
player1.placeShip()
tk.mainloop()
the problem i have is that lets say if i press the down arrow until my selected coordinate is [0,9], the code should colour the 6th to 10th box from top down, in the first column, but it colours the 5th to 9th box.
i have tried debugging it by checking if the coordinates x and y used in the last function refresh_ocean were wrong, but they were as expected
So the short and simple fix is to change (y-1) to (y+1).
That said I made a few changes:
Rewrote some of your names to follow PEP8 style guide.
Converted your refresh_ocean method to handle the initial draw and all draws afterwords. As well as added a delete('all') to clear the board so we are not draw on top of the previous objects. This will prevent using up more memory as the game progresses.
Cleaned up imports and changed from tkinter import * to import tkinter as tk. This will help prevent overwriting other things in the namespace.
By writing your refresh_ocean to handle all the drawing we can specify what needs to be drawn with tags like 'player1' and 'ai'.
Changed += to .append() for your list generation as append() is twice as fast as '+=. See this post: Difference between “.append()” and “+= []”?
Changed you single label of headers into a loop to create each label evenly. This will allow for a more accurate header then trying to manually set spaces in a single string.
Lastly because you are already checking of the key is one of the 4 arrow keys we can use a single bind to '<Key>' and get the same results as all 4 binds.
Updated code:
import tkinter as tk
class Player(tk.Tk):
def __init__(self):
super().__init__()
self.placed_ships = []
self.player_ocean = []
self.ai_ocean = []
self.bombed = []
self.sunk = []
self.bord_size = list('ABCDEFGHIJ')
self.selected_coord = [0, 0]
self.ship_sizes = [5, 4, 3]
self.direction = 'v'
self.shipChosen = 0
wh = 300
p_label_frame = tk.Frame(self, width=wh, height=30)
a_label_frame = tk.Frame(self, width=wh, height=30)
p_label_frame.grid(row=1, column=0, padx=50)
a_label_frame.grid(row=1, column=1, padx=50)
p_label_frame.grid_propagate(False)
a_label_frame.grid_propagate(False)
for ndex, letter in enumerate(self.bord_size):
p_label_frame.columnconfigure(ndex, weight=1)
a_label_frame.columnconfigure(ndex, weight=1)
tk.Label(p_label_frame, text=letter).grid(row=0, column=ndex)
tk.Label(a_label_frame, text=letter).grid(row=0, column=ndex)
self.player_canvas = tk.Canvas(self, height=wh, width=wh, highlightbackground='black', highlightthickness=0.5)
self.ai_canvas = tk.Canvas(self, height=wh, width=wh, highlightbackground='black', highlightthickness=0.5)
self.player_canvas.grid(row=2, column=0, padx=50)
self.ai_canvas.grid(row=2, column=1, padx=50)
temp = []
for i in range(10):
for y in range(10):
temp.append(0)
self.player_ocean.append(temp)
self.ai_ocean.append(temp)
temp = []
self.refresh_ocean()
self.bind("<Key>", self.move_ship)
self.bind("<Return>", self.select_placement)
def move_ship(self, event):
if event.keysym == 'Down' and self.selected_coord[1] < 9:
self.selected_coord[1] += 1
elif event.keysym == 'Up' and self.selected_coord[1] > 0:
self.selected_coord[1] -= 1
elif event.keysym == 'Left' and self.selected_coord[0] > 0:
self.selected_coord[0] -= 1
elif event.keysym == 'Right' and self.selected_coord[0] < 9:
self.selected_coord[0] += 1
print('selected coord:', self.selected_coord)
def select_placement(self, _=None):
col = self.selected_coord[0]
row = self.selected_coord[1]
if self.direction == 'v':
v_range_start = row - self.ship_sizes[self.shipChosen] + 1
for y in range(v_range_start, row+1):
'''insert validation to reject ship clashing'''
self.player_ocean[y][col] = 1
self.placed_ships += [y, col]
self.refresh_ocean(side='player1')
def refresh_ocean(self, side=None):
self.player_canvas.delete('all')
self.ai_canvas.delete('all')
for y in range(len(self.bord_size)):
for x in range(len(self.bord_size)):
if self.player_ocean[y][x] == 1 and side == 'player1':
self.player_canvas.itemconfig(self.player_canvas.create_rectangle(
(x+1) * 30, (y+1) * 30, x * 30, y * 30, fill='green'))
else:
self.player_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')
if self.ai_ocean[y][x] == 1 and side == 'ai':
self.ai_canvas.itemconfig(self.ai_canvas.create_rectangle(
(x + 1) * 30, (y + 1) * 30, x * 30, y * 30, fill='green'))
else:
self.ai_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')
if __name__ == '__main__':
Player().mainloop()
Results:
your refresh_ocean had an off by 1 error
def refresh_ocean(self): # 1s turns to green
for y in range(10):
for x in range(10):
if self.player_ocean[y][x] == 1:
self.player_canvas.itemconfig(self.player_canvas.create_rectangle( x*30, y * 30, x*30+30, y*30+30, fill='green'))
and select placement was placing ships in with a negative index.
i changed your iteration from range(row-size, row) to range(row, row+size) and added bounds checking, but that should probably be moved to the movement handling.
def selectPlacement(event):
col = self.selectedCoord[0]
row = self.selectedCoord[1]
if self.direction == 'v':
if row + self.ship_sizes[self.shipChosen] > 9:
row = 10 - self.ship_sizes[self.shipChosen]
for y in range(row, row + self.ship_sizes[self.shipChosen]):
'''insert validation to reject ship clashing'''
self.player_ocean[y][col] = 1
self.placedships += [y,col]
self.refresh_ocean()
ps: your drawing new squares on top of the old squares. you might want to clear the ocean before drawing.

Categories