3
\$\begingroup\$

`I made this Tic-Tac-Toe game first, by using user input in the console here: https://pastebin.com/6zLjrWcf , and now new and improved using Tkinter:

import tkinter as tk
from tkinter import ttk
import time
def create_button(relx, rely):
 button = tk.Button(width=10, height=2, command=lambda: callback(button))
 button.place(relx=relx, rely=rely)
 return button
def check_win(): 
 if (buttons[0]['text'] == buttons[1]['text'] == buttons[2]['text'] != '') or \
 (buttons[3]['text'] == buttons[4]['text'] == buttons[5]['text'] != '') or \
 (buttons[6]['text'] == buttons[7]['text'] == buttons[8]['text'] != '') or \
 (buttons[0]['text'] == buttons[3]['text'] == buttons[6]['text'] != '') or \
 (buttons[1]['text'] == buttons[4]['text'] == buttons[7]['text'] != '') or \
 (buttons[2]['text'] == buttons[5]['text'] == buttons[8]['text'] != '') or \
 (buttons[2]['text'] == buttons[4]['text'] == buttons[6]['text'] != '') or \
 (buttons[0]['text'] == buttons[4]['text'] == buttons[8]['text'] != ''):
 return True
 else:
 return False
def callback(button):
 global turn, x
 if x == 1:
 time.sleep(1)
 game.quit()
 invalid['text'] = ''
 if button['text'] != '':
 invalid['text'] = 'Invalid space try again'
 return
 button['text'] = turn
 if check_win():
 invalid['text'] = 'Player ' + turn + ' WINS!!!!!'
 x = 1
 turn = ('0' if turn == 'X' else 'X')
 label_button['text'] = 'PLAYER ' + turn + '\'S TURN.'
x = 0
turn = 'X'
game = tk.Tk()
game.title('TicTacToe')
game.geometry('700x500')
buttons = []
for i in range(1, 10):
 button_created = create_button(0.25 if i / 3 <= 1 else 0.45 if i / 3 <= 2 else 0.65, 0.2 if i in [1, 4, 7] else
 0.4 if i in [2, 5, 8] else 0.6)
 buttons.append(button_created)
label_button = ttk.Button(game, text='PLAYER ' + turn + '\'S TURN.', style='Fun.TButton', width=20, state='disabled')
label_button.pack(pady=30)
invalid = tk.Label(text='')
invalid.place(relx=0.4, rely=0.12)
game.mainloop()

My main question is if there is a way to compact check_win()? Also please review the rest of the code.

asked Aug 1, 2019 at 11:48
\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

Let us begin with some layout. This is a typical grid use case so that you won't have to manually manage grid. At the lowest level, a grid structure essentially places buttons by calculating coordinates. But this gets tedious over time, that's why a grid layout is provided. Also, it was a clever way of cheking win by being symbol agnostic. A normal tic tac toe game would have used checkwin(symbol) to determine win.

On strings

To escape ' within ' ' you can use " instead. From

'\'S TURN.'

to

"'S TURN."

and you can also use string formatting to clear up some clutter.

"PLAYER {}'S TURN.".format(turn)

On layout

Modifying your create_button function to this allows a grid structure

def create_button(x, y):
 button = tk.Button(width=10, height=2, command=lambda: callback(button))
 button.grid(row=x, column=y)
 return button

Then we modify others since different layouts can't be mixed

label_button = ttk.Button(
 game, 
 text="PLAYER {}'S TURN.".format(turn), 
 style='Fun.TButton', width=20, 
 state='disabled')
label_button.grid(row=0, column=1)
invalid = tk.Label(text='')
invalid.grid(row=4, column=1)

adding the buttons can be then done as

buttons = []
buttons.append(create_button(1, 0))
buttons.append(create_button(1, 1))
buttons.append(create_button(1, 2))
buttons.append(create_button(2, 0))
buttons.append(create_button(2, 1))
buttons.append(create_button(2, 2))
buttons.append(create_button(3, 0))
buttons.append(create_button(3, 1))
buttons.append(create_button(3, 2))

You can use a loop for the row and itertools.cycle for the 0, 1, 2 if you want to simplify it.

The check_win function

  • Simplifying if

Adding a () to if statements allows you to write or without \


if ... :
 ...
to
if (...):
 ...

thus the win_function can be simplified from

if (buttons[0]['text'] == buttons[1]['text'] == buttons[2]['text'] != '') or \
(buttons[3]['text'] == buttons[4]['text'] == buttons[5]['text'] != '') or \

to

def check_win():
 if (
 (buttons[0]['text'] == buttons[1]['text'] == buttons[2]['text'] != '') or
 (buttons[3]['text'] == buttons[4]['text'] == buttons[5]['text'] != '') or
 ...
 ):
 return True
 else:
 return False
  • Simplifying values write-up

This can also be further simplified by defining a function to replace buttons[0]['text']

def btext(i):
 return buttons[i]['text']

and using it

def check_win():
 if (
 (btext(0) == btext(1) == btext(2) != '') or
 (btext(3) == btext(4) == btext(5) != '') or
 (btext(6) == btext(7) == btext(8) != '') or
 (btext(0) == btext(3) == btext(6) != '') or
 (btext(1) == btext(4) == btext(7) != '') or
 (btext(2) == btext(5) == btext(8) != '') or
 (btext(2) == btext(4) == btext(6) != '') or
 (btext(0) == btext(6) == btext(8) != '')
 ):
 return True
 else:
 return False

On architecture

A common pattern is the MVC (Model, View, Controller). While checking and updating gui directly works here, you might consider adding states in a structure like this:

board = [
 ['', '', ''],
 ['', '', ''],
 ['', '', '']
]

Operations are done on this and the gui is updated according to this.

answered Aug 3, 2019 at 5:16
\$\endgroup\$
-1
\$\begingroup\$

From : Python Tic Tac Toe Game

 win_commbinations = ((0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6), (1, 4, 7), (2, 5, 8), (0, 4, 8), (2, 4, 6))
for a in win_commbinations:
 if board[a[0]] == board[a[1]] == board[a[2]] == "X":
 print("Player 1 Wins!\n")
 print("Congratulations!\n")
 return True
 if board[a[0]] == board[a[1]] == board[a[2]] == "O":
 print("Player 2 Wins!\n")
 print("Congratulations!\n")
 return True
 for a in range(9):
 if board[a] == "X" or board[a] == "O":
 count += 1
 if count == 9:
 print("The game ends in a Tie\n")
 return True

This alternative solution is a bit cleaner + includes a "Tie" check, which your original solution doesn't check ( just remove if you consider it irrelevant ofc )

answered Aug 1, 2019 at 15:28
\$\endgroup\$
1
  • \$\begingroup\$ You have not reviewed the code, but instead presented your own solution. While the code may improve some aspects, it does not have a tkinter GUI like the original code does. \$\endgroup\$ Commented Aug 1, 2019 at 16:11

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.