`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 tkfrom tkinter import ttkimport timedef create_button(relx, rely): button = tk.Button(width=10, height=2, command=lambda: callback(button)) button.place(relx=relx, rely=rely) return buttondef 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 Falsedef 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 = 0turn = '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.
2 Answers2
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 yourcreate_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 buttonThen 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 anditertools.cycle for the0, 1, 2 if you want to simplify it.
Thecheck_win function
- Simplifying if
Adding a() to if statements allows you to writeor without\
if ... : ...toif (...): ...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 replacebuttons[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 FalseOn 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.
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 TrueThis 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 )
- \$\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\$spyr03– spyr032019-08-01 16:11:52 +00:00CommentedAug 1, 2019 at 16:11
You mustlog in to answer this question.
Explore related questions
See similar questions with these tags.
