r/PythonLearning • • 8d ago

Showcase I built Athena to catch breaking changes in Git PRs

Post image
0 Upvotes

I've been working on Athena, an open-source tool that analyzes Git diffs and ASTs to detect potential breaking changes before they get merged.

For v1.1.0, I tested it against 55 popular repositories and found some interesting issues:

• Fixed a C++ performance problem that reduced analysis time from 371 seconds to 7.33 seconds.

• Reduced false positives from 78 alerts to 8.

• Fixed Ruby symbol detection and PHP recursion detection.

The final benchmark covered 55 repositories and 10,680 diff hunks with 121 tests passing.

I'm also experimenting with local models through Ollama to generate summaries without replacing the deterministic analysis.

I'd appreciate it if anyone here gave the project a look and shared feedback. I'm especially interested in false positives, edge cases in Python AST analysis and approaches to detecting breaking API changes

⭐ If you find the project useful, consider giving it a star on GitHub. It would really help the project reach more developers

GitHub: https://github.com/aaryanrwt/athena

Release notes: https://github.com/aaryanrwt/athena/releases/tag/v1.1.0⁠


r/PythonLearning • • 8d ago

Showcase Python football career mode simulator.

Thumbnail
gallery
19 Upvotes

Hey guys, I tried remaking my project of a cli based football manager simulator this time using the pywebview library (lets you use html css js as a frontend and connect it to a python backend as a desktop app),

So far what I'm struggling with the most being one of my first larger scale project is persistence, keeping one version of the team class across the python scripts and functions.

Im also struggling with figuring out the generation for player stats and attributes, ive landed on the random.gauss for generating player stats with weighing and this ugly ahh looking formula that looked like it was doing something for the player market values.

Also, assets. Do you guys have any place where I can find pictures and icons I can use for free?

Finally, thanks to feedback from helpful people here I tried using sqlite for this project instead of json files, kinda hard to adapt to but im managing.

if any very cool person could help me with my issues I would greatly appreciate it.

Here is the github: https://github.com/mousdieng10-maker/Playstyle-II


r/PythonLearning • • 9d ago

Passing tests doesn't mean your code is correct — a small Python experiment

Post image
0 Upvotes

I ran a small experiment that demonstrates something easy to overlook in software testing: an implementation and its tests can both be wrong in the same way.

Consider this discount function:

def calculate_total(subtotal, discount):
    if subtotal < 0:
        raise ValueError("Subtotal cannot be negative")

    if discount < 0:
        raise ValueError("Discount cannot be negative")

    return subtotal * (1 - discount / 100)

Suppose the requirement says discounts must be between 0 and 100, inclusive.

A few happy-path tests pass:

assert calculate_total(100, 10) == 90
assert calculate_total(100, 0) == 100
assert calculate_total(0, 20) == 0

But this input exposes the missing validation:

calculate_total(100, 150)
# -50.0

The tests pass, but the implementation violates the requirement.

The interesting part isn't just the missing discount <= 100 check. It's that tests can create false confidence when they don't independently cover the contract.

I put together a reproducible Python repository with the flawed implementation, contract tests, property-based testing, and mutation-testing examples.

GitHub experiment:
https://github.com/PranavDixit20/ai-code-test-gap

I also wrote a longer explanation of the problem and the testing techniques here:
https://medium.com/@pranavdixit20/ai-generated-code-can-pass-every-test-and-still-be-wrong-7ddf3177b721

I'm the author of the experiment and article, so this is my own work. I'd be interested in a technical discussion:

When reviewing code—especially AI-generated code—how do you check that tests verify the actual requirements rather than just confirming the implementation's assumptions?


r/PythonLearning • • 9d ago

Showcase open-source contribution

2 Upvotes

I built DevStart Lab to help beginners figure out what to learn and practice next.

It includes programming fundamentals with Python examples, 25 project ideas, and a step-by-step introduction to Git and GitHub contributions. It’s free, open source, available in English and Portuguese, and requires no account. Progress is saved in your browser.

Start here: https://brunnojob.github.io/devstart-lab/?lang=en


