Tkinter Tic Tac Toe Drawing a shape in a certain box
You can "discretize" the x
and y
values by integer-dividing and then multiplying with the width of the individual cells (and adding some offset for the center).
def drawo(event): x2, y2 = event.x, event.y x2 = x2 // 300 * 300 + 150 y2 = y2 // 300 * 300 + 150 ...
Same for drawx
.
Alternatively, you could use different canvas elements (or buttons, labels or similar) for the different cells in the grid and get the clicked widget
from the event
.
You need to bind the mouse click event to canvas:
w.bind('<Button-1>', on_click)
Then determine which cell is clicked in on_click
handler:
SIZE = 300player = 1 # 1 for O, 2 for Xdef on_click(event): global m global player row = event.y // SIZE col = event.x // SIZE # check whether the cell is not filled yet if m[row][col] == 0: # calculate the center of the cell cx = col * SIZE + SIZE // 2 cy = row * SIZE + SIZE // 2 # draw X or O based on current player if player == 1: draw_O(cx, cy) else: draw_X(cx, cy) # set cell is filled m[row][col] = player # now you need to check whether current player wins ... # if no one wins, toggle player player = 2 if player == 1 else 1def draw_O(x, y): radius = SIZE // 3 w.create_oval(x-radius, y-radius, x+radius, y+radius, width=5, tag='cell') # tag is used for resetting the gamedef draw_X(x, y): radius = SIZE // 3 w.create_line(x-radius, y-radius, x+radius, y+radius, width=5, tag='cell') w.create_line(x+radius, y-radius, x-radius, y+radius, width=5, tag='cell')
If you want to reset the game:
def reset_game(): global m global player # remove all 'O' and 'X' w.delete('cell') m = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] player = 1
For better design, put all the above logic in a class (inherited from Canvas
). Then you can use instance variables instead of global variables.
To add more detail to tobias_k's answer, the below code will draw an X when the right mouse button is clicked and an O when the left mouse button is clicked.
An improvement in the code could be to use a variable to define the size of the canvas and each X/O rather than hard coding 200 or 300.
from tkinter import *ttt = Tk()ttt.title("Tic Tac Toe")w = Canvas(ttt, width = 902, height = 902)w.configure (bg = "white")w.pack()m = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]def drawx(event): print("drawx") x, y = event.x, event.y x0 = x // 300 * 300 + 50 y0 = y // 300 * 300 + 50 x1 = x0 + 200 y1 = y0 + 200 #return w.create_oval(x0, y0, x1, y1) w.create_line(x0,y0,x1,y1, fill = "black") w.create_line(x0,y0+200,x1,y1-200, fill = "black")def drawo(event): print("drawo") x, y = event.x, event.y x0 = x // 300 * 300 + 50 y0 = y // 300 * 300 + 50 x1 = x0 + 200 y1 = y0 + 200 return w.create_oval(x0, y0, x1, y1)w.create_line(0, 300, 901, 300, fill = "black") w.create_line(0, 601, 901, 601, fill = "black")w.create_line(300, 0, 300, 901, fill = "black")w.create_line(601, 0, 601, 901, fill = "black")w.bind('<Button-1>',drawo)w.bind('<Button-3>',drawx)ttt.mainloop()