TIC_TAC_TOE

Tic Tac Toe with ttkbootstrap and pygame

Simple and good looking tic tac toe game including sound. The game is only for 2 player, sadly I am not ready enough to add the AI boot (I don’t want to add the random boot :) )

Description

The game is made only in ttkboostrap and some little pygame for the sound. You can customize this game as you want. The main thing you can do is to change the color and many things. To see them check the OPTION part.

Installation

Use the package manager pip to install ttkboostrap and the pygame

pip install ttkboostrap
pip install pygame 

Option

The configuration.py file is made in that the information is stored in dictionary/hash-map or like json file. In this way is very easy to change the color, the font and kind of everthing you want :/ (so be carefull)

Visual

Tic_Tac_Toe.png

Contributing

Pull request are wellcome, if you have any advice I am open. If you know to add the AI boot, I will very happy to add to my code

License

GNU GPLv3

Source Code: main.py

import os
import sys
import ttkbootstrap as ttk

from tkinter import IntVar
from widgets import BoardGame, BoardScore
from configuration import (
    # layout
    MAIN_SIZE, BOARD_GAME, BOARD_SCORE, RESET_BUTTON,
    # style
    FRAME_STYLE_SCORE, FRAME_STYLE_GAME, BUTTON_BOARD_STYLE, BUTTON_RESET_STYLE, LABEL_SCORE_STYLE,
    )

# import the modules for windows (it works  only on windows)

try:
    from ctypes import windll, byref, sizeof, c_int
except Exception:
    pass


def path_resource(relative_path: str) -> str:
    """
    it take the relative path and return the absolute path of the file from your system, is used for making the
    app into a exe file for window

    """
    try:
        base_path: str = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath('.')
    return os.path.join(base_path, relative_path)


class TicTacToe(ttk.Window):
    
    player_1: IntVar
    player_2: IntVar
    tie_score: IntVar
    
    def __init__(self):
        super().__init__()
        
        self.bind('<Alt-s>', lambda event: self.destroy())
        self.title('')
        self.set_emtpy_icon()
        self.set_title_bar_color()
        self.set_window_size(width = MAIN_SIZE[0], height = MAIN_SIZE[1])
        
        # set up the style
        self.Style = ttk.Style(theme = 'darkly')
        
        # style for the score/ board_score
        self.Style.configure(
                
                background = BOARD_SCORE['BACKGROUND'],
                style = FRAME_STYLE_SCORE,
                
                )
        
        self.Style.configure(
                
                background = BOARD_GAME['BACKGROUND_FRAME'],
                style = FRAME_STYLE_GAME,
                
                )
        
        self.Style.configure(
                
                background = BOARD_GAME['BACKGROUND'],
                bordercolor = BOARD_GAME['BORDER_COLOR'],
                borderthickness = BOARD_GAME['BORDER_THICKNESS'],
                borderwidth = BOARD_GAME['BORDER_WIDTH'],
                font = (BOARD_GAME['FONT'], BOARD_GAME['FONT_SIZE']),
                justify = BOARD_GAME['JUSTIFY'],
                relief = BOARD_GAME['RELIEF'],
                style = BUTTON_BOARD_STYLE,
                
                )
        
        self.Style.map(
                
                style = BUTTON_BOARD_STYLE,
                foreground = [
                        ('active', BOARD_GAME['TEXT_COLOR_ACTIVE']),
                        ('disabled', BOARD_GAME['TEXT_COLOR_DISABLED'])
                        ],
                background = [
                        ('active', BOARD_GAME['HOVER_COLOR_ACTIVE']),
                        ('disabled', BOARD_GAME['HOVER_COLOR_DISABLED'])
                        ]
                )
        
        self.Style.configure(
                
                background = RESET_BUTTON['BACKGROUND'],
                bordercolor = RESET_BUTTON['BORDER_COLOR'],
                borderthickness = RESET_BUTTON['BORDER_THICKNESS'],
                borderwidth = RESET_BUTTON['BORDER_WIDTH'],
                font = (RESET_BUTTON['FONT'], RESET_BUTTON['SIZE']),
                justify = RESET_BUTTON['JUSTIFY'],
                relief = RESET_BUTTON['RELIEF'],
                style = BUTTON_RESET_STYLE,
                
                )
        self.Style.map(
                
                style = BUTTON_RESET_STYLE,
                foreground = [
                        ('active', RESET_BUTTON['TEXT_COLOR_ACTIVE']),
                        ('disabled', RESET_BUTTON['TEXT_COLOR_DISABLED'])
                        ],
                background = [
                        ('active', RESET_BUTTON['HOVER_COLOR_ACTIVE']),
                        ('disabled', RESET_BUTTON['HOVER_COLOR_DISABLED'])]
                
                )
        
        self.Style.configure(
                
                background = BOARD_SCORE['BACKGROUND'],
                font = (BOARD_SCORE['FONT'], BOARD_SCORE['FONT_SIZE']),
                foreground = BOARD_SCORE['TEXT_COLOR'],
                style = LABEL_SCORE_STYLE,
                
                )
        
        #   set player data
        self.player_1 = ttk.IntVar(value = 0)
        self.player_2 = ttk.IntVar(value = 0)
        self.tie_score = ttk.IntVar(value = 0)
        
        # set widgets
        self.board_game = BoardGame(
                
                parent = self,
                style_cells = BUTTON_BOARD_STYLE,
                style_frame = FRAME_STYLE_GAME,
                player_1 = self.player_1,
                tie = self.tie_score,
                player_2 = self.player_2,
                
                )
        
        self.board_score = BoardScore(
                
                parent = self,
                style_labels = LABEL_SCORE_STYLE,
                style_frame = FRAME_STYLE_SCORE,
                style_button = BUTTON_RESET_STYLE,
                player_1 = self.player_1,
                tie = self.tie_score,
                player_2 = self.player_2,
                function = self.clean_board
                
                )
        
        # run
        self.mainloop()
    
    def clean_board(self):
        """
        It clean the board and reset the score
        """
        self.board_game.clean_board()
        self.player_1.set(0)
        self.player_2.set(0)
        self.tie_score.set(0)
    
    def set_emtpy_icon(self) -> None:
        """
        It sets the icon to  one empty from the title bar

        """
        try:
            path_image: str = path_resource('image/empty.ico')
            self.iconbitmap(path_image)
        except Exception:
            pass
    
    def set_window_size(self, width: int, height: int) -> None:
        """
        It adjust the window size to be in the center of the screen
        
        """
        left = int(self.winfo_screenwidth() / 2 - width / 2)
        top = int(self.winfo_screenheight() / 2 - height / 2)
        self.geometry(f'{width}x{height}+{left}+{top}')
    
    def set_title_bar_color(self) -> None:
        """
    It works only on Windows, not on GNU/Linux and macOS.
        """
        try:
            HWND = windll.user32.GetParent(self.winfo_id())
            DWMWA_ATTRIBUTE: int = 35  # target the title bar
            color_tile: int = 0x00030303
            windll.dwmapi.DwmSetWindowAttribute(HWND, DWMWA_ATTRIBUTE, byref(c_int(color_tile)), sizeof(c_int))
        except Exception:
            pass


if __name__ == '__main__':
    
    # starts the game
    TicTacToe()