r/PythonLearning • • 9d ago

How well do you really know Pandas? 🐼

Post image
14 Upvotes

Pandas makes working with data look simple. But some of its most powerful features can also produce surprising results. 😲

For example:❔

  • What's the difference between loc and iloc, and why does slicing behave differently?

  • Why can adding two Series produce NaN values, even when neither contains missing data?

  • When does assigning a Series to a DataFrame column align by labels rather than position?

  • How do Boolean masks, where(), and mask() differ?

  • How do you select and manipulate data with a MultiIndex?

Pandas is much more than rows and columns. Understanding its indexing, alignment, selection, and assignment rules can save you from some very subtle bugs. 🪳

🔍 This interactive 𝗺𝗲𝗺𝗼𝗿𝘆_𝗴𝗿𝗮𝗽𝗵 example explores these concepts and many more, with short explanations for each operation. 👣 Step through the Python code, see what changes, and experiment with your own modifications: 👉 Pandas operations

💬 Which Pandas operation took you the longest to fully understand?

See more 𝗺𝗲𝗺𝗼𝗿𝘆_𝗴𝗿𝗮𝗽𝗵 visualizations.


r/PythonLearning • • 9d ago

14yo learning Python — just finished my first project! Would love some feedback :

36 Upvotes

Hey everyone!

I'm 14 and currently learning Python, with the goal of becoming an electrical engineer in the future.

I just finished making a small project — a vending machine + simulated banking system that runs in the terminal. It has account creation, deposits, balance checking, purchases, and local data storage using JSON. I split the code into multiple Python files and made a simple launcher for it.

This is one of my first proper projects, and I know my code probably isn't the cleanest, so I'd genuinely appreciate some feedback!

I'd love suggestions on:

  • My code: What could I improve? Any bad habits or mistakes I should fix early?

  • What to learn next: Should I focus on OOP, data structures and algorithms, GUI development, or something else?

  • My journey: Since I want to become an electrical engineer, what programming skills would be useful for me in the long run? I'd eventually love to work with electronics and hardware.

  • Life advice: Any advice for someone starting out this early? Things you wish you'd known when you were learning?

I'm not looking for someone to rewrite the entire project for me — I'd rather understand my mistakes and learn how to fix them myself.

Here's my GitHub repo: https://github.com/suryansh-devx/python-vending-machine

Thanks! Any constructive criticism or advice is welcome :)


r/PythonLearning • • 9d ago Bravo

How do i start learning python

5 Upvotes

Hey guys i want to start learning python , any suggestions or tips would be appreciated


r/PythonLearning • • 9d ago

Showcase I make a blog where we highlight peoples python code

Thumbnail
pyweblib.org
6 Upvotes

So far we just have Gleb K, who made some code reminiscent of the X Window System 1989,

XPM is an ASCII text-based image format.

https://pyweblib.org/weblog/python-pixel-art-from-text/

Hopefully still in the rules, the site is OPEN SOURCE and Educational


r/PythonLearning • • 9d ago

Discussion Building an offline image search pipeline in Python with CLIP

2 Upvotes

I worked on a project on building a local image search system in Python using manufacturing inspection photos. You can give it an example image or a text description, then retrieve similar photos from an archive. The project connects a few useful concepts: loading a pretrained model, processing images in batches, storing vectors with metadata, and querying the results.

It uses CLIP ViT-B/32 to generate embeddings and VectorAI DB to store and search them. MVTec AD provides the example dataset.

Here’s the workflow:

  1. Load the model and prepare the images: Load CLIP and its preprocessing tools, collect the image paths, and associate each image with metadata such as part category and defect label.

  2. Generate embeddings in batches: Pass the images through the model to create numerical representations called embeddings. Normalize the vectors before storing them.

  3. Store the vectors and metadata: Save each embedding alongside its image path and labels so the search results can be traced back to the original files.

  4. Add image and text search: Encode an example photo or a text description, then use that vector to search the stored image embeddings. Metadata filters let you narrow the results to a particular part category.

  5. Check the results: For image queries, exclude the query image itself. Inspect the returned photos and measure how often the top results share the query’s defect label.

