Python Forum
Tkinter Tic Tac Toe updated
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Tkinter Tic Tac Toe updated
#1
Here is the 2nd go.
Hope you enjoy.
As always, I welcome feedback.

#! /usr/bin/env python3
'''Tkinter TIC TAC TOE'''

# Do the imports
import tkinter as tk
from tkinter import ttk
import os
import random as rnd


# This is so rgb colors can be used
def rgbcolor(rgb):
    return '#%02x%02x%02x' % rgb


class Game:
    ''' Game Class '''
    def __init__(self, parent):
        # Setup the root window
        self.parent = parent
        self.parent.columnconfigure(0, weight=1)
        self.parent.rowconfigure(0, weight=1)

        # Create the main container frame
        self.mainframe = tk.Frame(self.parent, height=510, bg=rgbcolor((80, 40, 35)))
        self.mainframe.grid(row=0, column=0, sticky='news')
        self.mainframe.grid_columnconfigure(0, weight=3)
        self.mainframe.grid_rowconfigure(0, weight=3, )

        # Create the header frame
        self.headerframe = tk.Frame(self.mainframe, bg=rgbcolor((80, 40, 35)), height=40)
        self.headerframe.grid(row=0, column=0, sticky='new')
        self.headerframe.grid_columnconfigure(0, weight=3)

        # This will display the header text
        self.header = tk.Canvas(self.headerframe, height=100, width=600, bg=rgbcolor((80, 40, 35)), highlightthickness=0)
        self.header.create_text(600/2.12, 100/1.93, text='TIC TAC TOE', fill=rgbcolor((45,10,5)), font=('sans', int(600/15), 'bold'))
        self.header.create_text(600/2.09, 100/1.87, text='TIC TAC TOE', fill='white', font=('sans', int(600/15), 'bold'))
        self.header.grid(row=0, column=0)

        # Container frame for the buttons
        self.btnframe = tk.Frame(self.mainframe, bg=rgbcolor((80,40,35)), pady=15)
        self.btnframe.grid(row=3, column=0, sticky='s')
        self.btnframe.grid_columnconfigure(0, weight=3)

        # Create the buttons
        btn_style = ttk.Style()
        btn_style.configure('Wild.TButton', foreground='tomato', borderwidth=1, background=rgbcolor((100,60,55)), \
                            highlightthickness=1, highlightcolor=rgbcolor((100,60,55)), font='sans 16 bold')
        btn_style.map('Wild.TButton',
                background = [('active',rgbcolor((125,85,80)))],
                foreground = [('active', 'orange')]
                )
        self.btn = ttk.Button(self.btnframe, text=' Reset ', cursor='hand2', style='Wild.TButton', \
                              command=self.reset)
        self.btn.grid(row=0, column=0, sticky='s', padx=32)

        self.ext_btn = ttk.Button(self.btnframe, text=' Quit ', style='Wild.TButton', command=os.sys.exit)
        self.ext_btn.grid(row=0, column=1, sticky='s', padx=32)

        # Create a message container frame
        self.msgframe = tk.Frame(self.mainframe, borderwidth=1, bg=rgbcolor((80,40,35)))
        self.msgframe.grid(row=2, column=0, pady=8, sticky='n')

        # The label will display game winner
        self.msg_label = tk.Label(self.msgframe, width=44, anchor='w', fg='tomato', bg=rgbcolor((80,40,35)))
        self.msg_label.grid(row=0, column=0, sticky='nw')

        # Initiate the game frame
        self.play()


    # This function will create the game board
    def play(self):
        # Create the container frame for the grid
        self.gameframe = tk.Frame(self.mainframe, relief = 'solid', highlightthickness=3, \
                                  highlightcolor='brown', highlightbackground='tomato', \
                                  borderwidth=3, width=350, bg=rgbcolor((180,140,135)), height=300)
        self.gameframe.grid(row=1,column=0, sticky='n')
        self.gameframe.grid_columnconfigure(0, weight=3)
        self.gameframe.grid_rowconfigure(0, weight=3)

        # This will create a 3x3 label grid and bind each label to the left mouse button
        for i in range(3):
            for j in range(3):
                self.label = tk.Frame(self.gameframe, relief='solid', width=150, height=90, \
                                      borderwidth=1, bg=rgbcolor((180,140,135)))
                self.label.grid(row=j, column=i, sticky='news')
                self.label.bind('<Button-1>', self.player_pick)

        # Create the what is needed for a win. Three 1's for player and three 2's for computer
        self.x_win = [1, 1, 1]
        self.o_win = [2, 2, 2]

        # This is where either a 1 or two will be placed depending on which player went.
        # This represents our 3x3 grid
        self.grid = [[0, 0, 0],[0, 0, 0],[0, 0, 0]]

        # This is the grid coordinates used for the computer to make a random choice.
        # This gets updated when each player makes a choice. e.g. 1 gets removed
        # so it can not be chosen again.
        self.grid_cords = [(0, 0), (0, 1), (0, 2),
                           (1, 0), (1, 1), (1, 2),
                           (2, 0), (2, 1), (2, 2)]

    # Resets the game board
    def reset(self):
        self.winner_label.destroy()
        self.gameframe.destroy()
        self.play()
        # self.msg_label['text'] = ''
        self.gameframe.update()

    # This places either X or O on the games board
    def do_entries(self, text,row, col, fg='brown'):
        label = tk.Label(self.gameframe, fg=fg, bg=rgbcolor((180,140,135)), text=text, \
                         font=('serif', int(150/2 - 85/3), 'bold'))
        label.grid(column = col, row=row)
        # self.labels[col][row]['text'] = text

    # Used for player turn
    def player_pick(self, event):

        # Get the coordinates for the clicked grid
        x_cord = event.x_root - self.gameframe.winfo_rootx()
        y_cord = event.y_root - self.gameframe.winfo_rooty()

        # Store the x and y coordinates in a varible
        loc = self.gameframe.grid_location(x_cord, y_cord)
        try:
            # Call the function to place the entry to the board
            self.do_entries('X',loc[1],loc[0])

            # Remove the grid coordinats from the grid cords above
            self.grid_cords.remove(loc)

            # Store one in the self.grid so we will be able to check for a winneror tie
            self.grid[loc[1]][loc[0]] = 1
        except ValueError as error:
            pass

        # Computers turn
        self.computer()

        # Check to see if any player has won or if there is a tie.
        # Display message of the outcome
        if self.x_win in self.possibilities():
            self.gameframe.destroy()
            self.gameframe.update()
            self.winner()
        elif self.o_win in self.possibilities():
            self.gameframe.destroy()
            self.mainframe.update()
            self.winner()
        else:
            if not self.grid_cords:
                self.gameframe.destroy()
                self.gameframe.update()
                self.winner()

    def winner(self):
        if self.x_win in self.possibilities():
            text = 'Congradulations! You have won!'
        elif self.o_win in self.possibilities():
            text = 'Oh! I\'m sorry, you have lost'
        else:
            text = 'Wow! A tie game!'

        self.winner_label = tk.Label(self.parent, text=text, fg='tomato', \
                         font = 'sans 18 bold', bg=rgbcolor((80,40,35)))
        self.winner_label.grid(column=0, row=0)

    # The computer player setup. All is the same as for player
    def computer(self):
        if self.grid_cords:
            try:
                loc = rnd.choice(self.grid_cords)
                self.grid_cords.remove(loc)
                self.do_entries('0', loc[1], loc[0], fg=rgbcolor((150,60,20)))
                self.grid[loc[1]][loc[0]] = 2
            except ValueError as error:
                print(error)

    # Setup the win possibilities and return
    def possibilities(self):
        # Columns
        col1 = [self.grid[0][0], self.grid[0][1], self.grid[0][2]]
        col2 = [self.grid[0][1], self.grid[1][1], self.grid[2][1]]
        col3 = [self.grid[0][2], self.grid[1][2], self.grid[2][2]]

        # Rows
        row1 = [self.grid[0][0], self.grid[1][0], self.grid[2][0]]
        row2 = [self.grid[1][0], self.grid[1][1], self.grid[1][2]]
        row3 = [self.grid[2][0], self.grid[2][1], self.grid[2][2]]

        # Diagonals
        diag1 = [self.grid[0][0], self.grid[1][1], self.grid[2][2]]
        diag2 = [self.grid[2][0], self.grid[1][1], self.grid[0][2]]

        wins = [col1, col2, col3, row1, row2, row3, diag1, diag2]
        return wins


def main():
    root = tk.Tk()
    root.title('TIC TAC TOE')
    root['borderwidth'] = 2
    root['relief'] = 'solid'
    root['highlightthickness'] = 10
    root['highlightcolor'] = 'tomato'
    root['highlightbackground'] = 'tomato'
    root['bg'] = rgbcolor((80,40,35))
    root.geometry('600x510+150+150')
    root.resizable(width=False, height=False)
    Game(root)
    root.mainloop()

if __name__ == '__main__':
    main()
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags


Reply


Messages In This Thread
Tkinter Tic Tac Toe updated - by menator01 - Jun-10-2020, 02:18 PM
RE: Tkinter Tic Tac Toe updated - by aary - Jun-10-2020, 04:03 PM
RE: Tkinter Tic Tac Toe updated - by Yoriz - Jun-10-2020, 04:37 PM
RE: Tkinter Tic Tac Toe updated - by menator01 - Jun-10-2020, 05:35 PM

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020