0

I'll try to explain this to my best ability. Short story short, making a tic tac toe game for a school project. I have all the code necessary i think, but when i run my code, tkinter window opens no problem, but when i am to click in one of the squares where i can place a "x" or a "o" my image wont load into the grid.

When i click, this is one the errors that pops up: line 2776, in _create return self.tk.getint(self.tk.call( _tkinter.TclError: unknown option "562.5"

If i was to guess, the error must be in both "def draw_o" and "def draw_x"

If you want to try the code here is the images to download: https://i.sstatic.net/qW9Bp.jpg

If relevant image of assignment: https://i.sstatic.net/lewRP.jpg

from math import log
from tkinter import *
import numpy as np

size = 600
symbol_size = (size / 3 - size / 8) /2
symbol_thick = 50
symbol_x_color = '#EE4035'
symbol_o_color = '#0492CF'
green = '#7BC043'



class cell:

    def __init__(self):
        self.window = Tk()
        self.window.title("Bondesjakk/Tic Tac Toe")
        self.canvas = Canvas(self.window, width = size, height = size)
        self.canvas.pack()
        self.window.bind("<Button-1>", self.click)

        

        self.initialize_board()
        self.player_x_turns = True
        self.board_status = np.zeros(shape=(3, 3) )

        self.player_x_starts = True
        self.reset_board = False
        self.gameover = False
        self.tie = False
        self.x_wins = False
        self.o_wins = False

        self.x_score = False
        self.o_score = False
        self.tie_score = False

        
    
    def mainloop(self):
        self.window.mainloop()
    
    def initialize_board(self):
        for i in range(2):
            self.canvas.create_line( (i + 1) * size / 3, 0, (i + 1) * size / 3, size)
        
        for i in range(2):
            self.canvas.create_line(0, (i + 1) * size / 3, size, (i + 1) * size / 3)

    def play_again(self):
        self.initialize_board()
        self.player_x_starts = not self.player_x_starts
        self.player_x_turns = self.player_x_starts
        self.board_status = np.zeros(shape =(3, 3) )

    def draw_o(self, logical_pos):
        o_image = PhotoImage('book/pybook/image/o.gif')
        logical_pos = np.array(logical_pos)
        grid_pos = self.convert_logical_to_grid_pos(logical_pos)
        self.canvas.create_image(grid_pos[0] - symbol_size, grid_pos[1] - symbol_size,
                                 grid_pos[0] + symbol_size, grid_pos[1] + symbol_size, width = symbol_thick,
                                 image = o_image)
    
    def draw_x(self, logical_pos):
        x_image = PhotoImage('book/pybook/image/x.gif') 
        grid_pos = self.convert_logical_to_grid_pos(logical_pos)
        self.canvas.create_image(grid_pos[0] - symbol_size, grid_pos[1] - symbol_size,
                                 grid_pos[0] + symbol_size, grid_pos[1] + symbol_size, width = symbol_thick,
                                 image = x_image)
    
    def display_gameover(self):

        if self.x_wins:
            self.x_score += 1
            text = "Winner: Player 1(x)"
            color = symbol_x_color

        elif self.o_wins:
            self.o_score += 1
            text = "Winner: Player 2(o)"
            color = symbol_o_color
        
        else:
            self.tie_score += 1
            text = "It's a tie"
            color = "gray"

        self.canvas.delete("all")
        self.canvas.create_text(size / 2, size / 3, font = "cmr 60 bold", fill = color, text = text)

        score_text = 'Scores \n'
        self.canvas.create_text(size / 2, 5 * size / 8, font = "cmr 40 bold", fill = green, text = score_text)

        score_text = 'Player 1 (x) : ' + str(self.x_score) + '\n'
        score_text = 'Player 2 (o) : ' + str(self.o_score) + '\n'
        score_text = 'Tie          : ' + str(self.tie_score) + '\n'

        self.canvas.create_text(size / 2, 3 * size / 4, font = "cmr 30 bold", fill = green, text = score_text)

        self.reset_board = True

        score_text = "Click to play again \n"
        self.canvas.create_text(size / 2, 15* size / 16, font = "cmr 20 bold", fill = "gray", text = score_text)

    def convert_logical_to_grid_pos(self, logical_pos):
        logical_pos = np.array(logical_pos, dtype = int)
        return (size / 3) * logical_pos + size / 6
    
    def convert_grid_to_logical_pos(self, grid_pos):
        grid_pos = np.array(grid_pos)
        return np.array(grid_pos // (size / 3), dtype = int)
    
    def is_grid_occupied(self, logical_pos):
        if self.board_status[logical_pos[0] ][logical_pos[1] ] == 0:
            return False
        else:
            return True
    
    def is_winner(self, player):
        player = -1 if player == "x" else 1

        #Three in a row
        for i in range(3):
            if self.board_status[i][1] == self.board_status[i][2] == player:
                return True
            if self.board_status[0][1] == self.board_status[2][i] == player:
                return True
        
        #Diagonals
        if self.board_status[0][0] == self.board_status[1][1] == self.board_status[2][2] == player:
            return True
        if self.board_status[2][0] == self.board_status[1][1] == self.board_status[0][2] == player:
            return True

        return False
    
    def is_tie(self):
        r, c = np.where(self.board_status == 0)
        tie = False
        if len(r) == 0:
            tie = True
        
        return tie

    def is_gameover(self):
        self.x_wins = self.is_winner("x")
        if not self.x_wins:
            self.o_wins = self.is_winner("o")

        if not self.o_wins:
            self.tie = self.is_tie()
        
        gameover = self.x.wins or self.o.wins or self.tie

        if self.x_wins:
            print("x wins!")
        if self.o_wins:
            print("o wins!")
        if self.tie:
            print("It's a tie!")
        
        return gameover
    
    def click(self, event):
        grid_pos = [event.x, event.y]
        logical_pos = self.convert_grid_to_logical_pos(grid_pos)

        if not self.reset_board:
            if self.player_x_turns:
                if not self.is_grid_occupied(logical_pos):
                    self.draw_x(logical_pos)
                    self.board_status[logical_pos[0] ][logical_pos[1] ] = -1
                    self.player_x_turns = not self.player_x_turns
            
            else:
                if not self.is_grid_occupied(logical_pos):
                    self.draw_o(logical_pos)
                    self.board_status[logical_pos[0] ][logical_pos[1] ] = 1
                    self.player_x_turns = not self.player_x_turns
            
            if self.gameover():
                self.display_gameover()
        else:
            self.canvas.delete("all")
            self.play_again()
            self.reset_board = False

game_instance = cell()
game_instance.mainloop()
3
  • It would be more helpful if you provide a minimal reproducible example. Much easier to figure out the problem if there are as few lines of code as possible Commented Nov 25, 2021 at 19:39
  • always put full error message (starting at word "Traceback") in question (not in comments) as text (not screenshot, not link to external portal). There are other useful information. Commented Nov 25, 2021 at 22:34
  • full error message should show you in which line you have problem and first you could use print() to see what you have in variables. It is called "print debuging". It seems you have wrong value in some variable or use it in wrong way. It show problem with option "562.5" - so maybe instead of var="562.5" it gets something like "562.5"=var Commented Nov 25, 2021 at 22:35

1 Answer 1

1

In create_image() you use x1, y1, x2, y2, width=... but it expects only position (x1,y1) as tuple (without x2,y2) and without width=...

        x = grid_pos[0] - symbol_size
        y = grid_pos[1] - symbol_size
        self.canvas.create_image( (x, y), image=x_image)

EDIT:

You have other mistakes

In line if self.gameover() you have to remove ()

--

If you use PhotoImage('book/pybook/image/o.gif') then it treats it as string with image's data, not as path to file. You have to use file=

o_image =  PhotoImage(file='book/pybook/image/o.gif')

--

But there is another problem. There is bug in PhotoImage which removes image from memory when it is assigned to local variable in function. You should assign to class variable using self.

self.o_image =  PhotoImage(file='book/pybook/image/o.gif')

--

And here another problem. You load the same image again and again and you assign it to the same variable - so bug removes previous image from memory and it removes it from canvas.

You could load it only once in __init__ and later use all time the same self.o_image, self.x_image

def __init___(...):

    self.o_image =  PhotoImage(file='book/pybook/image/o.gif')
    self.x_image =  PhotoImage(file='book/pybook/image/x.gif')

Doc (effbot.org in archive.org): PhotoImage, Canvas

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.