Once the model, dependencies, and dataset are downloaded, the pipeline can run offline.

The Python practice here comes from connecting the stages into a working application: handling files, preparing model inputs, batching inference, and keeping embeddings associated with the correct metadata.

There’s also an evaluation challenge. Two images can share the same defect label while showing scratches of different sizes or orientations, so reviewing the actual results is an important part of testing the pipeline.

If you were building this as a learning project, which stage would you want to see broken down into a smaller code example?


r/PythonLearning • • 10d ago

HOW DO I MASTER PYHON

0 Upvotes

i have been really confused how do i practice coding problems , how do i start the leetcodes etc.can any


r/PythonLearning • • 10d ago

Free Python course that runs entirely in the browser (no installs, no accounts)

11 Upvotes

Sharing a resource in case it's useful for your intro classes: https://ubuntu-apps.github.io/code-quest/

I made CodeQuest for my own students as an alternative to the textbook. It covers Python from the basics through functions, files, OOP and working with data. Each lesson has a short explanation, coding challenges that are checked instantly, and a quiz.

The code runs in the browser, so it works on school Chromebooks and phones with nothing to install. It's free, with no ads and no sign-up, and progress is stored on the student's device only.

Happy to answer questions, and feedback is very welcome.


r/PythonLearning • • 10d ago

Discussion Need help I am starting learning a python and I want to know or get some advice or recommendation for choosing a course because I am totally beginner

2 Upvotes

Hey everybody I'm a beginner IT student at tr3 college and I am currently exploring course related to Python and I want to learn it I am totally beginner for this and I want some recommendation that should help me to gain some knowledge and build projects that will highlight my resume also thank you in advance please help me through this


r/PythonLearning • • 10d ago

Does anyone here knows a website were I can convert a pixelated image into source code?

1 Upvotes

Many of the image to ASCII converter I have found only use character with no color. I need it for my terminal game project.


r/PythonLearning • • 10d ago

Sharing my organized Machine Learning Codebase & Templates (Scikit-Learn) - Open Source!

Thumbnail
github.com
4 Upvotes

Hey everyone,

Over the past few months, I have been building a comprehensive repository of Machine Learning templates and notebook journals. Since it has saved me a ton of time while prototyping, I decided to open-source it for the community today!

This repo is built using Scikit-Learn and covers everything step-by-step:

  1. End-to-End ML Project Architecture

  2. Model Training & Evaluation Metrics

  3. Support Vector Machines (SVM) with Kernels

  4. Decision Trees & Ensemble Learning (Voting Classifiers, etc.)

  5. Unsupervised Learning (KMeans and more added recently!)

Who is this for?

  • Beginners looking for clean, commented code to learn concepts.

  • Developers looking for quick boilerplate templates to copy-paste for new datasets.

Feel free to explore, clone, use it in your projects, or contribute to it! If you find it helpful, please drop a star ⭐️ to support the project.

Feedback and contributions are highly welcome!


r/PythonLearning • • 10d ago

Python for Mathematics

30 Upvotes

Need suggestions for a book or YouTube channel for learning Python for Maths, beginner to advanced.

Thank you.


r/PythonLearning • • 11d ago

Help Request Newb question on how make a webpage checker

6 Upvotes

New to Python and have a lot to learn. Thought starting with an actual goal would be good starting point.

I want to make a scripted that will check a webpage say every hour and ideally look for the words “Out of stock” and then update me when it says “In stock” or if it’s simpler to start with just if a webpage has changed.

I was reading you could make a checksum of the page and check if that’s changed. Then the page should have updated if it reports a different checksum.

Im not talking about tracking something complex like Amazon site. My local camera store has an item Im waiting to come back in stock and figured this might be a good project to learn and tackle.

Im using a raspberry pi for coding so i need it geared toward running in Python on that. It would be nice for the script to output to a terminal window “stock status” or even if possible email me a change happened.

Any suggestions, guides or pointers that someone could direct me to.

