Risk game with python - python

i am pretty much starting to learn code so my knowledge is limited.
following scenario:
there is this "risk" game where playerA rolls a dice three times and playerB two times. now the two highest results of playerA are compared to the two of player B. if the highest result of A is greater than playerBs, player A gets a point, otherwise (<=) B gets a point. The same for the second highest result of A and B. So the total results of the points could be: 2:0, 1:1 or 0:2
Now the question:
The are obviously 6^5=7776 ways to dice and 2890 of them lead to 2:0, 2611 to 1:1 and 2275 to 0:2.
How can i show this statistic by printing out for example "There are 2890 possibilities to win 2:0" ?
I am able to show for a random dice roll who wins the game, but not for all.
I would be very thankful for some help.
import random
r1 = random.randint(1,6)
r2 = random.randint(1,6)
r3 = random.randint(1,6)
b1 = random.randint(1,6)
b2 = random.randint(1,6)
Points_A = 0
Points_B = 0
Dice_A = [r1,r2,r3]
Dice_B = [b1,b2]
print("results of A: ", Dice_A)
print("results of B: ", Dice_B)
A = sorted(Würfel_A)
B = sorted(Würfel_B)
if A[2] > B[1]:
Points_A += 1
elif A[2] == B[1]:
Points_B +=1
else: Points_B += 1
if A[1] > B[0]:
Points_A += 1
elif A[1] == B[0]:
Points_B += 1
else: Points_B += 1
print("A has ", Points_A, "Points.")
print("B has ", Points_B, "Pionts.")

Here is how I would do it:
Create a function that casts a given number of dice and sorts the results in descending order, and returns that list. For example cast_dice(3) could return [6, 4, 1]
Use that function to produce a result for the red player and the blue player. Then zip those two lists (the third die of the red player will not play a role) so the mutual dice can be compared. Calculate the number of dice with which red wins. Red can win with either 0, 1 or 2 dice.
To get statistics on distribution, you could create a list with three counters: one for each possible red-score. Run the above procedure thousands of times and to populate this list of three.
Calculate an average score from that list of three
Here is an implementation:
from random import randint
def cast_dice(dice_count):
return sorted((randint(1, 6) for _ in range(dice_count)), reverse=True)
def get_stats(num_rounds):
score_counts = [0, 0, 0] # red can score 0, 1 or 2 per round
for round in range(num_rounds):
reds = cast_dice(3)
blues = cast_dice(2)
score = sum(int(red > blue) for red, blue in zip(reds, blues))
score_counts[score] += 1
return score_counts
score_counts = get_stats(10000)
red_wins = score_counts[1] + 2 * score_counts[2]
blue_wins = score_counts[1] + 2 * score_counts[0]
avg_score = red_wins / sum(score_counts)
print("Raw score counts: ", score_counts)
print("Number of winning red dice: ", red_wins)
print("Number of winning blue dice: ", blue_wins)
print("Average score for red per round: ", avg_score) # ~1.08...
print("Average score for blue per round: ", 2 - avg_score) # ~0.92...
print("For every blue winning die, red has", red_wins / blue_wins, "winning dice")
So this sampling suggests that the expected outcome per round is that red wins one, and blue wins one, but that red has a tiny advantage: it will happen a bit more often that red wins two than that blue wins two.
This corresponds to the mathematical results you provided in the question.
To put it a bit differently, after 13 rounds (of 3 dice against 2), blue will have lost 2 "armies" more than red (on average).

Related

How can I calculate the probability that two players different abilities will win a PARS squash game against each other? (Python)

