9 Replies - 542 Views - Last Post: 07 August 2019 - 01:28 PM Rate Topic: -----

Poll: Premier League Simulation (0 member(s) have cast votes)

Needs improvement?

  1. YES (0 votes [0.00%])

    Percentage of vote: 0.00%

  2. NO (0 votes [0.00%])

    Percentage of vote: 0.00%

Vote Guests cannot vote

#1 woody101298   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 06-August 19

Premier League Simulation

Posted 06 August 2019 - 08:55 AM

So I've created a simulator for the Premier League, which takes in all of the 20 teams and plays them against each other, recording the results and outputting a table at the end.

The skill levels are based off a prediction in an article by The Telegraph (link at the end).

I am wondering whether or not my code can be improved, condensed or even added to with other features. Very new to coding so expecting lots of repetition/errors... Thank you for any help!

Here is my code:

 import math, random

    # HIGHER RATED TEAM
    higher = 1.148698355
    # LOWER RATED TEAM
    lower = 0.8705505633


    # DEFINING THE TEAM CLASS
    class Team:
        def __init__(self, name, skill):
            self.name = name
            self.skill = skill
            self.points = self.gf = self.ga = self.wins = self.draws = self.losses = 0

        def add_goals(self, goals):
            self.gf += goals


    # INITIALISING ALL OF THE TEAMS - NAMES AND SKILL LEVELS
    arsenal = Team("Arsenal", 16)
    aston_villa = Team("Aston Villa", 6)
    bournemouth = Team("AFC Bournemouth", 8)
    brighton = Team("Brighton and Hove Albion", 5)
    burnley = Team("Burnley", 4)
    chelsea = Team("Chelsea", 17)
    crystal_palace = Team("Crystal Palace", 11)
    everton = Team("Everton", 14)
    leicester = Team("Leicester City", 12)
    liverpool = Team("Liverpool", 19)
    man_city = Team("Manchester City", 20)
    man_united = Team("Manchester United", 15)
    newcastle = Team("Newcastle United", 3)
    norwich = Team("Norwich City", 2)
    sheffield_united = Team("Sheffield United", 1)
    southampton = Team("Southampton", 7)
    tottenham = Team("Tottenham Hotspur", 18)
    watford = Team("Watford", 9)
    west_ham = Team("West Ham United", 10)
    wolves = Team("Wolverhampton Wanderers", 13)

    # HOME/AWAY TEAMS FOR PLAYING EACH TIME AGAINST EACH OTHER
    teams = [arsenal, aston_villa, bournemouth, brighton, burnley, chelsea,
             crystal_palace, everton, leicester, liverpool, man_city, man_united,
             newcastle, norwich, sheffield_united, southampton, tottenham, watford,
             west_ham, wolves]

    # PRINT ALL TEAMS' NAME AND SKILL
    for team in teams:
        print(team.name, team.skill)

    # RANDOM SYSTEM FOR HOME GOALS
    def home_score(home, away):
        homeSkill = home.skill / 3
        awaySkill = away.skill / 3

        if homeSkill == awaySkill:
            raise ValueError

        if homeSkill > awaySkill:
            homeGoals = 0
            lambHome = higher ** (homeSkill - awaySkill)
            z = random.random()
            while z > 0:
                z = z - (((lambHome ** homeGoals) * math.exp(-1 * lambHome)) /
                         math.factorial(homeGoals))
                homeGoals += 1
            return (homeGoals - 1)

        if homeSkill < awaySkill:
            homeGoals = 0
            lambHome = higher ** (homeSkill - awaySkill)
            z = random.random()
            while z > 0:
                z = z - (((lambHome ** homeGoals) * math.exp(-1 * lambHome)) /
                         math.factorial(homeGoals))
                homeGoals += 1

            return (homeGoals - 1)

    # RANDOM SYSTEM FOR AWAY GOALS
    def away_score(home, away):
        homeSkill = home.skill / 3
        awaySkill = away.skill / 3

        if homeSkill == awaySkill:
            return "Teams cannot play themselves!!!"

        if awaySkill > homeSkill:
            awayGoals = 0
            lambAway = lower ** (homeSkill - awaySkill)
            x = random.random()
            while x > 0:
               x = x - (((lambAway ** awayGoals) * math.exp(-1 * lambAway)) /
                        math.factorial(awayGoals))
               awayGoals += 1
            return (awayGoals - 1)

        if awaySkill < homeSkill:
            awayGoals = 0
            lambAway = lower ** (homeSkill - awaySkill)
            x = random.random()
            while x > 0:
               x = x - (((lambAway ** awayGoals) * math.exp(-1 * lambAway)) /
                        math.factorial(awayGoals))
               awayGoals += 1
            return (awayGoals - 1)

    # LEAGUE SIZE AND SETTING UP THE LEAGUE
    league_size = 20
    POINTS = []
    GOALS_FOR = []
    GOALS_AGAINST = []
    WINS =[]
    DRAWS = []
    LOSSES = []
    for x in range(league_size):
        POINTS += [0]
        GOALS_FOR += [0]
        GOALS_AGAINST += [0]
        WINS += [0]
        DRAWS += [0]
        LOSSES += [0]

    # PLAYING ALL TEAMS AGAINST EACH OTHER AND UPDATING STATISTICS
    for x in range(league_size):
        print("========================================")
        print(teams[x].name + "'s home games: ")
        print("========================================")
        for y in range(league_size):
            error = 0
            try:
                homeScore = home_score(teams[x], teams[y])
            except ValueError:
                pass
                error += 1
            try:
                awayScore = away_score(teams[x], teams[y])
            except ValueError:
                pass
            if error == 0:
                print(teams[x].name, homeScore, ":", awayScore, teams[y].name)
                GOALS_FOR[x] += homeScore
                GOALS_FOR[y] += awayScore
                GOALS_AGAINST[x] += awayScore
                GOALS_AGAINST[y] += homeScore
                if homeScore > awayScore:
                    WINS[x] += 1
                    LOSSES[y] += 1
                    POINTS[x] += 3
                elif homeScore == awayScore:
                    DRAWS[x] += 1
                    DRAWS[y] += 1
                    POINTS[x] += 1
                    POINTS[y] += 1
                else:
                    WINS[y] += 1
                    LOSSES[x] += 1
                    POINTS[y] += 3
            else:
                pass

    # ASSIGNING STATISTICS TO EACH TEAM
    for x in range(league_size):
        teams[x].points = POINTS[x]
        teams[x].gf = GOALS_FOR[x]
        teams[x].ga = GOALS_AGAINST[x]
        teams[x].wins = WINS[x]
        teams[x].draws = DRAWS[x]
        teams[x].losses = LOSSES[x]

    sorted_teams = sorted(teams, key=lambda t: t.points, reverse=True)


    # PRITNING THE FINAL LEAGUE TABLE
    print("| TEAM                      | POINTS | WINS | DRAWS | LOSSES | GOALS FOR | GOALS AGAINST |")
    for team in sorted_teams:
        print("|",team.name," "*(24 - len(team.name)),"|  ",team.points," "*(3 - len(str(team.points))),"| ",team.wins," "*(2 - len(str(team.wins))),"|  ",
              team.draws," "*(2 - len(str(team.draws))),"|  ",team.losses," "*(3 - len(str(team.losses))),"|    ",team.gf," "*(4 - len(str(team.gf))),"|     ",
              team.ga," "*(7 - len(str(team.ga))),"|")