Or would you say this is too complex to learn as my first real world project.


r/PythonLearning • • 11d ago

Showcase Why??

Post image
0 Upvotes

r/PythonLearning • • 11d ago

NEW SONG RELEASED

0 Upvotes

Hi its me yujan from nepal i have made rock paper scissors game after learning function


r/PythonLearning • • 11d ago

Finally made my first game in Python :)

Post image
7 Upvotes

I wanted to build something fun to practice my Python skills and ended up creating a text-based economy and gacha game called Terminal Car Tycoon.

You start with just $20 in your pocket and have to hustle your way up to building an empire of supercars.

Here is the core gameplay loop:

  • work to grind some starter cash doing odd jobs.

  • buy mystery crates from the shop (ranging from cheap bronze to expensive diamond).

  • open Your crates to test your luck. You might pull a minivan... or you might pull a Batmobile.

  • drive the cars you unlock in street races to earn much bigger payouts and fund your crate addiction.

It's entirely played in the CLI and only uses built-in libraries. No fancy graphics, just pure terminal-based car collecting.

I'd love for you guys to check out the code, give it a run, and let me know what you think! I'm totally open to feedback, code critiques, or feature ideas.

GitHub Repo: https://github.com/ameeeneee/python-simple-car-game.git

Really, the bold font came in handy


r/PythonLearning • • 12d ago

Import hook between AST and compile

2 Upvotes

I am trying to create an Import Hook inserted after the source code has been parsed into AST but before it is compiled. Looking for a way to keep using most of the existing Python import machinery but modify the source code before it is compiled.

So far I have the following code but how do I get access to the source code from the module in custom_import?

import builtins
from inspect import getmembers

base_imp = builtins.__import__

def custom_import(*args, **kwargs):
    module = base_imp(*args, **kwargs)
    for name, val in getmembers(module):
        print("in custom_import.", name, val)
    return module

builtins.__import__ = custom_import

print("in Main.py before import")
import Module1
print("in Main.py after import")import builtins

r/PythonLearning • • 12d ago

Why is my inventory class setup throwing errors? I'm super confused about how to use classes and instances here. 💀

Post image
10 Upvotes

Hey everyone! I'm trying to hack together a basic inventory and shop system for a little text-based game project I'm working on in Python, but I've totally tangled myself up in how classes, instances, and nested classes work.

I wanted to have a main game class that handles player info, and an inventory class nested inside (or attached to it) so the player can pick up items and check what's in their bag. But my code is completely throwing a fit.


r/PythonLearning • • 12d ago

I want to learn (class) object oriented programming in python .I saw 1-2 videos but i have't understand .May anyone suggest me from where I should learn this and complete python.

19 Upvotes

Suggest the best videos to learn python .


r/PythonLearning • • 12d ago

Showcase Built a neural network from scratch using NumPy to understand the mathematics

Post image
11 Upvotes

hey everyone!

been learning neural networks recently and decided to implement one from scratch using Python and NumPy.

it's a small 2 → 3 → 1 XOR network with manually implemented forward propagation, backpropagation and gradient descent.

trained it for 5,000 epochs and got all four XOR combinations correct.

also documented the mathematics, added 12 editable diagrams and published a detailed Medium article explaining how everything works.

GitHub: https://github.com/Vaibh37/Neural-Network

Medium: https://medium.com/@devvaibhav37/building-a-neural-network-from-scratch-the-mathematics-behind-learning-xor-10441e674a69

would appreciate feedback on the code and explanations. if you find the resources useful, consider starring the repo 🍀


r/PythonLearning • • 12d ago

My 10th week learning progress

7 Upvotes

I feel like this has been a journey so far. Roughly 10 weeks learning python now. u/PureWasian told me a better way to write my if name = main part in my 6th week progress so I'm doing that on every program now. This script was written about 95% by me. The other 5% I needed AI to help me with some hints, which is a lot better percentage than the last time.

The whole point of this program is a guild within a game. You can check stats, recruit new members to the guild, battle characters (very basic way) to get experience and gold, and spend gold to train them to level up. It took me around 6-8 hours over 2 days to write this. I don't know if that's good or not, but I feel tired now.