I've created a function winProbability(ra, rb, n) and I want to simulate n games in order to estimate the probability that a player with the ability ra will win a game against a player with ability rb
I'll show the code I've done so far. If this seems like a easy issue it's because I am new to coding.
import random #import random allows for the use of randomly generated numbers
def game(ra, rb): #this function game sets out the way the game runs
p_a_point = ra/(ra+rb) #this line of code determines the probability that
#player a wins any given point
a_points = 0 #the amount of points player a has is defaulted to 0
b_points = 0 #the amount of points player b has is defaulted to 0
score_to_win = 11 #the winning score is defaulted to 11
while (a_points < score_to_win and b_points < score_to_win) or abs (a_points - b_points) < 2: #while player a's points and player b's points are less than the winning score:
p_b_point = random.random()#the probability b wins a point is set the a random value between 0 and 1
if p_b_point < p_a_point: #is the probability b wins a point is less than the probability a wins a point:
a_points = a_points + 1 #a wins 1 point
else: #if player a doesn't win a point:
b_points = b_points + 1 #b wins a point
return(a_points, b_points)#both players points are returned
print(game(70,30))#the function is called with two integer values as parameters
def winProbability(ra, rb, n):
To be honest from here I am unsure on how to go about this. I was thinking of doing a for loop so for example:
for n in game (ra, rb):
but I am unsure if I can use a previous function in this loop call. I'm also confused on how to calculate probabilities in code
The general aim is to call the function with two probabilities for example 70 and 30 and give a decimal answer for the probability player ra will win.
To previous commenters, I apologise for being vague before. I've never posted on here before.
See if this helps.
from random import randint, seed
seed()
rounds = input(" How many rounds will be played in the match? ")
print("\n Please enter skill levels as integers from 0 to 99.\n")
a = input(" What is the skill level of player 1? ")
b = input(" What is the skill level of player 2? ")
# Catch empty inputs
if not rounds: rounds = 10
if not a: a = 0
if not b: b = 0
# Python inputs are always strings. Convert them to integers.
rounds = int(rounds)
a = int(a)
b = int(b)
# If both skill levels are 0, set them to 1.
# (This will avoid a possible division by zero error.)
if a+b == 0: a = b = 1
# Catch and correct numbers that are too high.
if a > 99: a = 99
if b > 99: b = 99
# Convert integer skill levels to values between 0.0 and 0.99
a = a/100
b = b/100
print()
print(" Chance player 1 will win: "+str(int(100*a/(a+b)))+" percent.")
print(" Chance Player 2 will Win: "+str(int(100*b/(a+b)))+" percent.")
print()
for x in range(rounds):
roll = randint(0,999)/1000
print("roll =",roll, end =": ")
if roll <= a/(a+b): # <-- Compare roll to ratio of player skill levels.
print("Round "+str(x+1)+" Winner: Player 1")
else:
print("Round "+str(x+1)+" Winner: Player 2")
print()
this was my answer
import random
def winProbability(ra, rb, n):
winCount = 0 #used to count how many times 'a' won
probabilityRange = ra + rb
for i in range(n):
# pick a number between 0 and probabiilityRange
number = random.randint(0, probabilityRange)
# if number is < ra then 'a' won if number is > ra then 'b' won if number == ra then results in a draw
if number < ra:
winCount += 1
print ('win')
if number > ra:
print('loss')
if number == ra:
print ('draw') # draw doesn't count as win
return winCount*(100/n)
print (winProbability(10000,1,100000))
This prints the results of each game played, and returns the possibility that 'a' will win in percentile form.

Probability not adding to 1