https://www.telegrap...-201920-season/

Is This A Good Question/Topic? 0
  • +

Replies To: Premier League Simulation

#2 modi123_1   User is offline

  • Suitor #2
  • member icon



Reputation: 15262
  • View blog
  • Posts: 61,178
  • Joined: 12-June 08

Re: Premier League Simulation

Posted 06 August 2019 - 09:01 AM

Also seen here:
https://www.freecode...mulation/303081
Was This Post Helpful? 1
  • +
  • -

#3 DK3250   User is offline

  • Pythonian
  • member icon

Reputation: 556
  • View blog
  • Posts: 1,739
  • Joined: 27-December 13

Re: Premier League Simulation

Posted 07 August 2019 - 12:25 AM

Hello woody101298, warm welcome to Dream.In.Code.

You have placed your post in the python forum; this forum is meant for coding issues and specific questions.
Your post is more like a presentation of your work, and there is another site for this: https://www.dreaminc...e-your-project/

Anyway, as you are new here, I'll comment on your post

Quote

I am wondering whether or not my code can be improved, condensed or even added to with other features
.You can almost always improve and condensed code is not necessarily better code.

In python there are an number of naming conventions.
Variable names in CAPITALS are used for constants only; your two constants 'higher' and 'lover' could be in capitals but the one in line 111-116 should not be.