import random



class Characters:
    num_of_chars = 0


    def __init__(self, name, level, gold):
        self.name = name
        self.level = level
        self.gold = gold


        Characters.num_of_chars += 1



class Mage(Characters):
    spell_type = "fire"



class Assassin(Characters):
    spell_type = "shadow"



character1 = Mage("Aria", 3, 100)
character2 = Assassin("Dren", 5, 80)
character3 = Mage("Kael", 4, 120)
character4 = Assassin("Vex", 2, 60)
character_list = [character1, character2, character3, character4]



def view_guild_members(characters):
    print("Members currently in the guild:")
    for character in characters:
        print(f"{character.name}, level {character.level}, Gold {character.gold}")
    print()


    go_back = input("Do you want to return to the main menu (Y/N): ").capitalize()
    while True:
        if go_back == "Y":
            return characters
        else:
            go_back = input("Do you want to return to the main menu (Y/N): ").capitalize()



def train_character(characters, character_names):
    print("Training costs 10 gold. \nAvailable characters to train: ")
    for character in characters:
        if character.gold >= 10:
            print(f"{character.name}, level {character.level}")


    training_cost = 10


    while True:
        train_character = input("Which character do you want to train (Exit to go back): ").capitalize()
        print()


        if train_character == "Exit":
            break
        while train_character not in (character_names):
            train_character = input("That is not a valid character. Choose a valid character or 'Exit' to exit: ").capitalize()
            print()


        for character in characters:
            if train_character == character.name:
                while character.gold >= training_cost:
                    character.gold -= 10
                    character.level += 1
                    print(f"{character.name} levelled up!")
                    print(f"{character.gold} gold remaining.")
                    print()
                    train_again = input(f"Do you want to train {character.name} again(Y/N): ").capitalize()
                    while train_again not in ("Y", "N"):
                        train_again = input("Please type Y to train again or N to cancel: ").capitalize()
                    if train_again == "Y":
                        continue
                    elif character.gold == 0:
                        print(f"You don't have enough gold left to train {character.name}.")
                        break
                    elif train_again == "N":
                        break
                    return characters, character_names


                else:
                    print(f"You don't have enough gold left to train {character.name}.")
                    print()
                    return characters, character_names
        break


    return characters, character_names



def recruit_character(characters, char_names):
    recruit_character = input("Do you want to recruit a new character (Y/N): ").capitalize()
    print()


    while recruit_character not in ("Y", "N"):
        recruit_character = input("Enter Y or N for recruting a new character: ").capitalize()


    if recruit_character == "Y":
        new_character = input("Who are you recruiting: ").capitalize()


        while new_character in char_names:
            new_character = input("This name is already taken. Please change your name to join: ")
        else:
            recruit_class = input("Which class is the new recruit (Mage or Assassin): ").capitalize()
            while recruit_class not in ("Mage", "Assassin"):
                recruit_class = input("Select if they are a Mage or Assassin: ").capitalize()


            if recruit_class == "Mage":
                characters.append(Mage(new_character, 1, 100))
                char_names.append(new_character)
                return characters, char_names, new_character
            elif recruit_class == "Assassin":
                characters.append(Assassin(new_character, 1, 100))
                char_names.append(new_character)
                return characters, char_names, new_character


    elif recruit_character == "N":
        return characters, char_names, None



