import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from tkinter import font
import os
import random
import re
# Initialize the main application window
root = tk.Tk()
# Define window dimensions
window_width = 1600
window_height = 900
# Set the window title
root.title('FFA Tournament')
# Set the window size
root.geometry(f'{window_width}x{window_height}')
# Disable resizing of the window
root.resizable(False, False)
# Center the window on the screen
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
x_coordinate = int((screen_width/2) - (window_width/2))
y_coordinate = int((screen_height/2) - (window_height/2))
# Set the window position to the center of the screen
root.geometry(f"+{x_coordinate}+{y_coordinate}")
# Create the main container frame
main_container = tk.Frame(root)
main_container.pack(fill='both', expand=True)
# Configure the grid layout for the main container frame
for column in range(4):
main_container.columnconfigure(column, weight=1)
main_container.rowconfigure(0, weight=9) # 90% of the vertical space for the story containers
main_container.rowconfigure(1, weight=1) # 10% of the vertical space for the submit button
# List to keep track of the textboxes
textboxes = []
# Function to swap the contents of two textboxes and update the contestants list
def swap_stories(textbox1, textbox2):
# Determine if we are in the finals round
in_finals = current_group_index == len(contestant_groups) + 1
# Get the stories from each textbox
story1 = textbox1.get('1.0', tk.END)
story2 = textbox2.get('1.0', tk.END)
# Swap the stories in the textboxes
textbox1.delete('1.0', tk.END)
textbox1.insert('1.0', story2)
textbox2.delete('1.0', tk.END)
textbox2.insert('1.0', story1)
# Swap the corresponding data in the contestant groups or finalists
if not in_finals:
group = contestant_groups[current_group_index - 1] # Get the current group
index1 = textboxes.index(textbox1)
index2 = textboxes.index(textbox2)
group[index1], group[index2] = group[index2], group[index1]
# Print statements to verify correct pairing
print(f'Swapped {group[index1]["name"]} with {group[index2]["name"]}')
print_contestants_group(group)
else:
index1 = textboxes.index(textbox1)
index2 = textboxes.index(textbox2)
finalists[index1], finalists[index2] = finalists[index2], finalists[index1]
# Print statements to verify correct pairing in finals
print(f'Swapped {finalists[index1]["name"]} with {finalists[index2]["name"]}')
print_contestants_group(finalists)
# Function to print the current group's contestants and their stories
def print_contestants_group(group):
for contestant in group:
print(f'Contestant: {contestant["name"]} - Story: {contestant["story"][:30]}...')
# Function to create a story container frame with a specific textbox background color
def create_story_container(parent, column, bg_color, story_text=''):
# Create the story frame within the parent frame
story_frame = tk.Frame(parent)
story_frame.grid(row=0, column=column, sticky='nsew', padx=5, pady=5)
# Configure the grid layout inside the story frame
story_frame.rowconfigure(0, weight=9) # 90% of the vertical space for the textbox
story_frame.rowconfigure(1, weight=1) # 10% of the vertical space for the arrow buttons
story_frame.columnconfigure(0, weight=1)
# Create the custom font
custom_font = font.Font(family="Helvetica", size=16)
# Create the textbox inside the story frame with the specified background color
textbox = tk.Text(story_frame, wrap='word', bg=bg_color, font=custom_font, padx=10, pady=10)
textbox.grid(row=0, column=0, sticky='nsew', padx=10, pady=10)
textbox.insert('1.0', story_text)
# Create a scrollbar and attach it to the textbox
scrollbar = ttk.Scrollbar(story_frame, orient='vertical', command=textbox.yview)
scrollbar.grid(row=0, column=1, sticky='ns') # Place it to the right of the textbox
textbox['yscrollcommand'] = scrollbar.set
# Create a frame for the arrow buttons inside the story frame
arrows_frame = tk.Frame(story_frame, bg='gray')
arrows_frame.grid(row=1, column=0, sticky='ew')
# Create a grid configuration for the arrows frame with equal weight columns
arrows_frame.columnconfigure(0, weight=1)
arrows_frame.columnconfigure(1, weight=1)
# Create the left arrow button
left_arrow_button = ttk.Button(arrows_frame, text='<-- Left', command=lambda: swap_stories(textboxes[column-1], textbox) if column > 0 else None)
left_arrow_button.grid(row=0, column=0, sticky='ew', padx=10, pady=10)
# Create the right arrow button
right_arrow_button = ttk.Button(arrows_frame, text='Right -->', command=lambda: swap_stories(textbox, textboxes[column+1]) if column < 3 else None)
right_arrow_button.grid(row=0, column=1, sticky='ew', padx=10, pady=10)
return textbox
# Define the hex background colors for the textboxes - gold, silver, bronze, white
textbox_colors = [
'#F3E0FF', # Light Purple
'#FFECB3', # Gold
'#C0C0C0', # Silver
'#D2B48C', # Bronze
]
# Create 4 story containers in the main container with the specified background colors
for i in range(4):
textbox = create_story_container(main_container, i, textbox_colors[i])
textboxes.append(textbox)
# Global variable to keep track of the current group index
current_group_index = 0
# Function to update the textboxes with the next group's stories
def update_stories(group_index):
global current_group_index
if group_index < len(contestant_groups):
for i in range(len(contestant_groups[group_index])):
textbox = textboxes[i]
textbox.delete('1.0', tk.END) # Clear the current text
textbox.insert('1.0', contestant_groups[group_index][i]['story']) # Insert new text
current_group_index += 1
else:
messagebox.showinfo("End of Tournament", "All groups have been displayed.")
# Function to convert text to a list of chunks of numbers and non-numbers
def natural_keys(text):
return [int(c) if c.isdigit() else c.lower() for c in re.split('(\d+)', text)]
# Function to output the sorted results to a text file
def output_results_to_file(contestants_list):
# Sort the contestants using natural sorting
sorted_contestants = sorted(contestants_list, key=lambda c: natural_keys(c['name']))
# Open the file for writing
with open('tournament_results.txt', 'w', encoding='utf-8') as file:
# Write each contestant's name and points to the file
for contestant in sorted_contestants:
file.write(f"{contestant['points']} - {contestant['name']}\n")
# Global list to keep track of the finalists
finalists = []
# Function to handle the submit action
def submit_action():
global current_group_index
global finalists
# Check if we're still in the initial group phase
if current_group_index <= len(contestant_groups):
current_group = contestant_groups[current_group_index - 1]
# Award points and determine the winner of the current group
group_winner = None
max_points = -1
for i, contestant in enumerate(current_group):
points_to_add = 0
if i == 0: # Gold
points_to_add = 3
elif i == 1: # Silver
points_to_add = 2
elif i == 2: # Bronze
points_to_add = 1
# Update points for the contestant in the original list
contestant['points'] += points_to_add
# Check for the winner
if contestant['points'] > max_points:
max_points = contestant['points']
group_winner = contestant
# Add the winner to the finalists list
finalists.append(group_winner)
# Move on to the next group if there are more groups left
if current_group_index < len(contestant_groups):
update_stories(current_group_index)
else:
# If we're done with the initial groups, set up the finalists' group
update_stories_with_finalists()
# If we're in the finalists' phase
elif current_group_index == len(contestant_groups) + 1:
# Award points for the finalists based on their ranking
for i, finalist in enumerate(finalists):
points_to_add = 0
if i == 0: # Gold
points_to_add = 3
elif i == 1: # Silver
points_to_add = 2
elif i == 2: # Bronze
points_to_add = 1
# Update points for the finalist
finalist['points'] += points_to_add
# Determine the overall winner
overall_winner = max(finalists, key=lambda f: f['points'])
# Display the winner in a pop-up
messagebox.showinfo("Winner", f"Winner: {overall_winner['name']}")
# Output the sorted results to a text file
output_results_to_file(contestants)
# End the program
root.destroy()
# If we're in the finalists' phase
elif current_group_index == len(contestant_groups) + 1:
# Determine the overall winner
overall_winner = None
max_points = -1
for finalist in finalists:
if finalist['points'] > max_points:
max_points = finalist['points']
overall_winner = finalist
# Display the winner in a pop-up
# Output the sorted results to a text file
output_results_to_file(contestants)
messagebox.showinfo("Winner", f"Winner: {overall_winner['name']}")
root.destroy() # End the program
# Function to load the finalists' stories into the textboxes
def update_stories_with_finalists():
global current_group_index
# Clear all textboxes
for textbox in textboxes:
textbox.delete('1.0', tk.END)
# Load the finalists' stories
for i, finalist in enumerate(finalists):
textboxes[i].insert('1.0', finalist['story'])
# Increment the index to indicate we're now in the finalists' phase
current_group_index += 1
# Create a frame for the submit button at the bottom
submit_button_frame = tk.Frame(main_container)
submit_button_frame.grid(row=1, column=0, columnspan=4, sticky='ew', padx=5, pady=5)
submit_button_frame.columnconfigure(0, weight=1) # Configure the frame to expand the button to the full width
# Create the Submit button and place it into the submit_button_frame
submit_button = ttk.Button(submit_button_frame, text='Submit', command=submit_action)
submit_button.grid(row=0, column=0, sticky='ew', padx=10, pady=10)
# Function to read the contestant files and return a list of contestants
def load_contestants(directory):
contestants = []
try:
for filename in os.listdir(directory):
if filename.endswith('.txt'):
with open(os.path.join(directory, filename), 'r', encoding='utf-8') as file:
story = file.read()
contestants.append({'name': filename[:-4], 'story': story, 'points': 0})
except FileNotFoundError:
messagebox.showerror("Error", "The contestants directory was not found.")
root.destroy()
return contestants
# Function to shuffle and group contestants into groups of 4
def group_contestants(contestants_list):
random.shuffle(contestants_list) # Randomly shuffle the list of contestants
groups = [contestants_list[i:i + 4] for i in range(0, len(contestants_list), 4)] # Slice the list into groups of 4
return groups
# Load contestants and check for the correct number
contestants = load_contestants('contestants')
if len(contestants) != 16:
messagebox.showerror("Error", "There must be 16 contestants to proceed.")
root.destroy()
else:
contestant_groups = group_contestants(contestants) # Group the contestants
# Load the first group's stories into the textboxes
update_stories(current_group_index)
# Start the main application loop
root.mainloop()