Your iteration is typical for newcomers to python, fx you do in line 164-170:
for x in range(league_size):
       teams[x].points = POINTS[x]
       teams[x].gf = GOALS_FOR[x]
       teams[x].ga = GOALS_AGAINST[x]
       teams[x].wins = WINS[x]
       teams[x].draws = DRAWS[x]
       teams[x].losses = LOSSES[x]
You should use the python ideom: for val, item in enumerate(items):; the code would then look like:
for num, team in enumerate(teams):
       team.points = POINTS[num]
       team.gf = GOALS_FOR[num]
       team.ga = GOALS_AGAINST[num]
       team.wins = WINS[num]
       team.draws = DRAWS[num]
       team.losses = LOSSES[num]


Line 111-123 can be simplified to POINTS = [0] * league_size etc.; omitting the loop (and as mentioned above 'POINTS' should be re-named)

More fundamentally, you do not use the Team class as you should. All the attributes (points, goals, wins, ..) should be inside the class. You attempt to do this in line 14, but but don't implement it further down the code. If done correctly your loops will change fx line 126-146 becomes:
   for team1 in teams:
       print("========================================")
       print(team.name + "'s home games: ")
       print("========================================")
       for  team2 in teams:
           error = 0
           try:
               homeScore = home_score(team1, team2)
           except ValueError:
               pass
               error += 1
           try:
               awayScore = away_score(team1, team2)
           except ValueError:
               pass
           if error == 0:
               print(team.name, homeScore, ":", awayScore, team.name)
               team1.gf += homeScore
               team2.gf += awayScore
               team1.ga += awayScore
               team2.ga += homeScore
               ....
I didn't rectify all the code, - this I'll leave to you...

This post has been edited by DK3250: 07 August 2019 - 12:39 AM
Reason for edit:: line ref included

Was This Post Helpful? 1
  • +
  • -

#4 DK3250   User is offline

  • Pythonian
  • member icon

Reputation: 556
  • View blog
  • Posts: 1,739
  • Joined: 27-December 13

Re: Premier League Simulation

Posted 07 August 2019 - 02:39 AM

Oh, one more thing: You use try/except to catch if a team is playing against itself in the two functions.
Try/except is meant for handling more fundamental errors, like file missing, type mismatch, or similar.

In your case you can return the Boolean 'None' to indicate the same-team situation; then just check the return value in main and only handle relevant situations.
Was This Post Helpful? 1
  • +
  • -

#5 woody101298   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 06-August 19

Re: Premier League Simulation

Posted 07 August 2019 - 03:19 AM

Thank you for your advice! I will update my code and post this in the right place later!
Was This Post Helpful? 0
  • +
  • -

#6 woody101298   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 06-August 19

Re: Premier League Simulation

Posted 07 August 2019 - 06:56 AM

I've created a simulator for the Premier League, which takes in all of the 20 teams and plays them against each other, recording the results and outputting a table at the end. I have incorporated advice from people on Forums and updated my code accordingly. https://codereview.s...ague-simulation
I originally posted this elsewhere on Dream.In.Code but was informed this is where it belongs so am posting it here instead.

My question is how can I sort the final league table by points first and then by goal difference after to establish where teams come if they get the same amount of points.
As a result of some advice on a forum, I am also looking into making a better system for setting the skill level if anyone has any ideas on that.

import math
import random

H_PARAMETER = 1.148698355
A_PARAMETER = 0.8705505633


class Team:
    def __init__(self, name, skill):
        self.name = name
        self.skill = skill
        self.points = self.gf = self.ga = self.wins = self.draws = self.losses = self.gdiff = self.mp = 0


def generate_random_goals(delta_skill, parameter):
    if delta_skill == 0:
        raise ValueError
    goals = 0
    lamb = parameter ** (delta_skill)
    z = random.random()
    while z > 0:
        z = z - (((lamb ** goals) * math.exp(-1 * lamb)) /
                 math.factorial(goals))
        goals += 1
    return goals - 1


def generate_random_score(home, away):
    delta_skill = (home.skill - away.skill) / 3
    return (generate_random_goals(delta_skill,
                                  H_PARAMETER), generate_random_goals(delta_skill, A_PARAMETER))