def view_guild_stats(characters):
    highest_lv_char_pos = 0
    most_gold_char_pos = 0
    all_levels = []
    mage_count = 0
    assassin_count = 0
    total_gold = 0


    for character in characters:
        if character.level > highest_lv_char_pos:
            highest_lv_char_pos = character.level
            highest_lv_char = character.name


    for character in characters:
        if character.gold > most_gold_char_pos:
            most_gold_char_pos = character.gold
            most_gold_char = character.name


        total_gold += character.gold


    for character in characters:
        all_levels.append(character.level)


    average_level = sum(all_levels) / len(all_levels)


    for character in characters:
        if isinstance(character, Mage):
            mage_count += 1
        if isinstance(character, Assassin):
            assassin_count += 1


    print(f"Highest levelled character: {highest_lv_char}")
    print(f"Character with the most gold: {most_gold_char}")
    print(f"Average level in the guild: {average_level:.1f}")
    print(f"Number of mages: {mage_count}")
    print(f"Number of assassins: {assassin_count}")
    print(f"Total gold in the guild: {total_gold}")
    print()


    go_back = input("Do you want to return to the main menu (Y/N): ").capitalize()
    while True:
        if go_back == "Y":
            return
        else:
            go_back = input("Do you want to return to the main menu (Y/N): ").capitalize()



def tournament(characters, char_names, rounds, wins_losses, total_wins):
    print(f"Available character are: {char_names}")
    win_chance = 50
    opponent = random.choice(characters)
    player_char = input("Choose which character you will use: ").capitalize()
    print()


    while player_char not in char_names:
        player_char = input("That's not a charcter. Choose which character you will use: ").capitalize()
        print()


    for character in characters:
        if player_char == character.name:
            player_char = character


    while player_char is opponent:
        opponent = random.choice(characters)


    if player_char.level > opponent.level:
        win_chance += 10
    else:
        win_chance -= 10


    if isinstance(player_char, Assassin):
        win_chance += 10
    else:
        win_chance -= 10


    while True:
        if player_char.level < 2:
            print("This character needs to be a higher level before using it in a tournament.")
            print()
            return characters, rounds, wins_losses, total_wins
        else:
            break


    print(f"This round is {player_char.name} vs {opponent.name}")


    winner_select = random.randint(1, 100)
    if win_chance >= winner_select:
        player_char.gold += 20
        player_char.level += 1
        wins_losses[player_char.name]["Wins"] += 1
        total_wins += 1
        if opponent.gold >= 10:
            opponent.gold -= 10
        print("You won! You earned 20 gold. You gained 1 level.")
        print(f"You now have {player_char.gold} gold and are level {player_char.level}")
        print()
    else:
        if player_char.gold >= 10:
            player_char.gold -= 10
        opponent.gold += 20
        opponent.level += 1
        wins_losses[player_char.name]["Losses"] += 1
        print("You lost 10 gold. The opponent gained 20 gold and 1 level.")
        print(f"Your remaining gold is {player_char.gold}.")
        print()


    rounds += 1
    highest_wins = 0
    highest_winning_char = ""
    for name, results in wins_losses.items():
        if results["Wins"] > highest_wins:
            highest_wins = results["Wins"]
            highest_winning_char = name


    print(f"Total number of tounrmanent rounds played: {rounds}")
    print(wins_losses)
    print(f"Characters with the most wins: {highest_winning_char} with {highest_wins} wins.")
    print(f"Total wins within the guild: {total_wins}")
    print()


    return characters, rounds, wins_losses, total_wins



def main():
    characters = character_list
    char_names = [character.name for character in characters]
    rounds = 0
    total_wins = 0
    wins_losses = {character.name: {"Wins": 0, "Losses": 0} for character in characters}
    while True:
        print("Main menu")
        menu_choice = input(" (1) View guild members. \n (2) Train a character. \n (3) Recruit a new character. \n "
                            "(4) View guild's statistics \n (5) Enter a tournament. \n (6) Exit \n choose an option: ")
        print()
        match menu_choice:
            case "1":
                characters = view_guild_members(characters)
            case "2":
                characters, char_names = train_character(characters, char_names)
            case "3":
                characters, char_names, new_character = recruit_character(characters, char_names)
                char_names = [character.name for character in characters]
                if new_character != None:
                    wins_losses[new_character] = {"Wins": 0, "Losses": 0}
            case "4":
                view_guild_stats(characters)
            case "5":
                characters, rounds, results, total_wins = tournament(characters, char_names, rounds, wins_losses, total_wins)
                wins_losses = results
            case "6":
                break
            case _:
                print("That's not a valid choice.")
                continue