I was wondering if I can get some help looking at the second for loop. In this case, the die is not fair, and I have the die weighted heavily for even numbers. There are two issues with the code: the probabilities do not add up to 1, and the probability of the odd numbers is larger than the even numbers.
import random
NUM_ROLLS = 100
DIE_SIDES = [1,3,2,4,4,6]
odd_roll_result = 0
even_roll_result = 0
probability = 0
# Create the dictionary to store the results of each roll of the die.
rolls = {}
#Loop for rolling the die NUM_ROLLS times
for r in range(NUM_ROLLS):
roll_result = random.randint(0,len(DIE_SIDES)-1)
if roll_result in rolls:
# Add to the count for this number.
rolls[roll_result] += 1
else:
# Record the first roll result for this number.
rolls[roll_result] = 1
#print(DIE_SIDES[roll_result])
# Print how many times each number was rolled
for roll_result in range(len(DIE_SIDES)):
# print("The number", str(roll_result).format(roll_result, DIE_SIDES[roll_result]),
# "was rolled", str(rolls[roll_result]), "times.")
print("The number", roll_result, DIE_SIDES[roll_result],
"was rolled", str(rolls[roll_result]), "times.")
if roll_result == 1 or roll_result == 3 or roll_result == 5:
odd_roll_result = odd_roll_result + rolls[roll_result]
#print(odd_roll_result)
if roll_result == 2 or roll_result == 4 or roll_result == 6:
even_roll_result = even_roll_result + rolls[roll_result]
#print(even_roll_result)
probability_odd = odd_roll_result/NUM_ROLLS
th_exp = 1/6
prob_th = abs(th_exp-probability_odd)
probability_even = even_roll_result/NUM_ROLLS
print("The probability of getting an odd number is " , probability_odd )
print("Theoretical probability of getting an odd number is " , prob_th )
print("The probability of getting an even number is " , probability_even )
First, as other commenters have pointed out, you should fix the definition of DIE_SIDES:
DIE_SIDES = [1,2,3,4,5,6]
Then change the line that rolls the dice like this:
roll_result = random.randint(1,len(DIE_SIDES))
Or even better:
roll_result = random.choice(DIE_SIDES)
Your code considers 0 a roll_result, but does not count it in either odd_roll_result or even_roll_result. This is why the probabilities do not add up to 1.

Trying to find how often a dice roll result occurs in a list of randomly rolled n-sided dice