def simulate_league(teams):
    for home_team in teams:
        print("=" * 50)
        print(home_team.name + "'s home games: ")
        print("=" * 50)
        for away_team in teams:
            if home_team == away_team:
                pass
            if home_team != away_team:
                home_score, away_score = generate_random_score(home_team, away_team)
                print(home_team.name, home_score, ":", away_score, away_team.name)
                home_team.gf += home_score
                away_team.gf += away_score
                home_team.ga += away_score
                away_team.ga += home_score
                home_team.gdiff += (home_score - away_score)
                away_team.gdiff += (away_score - home_score)
                home_team.mp += 1
                away_team.mp += 1
                if home_score == away_score:
                    home_team.draws += 1
                    away_team.draws += 1
                    home_team.points += 1
                    away_team.points += 1
                if home_score > away_score:
                    home_team.wins += 1
                    away_team.losses += 1
                    home_team.points += 3
                if away_score > home_score:
                    away_team.wins += 1
                    home_team.losses += 1
                    away_team.points += 3


if __name__ == "__main__":
    teams = [
        Team("Arsenal", 16), Team("Aston Villa", 6), Team("AFC Bournemouth", 8), Team("Brighton and Hove Albion", 5),
        Team("Burnley", 4), Team("Chelsea", 17), Team("Crystal Palace", 11), Team("Everton", 14),
        Team("Leicester City", 12), Team("Liverpool", 19), Team("Manchester City", 20), Team("Manchester United", 15),
        Team("Newcastle United", 3), Team("Norwich City", 2), Team("Sheffield United", 1), Team("Southampton", 7),
        Team("Tottenham Hotspur", 18), Team("Watford", 9), Team("West Ham United", 10),
        Team("Wolverhampton Wanderers", 13)
    ]

    for team in teams:
        print(team.name, team.skill)

    simulate_league(teams)

    sorted_teams = sorted(teams, key=lambda t: t.points, reverse=True)

    print("=" * 108)
    print(
        "| {:<25} | {:^4} | {:^3} | {:^3} | {:^3} | {:^4} | {:^4} | {:^4} | {:^6} |".format("CLUB", "MP", "W", "D",
                                                                                            "L", "GF",
                                                                                            "GA",
                                                                                            "GD", "PTS"))
    for team in sorted_teams:
        print("| {:<25} | {:^4} | {:^3} | {:^3} | {:^3} | {:^4} | {:^4} | {:^4} | {:^6} |".format(team.name, team.mp,
                                                                                                  team.wins,
                                                                                                  team.draws,
                                                                                                  team.losses,
                                                                                                  team.gf,
                                                                                                  team.ga, team.gdiff,
                                                                                                  team.points))



Was This Post Helpful? 0
  • +
  • -

#7 modi123_1   User is offline

  • Suitor #2
  • member icon



Reputation: 15262
  • View blog
  • Posts: 61,178
  • Joined: 12-June 08

Re: Premier League Simulation

Posted 07 August 2019 - 07:00 AM

To clear up a little confusion. If you have a general post like 'hey- look what I made!' that's a good candidate for 'share your project' or the blog.

If you have specific questions programming questions that's best in the language subforum.

In this case - asking for help on sorting a python collection is best in the python area. I'll move it there. :^:
Was This Post Helpful? 0
  • +
  • -

#8 woody101298   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 06-August 19

Re: Premier League Simulation

Posted 07 August 2019 - 07:01 AM

View Postmodi123_1, on 07 August 2019 - 07:00 AM, said:

To clear up a little confusion. If you have a general post like 'hey- look what I made!' that's a good candidate for 'share your project' or the blog.

If you have specific questions programming questions that's best in the language subforum.

In this case - asking for help on sorting a python collection is best in the python area. I'll move it there. :^:/>


Thank you - eventually it'll end up in the right place!
Was This Post Helpful? 0
  • +
  • -

#9 modi123_1   User is offline

  • Suitor #2
  • member icon



Reputation: 15262
  • View blog
  • Posts: 61,178
  • Joined: 12-June 08

Re: Premier League Simulation

Posted 07 August 2019 - 07:02 AM

Not a problem. It can be a little tricky sometimes, but eventually everyone picks up on the funky flow.
Was This Post Helpful? 1
  • +
  • -

#10 DK3250   User is offline

  • Pythonian
  • member icon

Reputation: 556
  • View blog
  • Posts: 1,739
  • Joined: 27-December 13

Re: Premier League Simulation

Posted 07 August 2019 - 01:28 PM

To sort by two fields, you can make line 83 like this:
sorted_teams = sorted(teams, key=lambda t: (-t.points, -t.gdiff))

The minus indicates reversed order i.e. descending values.

Line 40-41 doesn't do anything, - can be deleted.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1