Here is a Python version, which you could adapt fairly easily:
'''A simple noughts and crosses game
This is really used as a test of tkinter under Python.
The actual game and its result are displayed on the screen
but no scoring is kept.
'''
import tkinter as tk
import tkinter.font as tkfont
BOXSIZE = 60
MARGIN = BOXSIZE * 2 / 3
HEIGHT = WIDTH = BOXSIZE * 3 + MARGIN * 2
FONTSIZE = int(-BOXSIZE * 3 / 4)
LINESIZE = FONTSIZE / -8
BUTTON_LEFT = 1
BUTTON_RIGHT = 3
squares = [
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
]
game_over = False
def new_game():
canvas.delete('all')
global squares
squares = [[0 for col in squares[0]] for row in squares]
xy1 = MARGIN
xy2 = xy1 + BOXSIZE * 3
for x in range(4):
row = x * BOXSIZE + MARGIN
canvas.create_line(row, xy1, row, xy2)
for y in range(4):
column = y * BOXSIZE + MARGIN
canvas.create_line(xy1, column, xy2, column)
canvas.pack()
global game_over
game_over = False
def screen_to_square(pos: int) -> int:
'''Convert the x and y screen coordinates to offsets into the squares matrix
This works for mouse X or Y co-ordinates since the frame is a
symmetrical 3 x 3 diagram
'''
xory = pos - MARGIN
xory //= BOXSIZE
if xory < 0 or xory > 2:
xory = None
return int(xory)
def draw_letter(x: int, y: int, XO: str, colour: str) -> None:
x = MARGIN + x * BOXSIZE + BOXSIZE // 2
y = MARGIN + y * BOXSIZE + BOXSIZE // 2
canvas.create_text(x, y, text=XO, font=font, fill=colour)
def draw_line(x1: int, y1: int, x2: int, y2: int, colour: str) -> None:
offset = MARGIN + BOXSIZE // 5
x1 = x1 * BOXSIZE + offset
x2 = x2 * BOXSIZE + offset
y1 = y1 * BOXSIZE + offset
y2 = y2 * BOXSIZE + offset
adjustment1 = BOXSIZE // 3
adjustment2 = adjustment1 * 2
if y1 == y2:
x2 += adjustment2
y1 += adjustment1
y2 += adjustment1
elif x1 == x2:
y2 += adjustment2
x1 += adjustment1
x2 += adjustment1
elif x1 < x2 and y1 < y2:
x2 += adjustment2
y2 += adjustment2
else:
y1 += adjustment2
x2 += adjustment2
canvas.create_line(x1, y1, x2, y2, width=LINESIZE, fill=colour)
global game_over
game_over = True
def on_click(event: tk.Event) -> None:
if game_over:
return
x = screen_to_square(event.x)
y = screen_to_square(event.y)
if x == None or y == None or squares[x][y] != 0:
return
XO = 'X' if event.num == BUTTON_LEFT else 'O'
colour = 'red' if event.num == BUTTON_LEFT else 'blue'
squares[x][y] = XO
draw_letter(x, y, XO, colour)
for row in range(3):
if (squares[row][0] != 0
and squares[row][1] == squares[row][0]
and squares[row][2] == squares[row][0]):
draw_line(row, 0, row, 2, colour)
return
for col in range(3):
if (squares[0][col] != 0
and squares[1][col] == squares[0][col]
and squares[2][col] == squares[0][col]):
draw_line(0, col, 2, col, colour)
return
if (squares[0][0] != 0
and squares[1][1] == squares[0][0]
and squares[2][2] == squares[0][0]):
draw_line(0, 0, 2, 2, colour)
elif (squares[2][0] != 0
and squares[1][1] == squares[2][0]
and squares[0][2] == squares[2][0]):
draw_line(0, 2, 2, 0, colour)
root = tk.Tk()
root.title('Noughts and Crosses')
font = tkfont.Font(root, size=FONTSIZE, weight=tkfont.BOLD)
restart_button = tk.Button(root, text="New Game", command=new_game)
restart_button.pack(side=tk.TOP)
canvas = tk.Canvas(root, width=WIDTH, height=HEIGHT)
new_game()
canvas.bind("<Button-1>", on_click)
canvas.bind("<Button-3>", on_click)
root.mainloop()