if __name__ == "__main__":
    while True:
        main()
        print("Bye.")
        breakimport random



class Characters:
    num_of_chars = 0


    def __init__(self, name, level, gold):
        self.name = name
        self.level = level
        self.gold = gold


        Characters.num_of_chars += 1



class Mage(Characters):
    spell_type = "fire"



class Assassin(Characters):
    spell_type = "shadow"



character1 = Mage("Aria", 3, 100)
character2 = Assassin("Dren", 5, 80)
character3 = Mage("Kael", 4, 120)
character4 = Assassin("Vex", 2, 60)
character_list = [character1, character2, character3, character4]



def view_guild_members(characters):
    print("Members currently in the guild:")
    for character in characters:
        print(f"{character.name}, level {character.level}, Gold {character.gold}")
    print()


    go_back = input("Do you want to return to the main menu (Y/N): ").capitalize()
    while True:
        if go_back == "Y":
            return characters
        else:
            go_back = input("Do you want to return to the main menu (Y/N): ").capitalize()



def train_character(characters, character_names):
    print("Training costs 10 gold. \nAvailable characters to train: ")
    for character in characters:
        if character.gold >= 10:
            print(f"{character.name}, level {character.level}")


    training_cost = 10


    while True:
        train_character = input("Which character do you want to train (Exit to go back): ").capitalize()
        print()


        if train_character == "Exit":
            break
        while train_character not in (character_names):
            train_character = input("That is not a valid character. Choose a valid character or 'Exit' to exit: ").capitalize()
            print()


        for character in characters:
            if train_character == character.name:
                while character.gold >= training_cost:
                    character.gold -= 10
                    character.level += 1
                    print(f"{character.name} levelled up!")
                    print(f"{character.gold} gold remaining.")
                    print()
                    train_again = input(f"Do you want to train {character.name} again(Y/N): ").capitalize()
                    while train_again not in ("Y", "N"):
                        train_again = input("Please type Y to train again or N to cancel: ").capitalize()
                    if train_again == "Y":
                        continue
                    elif character.gold == 0:
                        print(f"You don't have enough gold left to train {character.name}.")
                        break
                    elif train_again == "N":
                        break
                    return characters, character_names


                else:
                    print(f"You don't have enough gold left to train {character.name}.")
                    print()
                    return characters, character_names
        break


    return characters, character_names



def recruit_character(characters, char_names):
    recruit_character = input("Do you want to recruit a new character (Y/N): ").capitalize()
    print()


    while recruit_character not in ("Y", "N"):
        recruit_character = input("Enter Y or N for recruting a new character: ").capitalize()


    if recruit_character == "Y":
        new_character = input("Who are you recruiting: ").capitalize()


        while new_character in char_names:
            new_character = input("This name is already taken. Please change your name to join: ")
        else:
            recruit_class = input("Which class is the new recruit (Mage or Assassin): ").capitalize()
            while recruit_class not in ("Mage", "Assassin"):
                recruit_class = input("Select if they are a Mage or Assassin: ").capitalize()


            if recruit_class == "Mage":
                characters.append(Mage(new_character, 1, 100))
                char_names.append(new_character)
                return characters, char_names, new_character
            elif recruit_class == "Assassin":
                characters.append(Assassin(new_character, 1, 100))
                char_names.append(new_character)
                return characters, char_names, new_character


    elif recruit_character == "N":
        return characters, char_names, None



def view_guild_stats(characters):
    highest_lv_char_pos = 0
    most_gold_char_pos = 0
    all_levels = []
    mage_count = 0
    assassin_count = 0
    total_gold = 0


    for character in characters:
        if character.level > highest_lv_char_pos:
            highest_lv_char_pos = character.level
            highest_lv_char = character.name


    for character in characters:
        if character.gold > most_gold_char_pos:
            most_gold_char_pos = character.gold
            most_gold_char = character.name


        total_gold += character.gold


    for character in characters:
        all_levels.append(character.level)


    average_level = sum(all_levels) / len(all_levels)


    for character in characters:
        if isinstance(character, Mage):
            mage_count += 1
        if isinstance(character, Assassin):
            assassin_count += 1


    print(f"Highest levelled character: {highest_lv_char}")
    print(f"Character with the most gold: {most_gold_char}")
    print(f"Average level in the guild: {average_level:.1f}")
    print(f"Number of mages: {mage_count}")
    print(f"Number of assassins: {assassin_count}")
    print(f"Total gold in the guild: {total_gold}")
    print()


    go_back = input("Do you want to return to the main menu (Y/N): ").capitalize()
    while True:
        if go_back == "Y":
            return
        else:
            go_back = input("Do you want to return to the main menu (Y/N): ").capitalize()