I am trying to find the occurrences of each number for sides going 1 up to the number of sides on a dice roll. I would like the program to find the number of occurrences for each number that is in listRolls.
Example: if there were a 6 sided dice then it would be 1 up to 6 and the list would roll the dice x amount of times and I would like to find how many times the dice rolled a 1 so on and so forth.
I am new to python and trying to learn it! Any help would be appreciated!
import random
listRolls = []
# Randomly choose the number of sides of dice between 6 and 12
# Print out 'Will be using: x sides' variable = numSides
def main() :
global numSides
global numRolls
numSides = sides()
numRolls = rolls()
rollDice()
counterInputs()
listPrint()
def rolls() :
# for rolls in range(1):
###################################
## CHANGE 20, 50 to 200, 500 ##
##
x = (random.randint(20, 50))
print('Ran for: %s rounds' %(x))
print ('\n')
return x
def sides():
# for sides in range(1):
y = (random.randint(6, 12))
print ('\n')
print('Will be using: %s sides' %(y))
return y
def counterInputs() :
counters = [0] * (numSides + 1) # counters[0] is not used.
value = listRolls
# if value >= 1 and value <= numSides :
# counters[value] = counters[value] + 1
for i in range(1, len(counters)) :
print("%2d: %4d" % (i, value[i]))
print ('\n')
# Face value of die based on each roll (numRolls = number of times die is
thrown).
# numSides = number of faces)
def rollDice():
i = 0
while (i < numRolls):
x = (random.randint(1, numSides))
listRolls.append(x)
# print (x)
i = i + 1
# print ('Done')
def listPrint():
for i, item in enumerate(listRolls):
if (i+1)%13 == 0:
print(item)
else:
print(item,end=', ')
print ('\n')
main()
Fastest way (I know of) is using Counter() from collections (see bottom for dict-only replacement):
import random
from collections import Counter
# create our 6-sided dice
sides = range(1,7)
num_throws = 1000
# generates num_throws random values and counts them
counter = Counter(random.choices(sides, k = num_throws))
print (counter) # Counter({1: 181, 3: 179, 4: 167, 5: 159, 6: 159, 2: 155})
collections.Counter([iterable-or-mapping])) is a specialized dictionary that counts the occurences in the iterable you give it.
random.choices(population, weights=None, *, cum_weights=None, k=1) uses the given iterable (a range(1,7) == 1,2,3,4,5,6 and draws k things from it, returning them as list.
range(from,to[,steps]) generates a immutable sequence and makes random.choices perform even better then when using a list.
As more complete program including inputting facecount and throw-numbers with validation:
def inputNumber(text,minValue):
"""Ask for numeric input using 'text' - returns integer of minValue or more. """
rv = None
while not rv:
rv = input(text)
try:
rv = int(rv)
if rv < minValue:
raise ValueError
except:
rv = None
print("Try gain, number must be {} or more\n".format(minValue))
return rv
from collections import Counter
import random
sides = range(1,inputNumber("How many sides on the dice? [4+] ",4)+1)
num_throws = inputNumber("How many throws? [1+] ",1)
counter = Counter(random.choices(sides, k = num_throws))
print("")
for k in sorted(counter):
print ("Number {} occured {} times".format(k,counter[k]))
Output:
How many sides on the dice? [4+] 1
Try gain, number must be 4 or more
How many sides on the dice? [4+] a
Try gain, number must be 4 or more
How many sides on the dice? [4+] 5
How many throws? [1+] -2
Try gain, number must be 1 or more
How many throws? [1+] 100
Number 1 occured 22 times
Number 2 occured 20 times
Number 3 occured 22 times
Number 4 occured 23 times
Number 5 occured 13 times
You are using python 2.x way of formatting string output, read about format(..) and its format examples.
Take a look at the very good answers for validating input from user: Asking the user for input until they give a valid response
Replacement for Counter if you aren't allowed to use it:
# create a dict
d = {}
# iterate over all values you threw
for num in [1,2,2,3,2,2,2,2,2,1,2,1,5,99]:
# set a defaultvalue of 0 if key not exists
d.setdefault(num,0)
# increment nums value by 1
d[num]+=1
print(d) # {1: 3, 2: 8, 3: 1, 5: 1, 99: 1}
You could trim this down a bit using a dictionary. For stuff like dice I think a good option is to use random.choice and just draw from a list that you populate with the sides of the dice. So to start, we can gather rolls and sides from the user using input(). Next we can use the sides to generate our list that we pull from, you could use randint method in place of this, but for using choice we can make a list in range(1, sides+1). Next we can initiate a dictionary using dict and make a dictionary that has all the sides as keys with a value of 0. Now looks like this d = {1:0, 2:0...n+1:0}.From here now we can use a for loop to populate our dictionary adding 1 to whatever side is rolled. Another for loop will let us print out our dictionary. Bonus. I threw in a max function that takes the items in our dictionary and sorts them by their values and returns the largest tuple of (key, value). We can then print a most rolled statement.
from random import choice
rolls = int(input('Enter the amount of rolls: '))
sides = int(input('Enter the amound of sides: '))
die = list(range(1, sides+1))
d = dict((i,0) for i in die)
for i in range(rolls):
d[choice(die)] += 1
print('\nIn {} rolls, you rolled: '.format(rolls))
for i in d:
print('\tRolled {}: {} times'.format(i, d[i]))
big = max(d.items(), key=lambda x: x[1])
print('{} was rolled the most, for a total of {} times'.format(big[0], big[1]))
Enter the amount of rolls: 5
Enter the amound of sides: 5
In 5 rolls, you rolled:
Rolled 1: 1 times
Rolled 2: 2 times
Rolled 3: 1 times
Rolled 4: 1 times
Rolled 5: 0 times
2 was rolled the most, for a total of 2 times

Program to Simulate 2 Coins Being Flipped at the Same Time

My assignment is to create a program that simulates 2 coins being tossed at the same time. If both heads, then Group A gets a point; if both tails then Group B gets a point. If the coins are different then the Prof gets a point. The program must take 2 inputs: number of games and number of tosses per game. Here are 2 separate sample runs to illustrate:
How many games? 1
How many coin tosses per game? 100
Game 0:
Group A: 25 (25.0%); Group B: 19 (19.0%); Prof: 56 (56.0%)
Wins: Group A=0 (0.0%); Group B=0 (0.0%); Prof=1 (100.0%)
How many games? 5
How many coin tosses per game? 10
Game 0:
Group A: 3 (30.0%); Group B: 1 (10.0%); Prof: 6 (60.0%)
Game 1:
Group A: 6 (60.0%); Group B: 1 (10.0%); Prof: 3 (30.0%)
Game 2:
Group A: 4 (40.0%); Group B: 1 (10.0%); Prof: 5 (50.0%)
Game 3:
Group A: 4 (40.0%); Group B: 1 (10.0%); Prof: 5 (50.0%)
Game 4:
Group A: 5 (50.0%); Group B: 3 (30.0%); Prof: 2 (20.0%)
Wins: Group A=2 (40.0%); Group B=0 (0.0%); Prof=3 (60.0%)
My code (albeit clunky) works for taking the inputs, simulating coin tosses, and calculating and displaying the number of points per group and the percent. My problem however, is in calculating and storing the number of wins across all of the games played. Here is my code as of now:
import random
def coinFlip():
games = input("How many games? ")
tosses = input("How many coin tosses per game? ")
for i in range(games):
gA = 0
gAW = 0
gB = 0
gBW = 0
prof = 0
profW = 0
for j in range(tosses):
flip1 = random.randint(0, 1)
flip2 = random.randint(0, 1)
if (flip1 == 0 and flip2 == 0):
gA += 1
elif (flip1 == 1 and flip2 == 1):
gB += 1
else:
prof += 1
gAper = ((gA * 1.0) / tosses) * 100
gBper = ((gB * 1.0) / tosses) * 100
profper = ((prof * 1.0) / tosses) * 100
if (gA > gB and gA > prof):
gAW += 1
elif (gB > gA and gB > prof):
gBW += 1
elif ( prof > gA and prof > gB):
profW += 1
gAWper = ((gAW * 1.0) / games) * 100
gBWper = ((gBW * 1.0) / games) * 100
profWper = ((profW * 1.0) / games) * 100
print "Game {}:".format(i)
print " Group A: {} ({}%); Group B: {} ({}%); Prof: {} ({}%)".format(gA, gAper, gB, gBper, prof, profper)
print "Wins: Group A = {} ({}%); Group B = {} ({}%); Prof: {} ({}%)".format(gAW, gAWper, gBW, gBWper, profW, profWper)
I'm thinking I should store the wins in a list, but that's where I'm lost.
The critical problem is that you have reset the long-term counts at the start of every game. Thus, nobody gets to record more than one win. This works great for my Monday-night Frisbee games, but is not effective for your assignment.
Return to your psuedo-code and see where the loops and initializations match up. Here's a code version:
def coinFlip():
# Set-up you do only once per program execution
games = input("How many games? ")
tosses = input("How many coin tosses per game? ")
games_won_A = 0
games_won_B = 0
games_won_prof = 0
for i in range(games):
# Set-up things you do once per game
tosses_won_A = 0
tosses_won_B = 0
tosses_won_prof = 0
for j in range(tosses):
# Things you do every toss
flip1 = random.randint(0, 1)
flip2 = random.randint(0, 1)
...
# Summary things you do every game
# ... such as compute percentages
# Summary things you do at the end of the program execution
# ... such as print the overall totals
Does that get you moving?
BTW< note that this becomes a lot shorter if you put the counters into a list. For instance, counting the winner of each flip becomes a single line:
win_count[flip1 + flip2] += 1
win_count can be a list of three elements, recording the wins for A, prof, and B, in that order.
This probably isn't what the OP was looking for, but in general generating random numbers with numpy can accomplish this quickly and simply.
import numpy as np
# get these from input or wherever
games = 5
tosses = 10
n_coins = 2
experiment = np.random.randint(2,size=(games, tosses, n_coins))
flip_results = experiment.sum(axis=2) # 0 means group A wins, 1 Prof, 2 group B
game_results = np.stack((flip_results == 0, flip_results == 1, flip_results == 2))
game_results = game_results.sum(axis=2)
total_results = game_results.sum(axis=1)
print(game_results, total_results)

Producing a sorted football league table in Python

I have created a program which simulates an entire football season between teams. The user inputs the teams' names and their skill ratings. It then uses the Poisson distribution to compare their skill ratings and calculate the result between the two teams. After each match, the relevant lists are updated: the winning teams gains 3 points (so if it is the third team that has won then the value at index [2] increases by 3). I have a separate list for points, goals scored, goals conceded, games won, games drawn, and games lost (side note - is there a more efficient way of doing this?)
The problem I have comes at the end of the season: each team is outputted with their data in the order that the teams were originally input. This is done using the fact that a team's name in the 'names' list is the same index as their points in the 'points' list. So the issue is, if I order the 'points' list then they will be out of sync with their names. I hope this makes sense but here is an example output for a season:
Enter number of teams in league: 4
Enter team 1 name: a
Enter team 2 name: b
Enter team 3 name: c
Enter team 4 name: d
Enter a skill: 1
Enter b skill: 3
Enter c skill: 5
Enter d skill: 8
===========================================
a's home games:
===========================================
a 2 - 0 b
a 0 - 2 c
a 0 - 0 d
===========================================
b's home games:
===========================================
b 2 - 3 a
b 1 - 0 c
b 0 - 0 d
===========================================
c's home games:
===========================================
c 1 - 0 a
c 1 - 0 b
c 0 - 1 d
===========================================
d's home games:
===========================================
d 4 - 0 a
d 2 - 0 b
d 0 - 0 c
Final table:
a Skill: 1 Points: 7 For: 5 Against: 9 Goal difference: -4 Wins: 2 Draws: 1 Losses: 3
b Skill: 3 Points: 4 For: 3 Against: 8 Goal difference: -5 Wins: 1 Draws: 1 Losses: 4
c Skill: 5 Points: 10 For: 4 Against: 2 Goal difference: 2 Wins: 3 Draws: 1 Losses: 2
d Skill: 8 Points: 12 For: 7 Against: 0 Goal difference: 7 Wins: 3 Draws: 3 Losses: 0
[4, 7, 10, 12]
So what I would now like to do is to be able to print a final league table in descending points order, rather than the way it prints now just in index order.
Sorry if this is poorly worded - the code for my program might be more useful so here it is:
import math
import random
#Lambda value in Poisson distribution for higher rated team
lambOne = 1.148698355
#Lambda value for lower rated team
lambTwo = 0.8705505633
#Poisson distribution calculating goals scored by the home team
def homeMatch(homeRating,awayRating):
global lambOne
global x
global y
if x == y:
raise ValueError
else:
lamb = lambOne**(int(homeRating)-int(awayRating))
homeScore = 0
z = random.random()
while z > 0:
z = z - ((lamb**homeScore * math.exp(lamb * -1))/(math.factorial(homeScore)))
homeScore += 1
return (homeScore-1)
#Poisson distribution calculating goals scored by away team
def awayMatch(homeRating,awayRating):
global lambTwo
global x
global y
#This check is to stop a team playing itself
if x == y:
raise ValueError
else:
lamb = lambTwo**(int(homeRating)-int(awayRating))
awayScore = 0
z = random.random()
while z > 0:
z = z - ((lamb**awayScore * math.exp(lamb * -1))/(math.factorial(awayScore)))
awayScore += 1
return (awayScore-1)
#Selecting number of teams in league
leagueSize = int(input("Enter number of teams in league: "))
#Initialising empty lists
teamNames = []
teamSkill = []
teamPoints = []
teamFor = []
teamAgainst = []
teamWins = []
teamDraws = []
teamLosses = []
#Populating lists with number of zeroes equal to the number of teams (one zero for each)
for x in range(leagueSize):
teamPoints += [0]
teamFor += [0]
teamAgainst += [0]
teamWins += [0]
teamDraws += [0]
teamLosses += [0]
#Entering names and skill ratings for each team
for i in range(leagueSize):
teamNames += [input("Enter team "+str(i+1)+" name: ")]
for j in range(leagueSize):
teamSkill += [input("Enter "+teamNames[j]+" skill: ")]
#Initialising variables
homeScore = 0
awayScore = 0
#The season begins - each team plays all of its home games in one go
for x in range(leagueSize):
#input("Press enter to continue ")
print("===========================================")
print(teamNames[x]+"'s home games: ")
print("===========================================\n")
for y in range(leagueSize):
error = 0
try:
homeScore = homeMatch(teamSkill[x],teamSkill[y])
#Skipping a game to stop a team playing itself
except ValueError:
pass
error += 1
try:
awayScore = awayMatch(teamSkill[x],teamSkill[y])
except ValueError:
pass
if error == 0:
#Updating lists
print(teamNames[x],homeScore,"-",awayScore,teamNames[y],"\n")
teamFor[x] += homeScore
teamFor[y] += awayScore
teamAgainst[x] += awayScore
teamAgainst[y] += homeScore
if homeScore > awayScore:
teamWins[x] += 1
teamLosses[y] += 1
teamPoints[x] += 3
elif homeScore == awayScore:
teamDraws[x] += 1
teamDraws[y] += 1
teamPoints[x] += 1
teamPoints[y] += 1
else:
teamWins[y] += 1
teamLosses[x] += 1
teamPoints[y] += 3
else:
pass
#Printing table (unsorted)
print("Final table: ")
for x in range(leagueSize):
#Lots of formatting
print(teamNames[x]+(15-len(teamNames[x]))*" "+" Skill: "+str(teamSkill[x])+(5-len(str(teamSkill[x])))*" "+" Points: "+str(teamPoints[x])+(5-len(str(teamPoints[x])))*" "+" For: "+str(teamFor[x])+(5-len(str(teamFor[x])))*" "+" Against: "+str(teamAgainst[x])+(5-len(str(teamPoints[x])))*" "+" Goal difference: "+str(teamFor[x]-teamAgainst[x])+(5-len(str(teamFor[x]-teamAgainst[x])))*" "+" Wins: "+str(teamWins[x])+(5-len(str(teamWins[x])))*" "+" Draws: "+str(teamDraws[x])+(5-len(str(teamDraws[x])))*" "+" Losses: "+str(teamLosses[x])+(5-len(str(teamLosses[x])))*" ")
teamPoints.sort()
print(teamPoints)
Sorry that this is very long and likely poorly worded and inefficient but I hope someone will be able to help me! Thank you very much :)
While your current approach is (barely) workable, it makes it very difficult to (for example) change the information you want to store about each team. You might consider defining a Team class instead, each instance of which stores all the information about a specific team.
class Team:
def __init__(self, name, skill):
self.name = name
self.skill = skill
self.points = self.goals_for = self.goals_against = \
self.wins = self.draws = self.losses = 0
This lets you create a new team object by passing a name and a skill level, in this way:
t1 = Team("Bradford City", 3)
t1 now has attributes name and skill with the given values, as well as a number of others (points, goals_for, and so on) whose values are all zero.
Then you can initialise the league quite easily:
league_size = 4
teams = []
for _ in range(league_size):
teams.append(Team(input("Name of team "+str(_)+": "),
int(input("Team "+str(_)+"'s skill level: ")))
Then to print the skill level of each team you can loop over the list:
for team in teams:
print(team.name, team.skill)
I hope this gives you some idea how your approach can be simplified. Your functions to play the matches can also take teams as arguments now, and modify the team objects directly according to the computed outcomes.
To get to the answer you want, once you have a list of teams you can print them out sorted by the number of points they hold quite easily:
for team in sorted(teams, key=lambda t: t.points):
print(team.name, team.skill, team.points, ...)
As far as I can see, none of your global declarations were necessary (if a name isn't defined locally Python will look for a global name to satisfy a reference). Besides which, inputs to a function should usually be passed as arguments, it's rather bad practice just to grab things from the environment!
I hope this is sufficient for you to rework your program to be more tractable. As a beginner I'd say you have done extremely well to get this far. The next steps are going to be exciting for you!
Added later: Your all-play-all could be easier to program as a result:
for home in teams:
for away in teams:
if home is away: # Teams don't play themselves
continue
play_match(home, away)
The play_match function would simulate the match and adjust each team's statistics. Of course you could simulate the away matches with another line reading
play_match(away, home)
though I'm not sure your algorithm is symmetrical for that.

Categories

Resources