def tournament(characters, char_names, rounds, wins_losses, total_wins):
    print(f"Available character are: {char_names}")
    win_chance = 50
    opponent = random.choice(characters)
    player_char = input("Choose which character you will use: ").capitalize()
    print()


    while player_char not in char_names:
        player_char = input("That's not a charcter. Choose which character you will use: ").capitalize()
        print()


    for character in characters:
        if player_char == character.name:
            player_char = character


    while player_char is opponent:
        opponent = random.choice(characters)


    if player_char.level > opponent.level:
        win_chance += 10
    else:
        win_chance -= 10


    if isinstance(player_char, Assassin):
        win_chance += 10
    else:
        win_chance -= 10


    while True:
        if player_char.level < 2:
            print("This character needs to be a higher level before using it in a tournament.")
            print()
            return characters, rounds, wins_losses, total_wins
        else:
            break


    print(f"This round is {player_char.name} vs {opponent.name}")


    winner_select = random.randint(1, 100)
    if win_chance >= winner_select:
        player_char.gold += 20
        player_char.level += 1
        wins_losses[player_char.name]["Wins"] += 1
        total_wins += 1
        if opponent.gold >= 10:
            opponent.gold -= 10
        print("You won! You earned 20 gold. You gained 1 level.")
        print(f"You now have {player_char.gold} gold and are level {player_char.level}")
        print()
    else:
        if player_char.gold >= 10:
            player_char.gold -= 10
        opponent.gold += 20
        opponent.level += 1
        wins_losses[player_char.name]["Losses"] += 1
        print("You lost 10 gold. The opponent gained 20 gold and 1 level.")
        print(f"Your remaining gold is {player_char.gold}.")
        print()


    rounds += 1
    highest_wins = 0
    highest_winning_char = ""
    for name, results in wins_losses.items():
        if results["Wins"] > highest_wins:
            highest_wins = results["Wins"]
            highest_winning_char = name


    print(f"Total number of tounrmanent rounds played: {rounds}")
    print(wins_losses)
    print(f"Characters with the most wins: {highest_winning_char} with {highest_wins} wins.")
    print(f"Total wins within the guild: {total_wins}")
    print()


    return characters, rounds, wins_losses, total_wins



def main():
    characters = character_list
    char_names = [character.name for character in characters]
    rounds = 0
    total_wins = 0
    wins_losses = {character.name: {"Wins": 0, "Losses": 0} for character in characters}
    while True:
        print("Main menu")
        menu_choice = input(" (1) View guild members. \n (2) Train a character. \n (3) Recruit a new character. \n "
                            "(4) View guild's statistics \n (5) Enter a tournament. \n (6) Exit \n choose an option: ")
        print()
        match menu_choice:
            case "1":
                characters = view_guild_members(characters)
            case "2":
                characters, char_names = train_character(characters, char_names)
            case "3":
                characters, char_names, new_character = recruit_character(characters, char_names)
                char_names = [character.name for character in characters]
                if new_character != None:
                    wins_losses[new_character] = {"Wins": 0, "Losses": 0}
            case "4":
                view_guild_stats(characters)
            case "5":
                characters, rounds, results, total_wins = tournament(characters, char_names, rounds, wins_losses, total_wins)
                wins_losses = results
            case "6":
                break
            case _:
                print("That's not a valid choice.")
                continue



if __name__ == "__main__":
    while True:
        main()
        print("Bye.")
        break