Let's say I have a list of soccer players. For now, I only have four players. [Messi, Iniesta, Xavi, Neymar]. More players will be added later on. I want to keep track of the number of times these soccer players pass to each other during the course of a game. To keep track of the passes, I believe I'll need a data structure similar to this
Messi = {Iniesta: 4, Xavi: 5 , Neymar: 8}
Iniesta = {Messi: 4, Xavi: 10 , Neymar: 5}
Xavi = {Messi: 5, Iniesta: 10 , Neymar: 6}
Neymar = {Messi: 8, Iniesta: 5 , Xavi: 6}
Am I right to use a dictionary? If not, what data structure would be better suited? If yes, how do I approach this using a dictionary though? How do I address the issue of new players being included from time to time, and creating a dictionary for them as well.
As an example, If I get the first element in the list, List(i) in the first iteration is Messi, how do i use the value stored in it to create a dictionary with the name Messi. That is how do i get the line below.
Messi = [Iniesta: 4, Xavi: 5 , Neymar: 8]
It was suggested I try something like this
my_dynamic_vars = dict()
string = 'someString'
my_dynamic_vars.update({string: dict()})
Python and programming newbie here. Learning with experience as I go along. Thanks in advance for any help.
This is a fun question, and perhaps a good situation where something like a graph might be useful. You could implement a graph in python by simply using a dictionary whose keys are the names of the players and whose values are lists players that have been passed the ball.
passes = {
'Messi' : ['Iniesta', 'Xavi','Neymar', 'Xavi', 'Xavi'],
'Iniesta' : ['Messi','Xavi', 'Neymar','Messi', 'Xavi'],
'Xavi' : ['Messi','Neymar','Messi','Neymar'],
'Neymar' : ['Iniesta', 'Xavi','Iniesta', 'Xavi'],
}
To get the number of passes by any one player:
len(passes['Messi'])
To add a new pass to a particular player:
passes['Messi'].append('Xavi')
To count the number of times Messi passed to Xavi
passes['Messi'].count('Xavi')
To add a new player, just add him the first time he makes a pass
passes['Pele'] = ['Messi']
Now, he's also ready to have more passes 'appended' to him
passes['Pele'].append['Xavi']
What's great about this graph-like data structure is that not only do you have the number of passes preserved, but you also have information about each pass preserved (from Messi to Iniesta)
And here is a super bare-bones implementation of some functions which capture this behavior (I think a beginner should be able to grasp this stuff, let me know if anything below is a bit too confusing)
passes = {}
def new_pass(player1, player2):
# if p1 has no passes, create a new entry in the dict, else append to existing
if player1 not in passes:
passes[player1] = [player2]
else:
passes[player1].append(player2)
def total_passes(player1):
# if p1 has any passes, return the total number; otherewise return 0
total = len(passes[player1]) if player1 in passes else 0
return total
def total_passes_from_p1_to_p2(player1, player2):
# if p1 has any passes, count number of passes to player 2; otherwise return 0
total = passes[player1].count(player2) if player1 in passes else 0
return total
Ideally, you would be saving passes in some database that you could continuously update, but even without a database, you can add the following code and run it to get the idea:
# add some new passes!
new_pass('Messi', 'Xavi')
new_pass('Xavi', 'Iniesta')
new_pass('Iniesta', 'Messi')
new_pass('Messi', 'Iniesta')
new_pass('Iniesta', 'Messi')
# let's see where we currently stand
print total_passes('Messi')
print total_passes('Iniesta')
print total_passes_from_p1_to_p2('Messi', 'Xavi')
Hopefully you find this helpful; here's some more on python implementation of graphs from the python docs (this was a fun answer to write up, thanks!)
I suggest you construct a two dimensional square array. The array should have dimensions N x N. Each index represents a player. So the value at passes[i][j] is the number of times the player i passed to player j. The value passes[i][i] is always zero because a player can't pass to themselves
Here is an example.
players = ['Charles','Meow','Rebecca']
players = dict( zip(players,range(len(players)) ) )
rplayers = dict(zip(range(len(players)),players.keys()))
passes = []
for i in range(len(players)):
passes.append([ 0 for i in range(len(players))])
def pass_to(f,t):
passes[players[f]][players[t]] += 1
pass_to('Charles','Rebecca')
pass_to('Rebecca','Meow')
pass_to('Charles','Rebecca')
def showPasses():
for i in range(len(players)):
for j in range(len(players)):
print("%s passed to %s %d times" % ( rplayers[i],rplayers[j],passes[i][j],))
showPasses()
Related
Inspired by some projects, I have decided to work on a calculator project based on Python.
Essentially, I have 5 teams in a fantasy league, with points assigned to these teams based on their current standings. Teams A-E.
Assuming the league has 10 more matches to be played, my main aim is to calculate the probability that a team makes it to the top 3 in their league given the matches have a 33.3% of either going:
A win to the team (which adds 2 points to the winning team)
A lose to the team (which awards 0 points to the losing team)
A draw (which awards 1 point to both teams)
This also in turn means there will be 3^10 outcomes for the 10 matches to be played.
For each of these 3^10 scenarios, I will also compute how the final points table will look, and from there, I will be able to sort and figure out which are the top 3 teams in the fantasy league.
I've worked halfway through the project, as shown:
Points = { "A":12, "B":14, "C":8, "D":12, "E":6} #The current standings
RemainingMatches = [
A:B
B:D
C:E
A:E
D:C
B:D
C:D
A:E
C:E
D:C
]
n=len(RemainingMatches) # Number of matches left
combinations = pow(3,n) # Number of possible scenarios left assumes each game has 3 outcomes
print( "Number of remaining matches = %d" % n )
print( "Number of possible scenarios = %d" % combinations )
for i in range(0,combinations)
...
for i in range(0,n)
I am currently wondering how do I get these possible combinations to match a certain scenario? For example, when i = 0, it points to the first matchup where A wins, B losses. Hence, Points[A] = Points[A] + 2 etc. I know there will be a nested loop since I have to consider the other matches too. But how do I exactly map each scenario, and then nest it?
Apologies if I am being unclear here, struggling with this part at the moment.
Thinking Process:
3 outcomes per game.
for i to combinations:
#When i =1, means A win/B lost?
#When i =2, means B win/A lost?
#When i =3, means A/B drew?
for i to n:
#Go to next match?
Not exactly sure what is the logic flow for this kind of scenario. Thank you.
Here is a different way to write the code. If you knew in advance the outcome of each of the ten remaining games, you could compute which teams would finish in top three. This is done with the play_out function, which takes current standings, remaining games, and the known outcomes of future games.
Now all that remains is to loop over all possible future outcomes and tally the winning probabilities. This is done in the simulate_league function that takes in current standings and remaining games, and returns a probability that a given team finishes in top 3.
There may be situations where two teams are tied for the third place. In cases like this, the code below allows for four teams or more to be in "top 3". To use a different rule, you can change the top3scores = nlargest(3, set(pts.values())) line.
In terms of useful Python functions, itertools.product is used to generate all possible win/draw/loss outcomes, and heapq.nlargest is used to find the largest 3 scores out of a bunch. The collections.Counter class is used to count the number of possibilities in which a given team finishes in top 3.
from itertools import product
from heapq import nlargest
from collections import Counter
Points = {"A":12, "B":14, "C":8, "D":12, "E":6} # The current standings
RemainingMatches = ["A:B","B:D","C:E","A:E","D:C","B:D","C:D","A:E","C:E","D:C"]
# reformat remaining matches
RemainingMatches = [tuple(s.split(":")) for s in RemainingMatches]
def play_out(points, remaining_matches, winloss_schedule):
pts = points.copy()
# simulate remaining games given predetermine win/loss/draw outcomes
# given by winloss_schedule
for (team_a, team_b), outcome in zip(remaining_matches, winloss_schedule):
if outcome == -1:
pts[team_a] += 2
elif outcome == 0:
pts[team_a] += 1
pts[team_b] += 1
else:
pts[team_b] += 2
# top 3 scores (allows for ties)
top3scores = nlargest(3, set(pts.values()))
return {team: score in top3scores for team, score in pts.items()}
def simulate_league(points, remaining_matches):
top3counter = Counter()
for winloss_schedule in product([-1, 0, 1], repeat=len(remaining_matches)):
top3counter += play_out(points, remaining_matches, winloss_schedule)
total_possibilities = 3 ** len(remaining_matches)
return {team: top3count / total_possibilities
for team, top3count in top3counter.items()}
# simulate_league(Points, RemainingMatches)
# {'A': 0.9293637487510372,
# 'B': 0.9962573455943369,
# 'C': 0.5461057765584515,
# 'D': 0.975088485833799,
# 'E': 0.15439719554945894}
I was working on building a randomized character generator for Pathfinder 3.5 and got stuck.
I am using the Populate_Skills(Skill_String, Draw, Skill_List, Class_Skill): function to populate a randiomized list of skills with their class based points total, class bonus, and point buy. So modelling the action of a player picking skills for their character.
As an example below, Wizards.
I pick Knowledge_Arcana as a skill and spend one of my skill point pool (Calculated by taking my intelligence modifier +2) on it. So that skill now equals my intelligence modifier(+1 in this case), class skill bonus as a wizard (+3), plus the point I spent(+1) for a total of 5.
The problem is while the function prints the correct result of 5, the outstanding variables do not populate with the final total. To continue our example I'd run the function on Knowledge_Arcana, get a +5, and then check the Knowledge_Arcana after the function call and get just +1. Conversely, if I write out the function as just an if statement it works. Example is next to the function for comparison.
Does anyone know why Im getting the different result?
## Creating the lists and breaking into two separate sections
Int_Mod = 1
Skill_Ranks = 3
Rand_Class = 'Wizard'
Knowledge_Arcana = Int_Mod
Knowledge_Dungeoneering = Int_Mod
Wizard_Class_Top_Skills = ["Knowledge_Arcana"]
Wizard_Class_Less_Skills = ["Knowledge_Dungeoneering"]
Class_Skill = 3
Important_Skills_Weighted = .6
Less_Important_Skills_Weighted = .4
Important_Skills_Total_Weighted = round(Skill_Ranks*Important_Skills_Weighted)
Less_Skill_Total_Weighted = round(Skill_Ranks*Less_Important_Skills_Weighted)
Wiz_Draw =['Knowledge_Arcana', 'Knowledge_Dungeoneering']
def Populate_Skills(Skill_String, Draw, Skill_List, Class_Skill):
if Skill_String in Draw:
Skill_List = Skill_List + Class_Skill + Draw.count(Skill_String)
print(Skill_String, Skill_List)
else:
print('Nuts!')
## Function Calls
Populate_Skills('Knowledge_Arcana', Wiz_Draw, Knowledge_Arcana, Class_Skill)
Populate_Skills('Knowledge_Dungeoneering', Wiz_Draw, Knowledge_Dungeoneering, Class_Skill)
print(Knowledge_Arcana,Knowledge_Dungeoneering)
Edited to be a MRE, I believe. Sorry folks, Im new.
You are passing in a reference to a list and expect the function to modify it; but you are reassigning the variable inside the function which creates a local variable, which is then lost when the function is exited. You want to manipulate the same variable which the caller passed in, instead.
def Populate_Skills(Skill_String, Draw, Skill_List, Class_Skill):
if Skill_String in Draw:
Skill_List.extend(Class_Skill + Draw.count(Skill_String))
print(Skill_String, Skill_List)
else:
print('Nuts!')
Alternatively, have the function return the new value, and mandate for the caller to pick it up and assign it to the variable.
def Populate_Skills(Skill_String, Draw, Skill_List, Class_Skill):
if Skill_String in Draw:
Skill_List = Skill_List + Class_Skill + Draw.count(Skill_String)
print(Skill_String, Skill_List)
else:
print('Nuts!')
return Skill_List
Skill_List = Populate_Skills('Knowledge_Arcana', Wiz_Draw, Knowledge_Arcana, Class_Skill)
# etc
You should probably also rename your variables (capital letters should be used for classes and globals; regular Python functions and variables should use snake_case) and avoid using global variables at all. The entire program looks like you should probably look into refactoring it into objects, but that's far beyond the scope of what you are asking.
How to print different items depending on a random print in Python? Here is part of my script.
Mage = "Mage"
Warrior = "Warrior"
Thief = "Thief"
skilltree = (Mage, Warrior, Thief)
print random.choice (skilltree)
Now say it randomly chose Warrior. In my next script it would print 7 skills. But if it were to randomly choose Thief or Mage they would of been 7 completely different skills. So I want the 7 skills you get to depend on the randomly chosen skill tree.
You have done the hard part. Now you just need to map the skills to each category. For instance, using a dictionary:
skills = {'Mage': range(7), 'Warrior': range(7,14), 'Thief': range(14,21)}
choice = random.choice(skilltree)
print skills[choice]
This will print the list of skills you associated with the chosen skilltree. I used range just to illustrate, you could have a list of strings with the skills.
I will just illustrate a little bit further with Paulo's example in case you are not familiar with using a dictionary (and like he said using a dictionary is probably the best choice for a mapping).
MageSkills = ["Mskill1", "Mskill2"]
ThiefSkills = ["Tskill1", "Tskill2"]
WarriorSkills = ["Wskill1", "Wskill2"]
skills = {'Warrior': WarriorSkills, 'Mage': MageSkills, 'Thief': ThiefSkills}
choice = 'Warrior'
print(skills[choice])
The general concept of a solution has been outlined by others, but I think they're missing the key misunderstanding behind your question, which is how to persist something that you randomly chose and printed. As far as that goes, and for understanding this is what I would do:
import random
classes = ("Mage", "Warrior", "Thief")
skill_dictionary = {"Mage": ["Fireball", "Ice Blast"...], "Warrior": [...]} # etc
random_class = random.choice(classes) # Keep a version around for yourself
print random_class # print the version you just saved so you still have a copy
print skill_dictionary[random_class] #Then use the saved version to get the skill list
An important thought distinction to have here is separating getting the data from displaying it. First you randomly choose the data, and only after you already have it do you decide to show it to the user with your print statement.
The dictionary is just a key/value store (something that maps keys(your classes) to values (your skills)). It happens to fit this problem well, but you could implement this in other ways.
I'm creating objects derived from a rather large txt file. My code is working properly but takes a long time to run. This is because the elements I'm looking for in the first place are not ordered and not (necessarily) unique. For example I am looking for a digit-code that might be used twice in the file but could be in the first and the last row. My idea was to check how often a certain code is used...
counter=collections.Counter([l[3] for l in self.body])
...and then loop through the counter. Advance: if a code is only used once you don't have to iterate over the whole file. However You are stuck with a lot of iterations which makes the process really slow.
So my question really is: how can I improve my code? Another idea of course is to oder the data first. But that could take quite long as well.
The crucial part is this method:
def get_pc(self):
counter=collections.Counter([l[3] for l in self.body])
# This returns something like this {'187':'2', '199':'1',...}
pcode = []
#loop through entries of counter
for k,v in counter.iteritems():
i = 0
#find post code in body
for l in self.body:
if i == v:
break
# find fist appearence of key
if l[3] == k:
#first encounter...
if i == 0:
#...so create object
self.pc = CodeCana(k,l[2])
pcode.append(self.pc)
i += 1
# make attributes
self.pc.attr((l[0],l[1]),l[4])
if v <= 1:
break
return pcode
I hope the code explains the problem sufficiently. If not, let me know and I will expand the provided information.
You are looping over body way too many times. Collapse this into one loop, and track the CodeCana items in a dictionary instead:
def get_pc(self):
pcs = dict()
pcode = []
for l in self.body:
pc = pcs.get(l[3])
if pc is None:
pc = pcs[l[3]] = CodeCana(l[3], l[2])
pcode.append(pc)
pc.attr((l[0],l[1]),l[4])
return pcode
Counting all items first then trying to limit looping over body by that many times while still looping over all the different types of items defeats the purpose somewhat...
You may want to consider giving the various indices in l names. You can use tuple unpacking:
for foo, bar, baz, egg, ham in self.body:
pc = pcs.get(egg)
if pc is None:
pc = pcs[egg] = CodeCana(egg, baz)
pcode.append(pc)
pc.attr((foo, bar), ham)
but building body out of a namedtuple-based class would help in code documentation and debugging even more.
I'm starting out in python.. The details I have written in the below.. It goes to an infinite loop and give me an error when I try to call the function inside itself.. Is this kind of recursion not allowed ?
Posting code below.. Thanks for all your help :)
The program assumes that we have 100 passengers boarding a plane. Assuming if the first one has lost his boarding pass, he finds a random seat and sits there. Then the other incoming passengers sit in their places if unoccupied or some other random seat if occupied.
The final aim is to find the probability with which the last passenger will not sit in his/her own seat. I haven't added the loop part yet which
would make it a proper simulation. The question above is actually a puzzle in probability. I am trying to verify the answer as I don't really follow the reasoning.
import random
from numpy import zeros
rand = zeros((100,3))
# The rows are : Passenger number , The seat he is occupying and if his designated seat is occupied. I am assuming that the passengers have seats which are same as the order in which they enter. so the 1st passenger enter has a designated seat number 1, 2nd to enter has no. 2 etc.
def cio(r): # Says if the seat is occupied ( 1 if occupied, 0 if not)
if rand[r][2]==1:
return 1
if rand[r][2]==0:
return 0
def assign(ini,mov): # The first is passenger no. and the second is the final seat he gets. So I keep on chaning the mov variable if the seat that he randomly picked was occupied too.
if cio(rand[mov][2])== 0 :
rand[mov][2] = 1
rand[mov][1] = ini
elif cio(rand[mov][2])== 1 :
mov2 = random.randint(0,99)
# print(mov2) Was used to debug.. didn't really help
assign(ini,mov2) # I get the error pointing to this line :(
# Defining the first passenger's stats.
rand[0][0] = 1
rand[0][1] = random.randint(1,100)
m = rand[0][1]
rand[m][2]= 1
for x in range(99):
rand[x+1][0] = x + 2
for x in range(99):
assign(x+1,x+1)
if rand[99][0]==rand[99][1] :
print(1);
else :
print(0);
Please tell me if y'all get the same error.. ALso tell me if I am breaking any rules coz thisi sthe first question I'm posting.. Sorry if it seems too long.
This is how it should've been...
The code does work fine in this case with the following mods :
def assign(ini,mov):
if cio(mov)== 0 : """Changed here"""
rand[mov][2] = 1
rand[mov][1] = ini
elif cio(mov)== 1 : """And here"""
mov2 = random.randint(0,99)
assign(ini,mov2)
I am using Python 2.6.6 on Windows 7, using a software from Enthought Academic Version of Python.
http://www.enthought.com/products/getepd.php
Also the answer to this puzzle is 0.5 which is actually what I am getting(almost) by running it 10000 times.
I didn't see it here but it had to be available online..
http://www.brightbubble.net/2010/07/10/100-passengers-and-plane-seats/
Recursion, while allowed, isn't your best first choice for this.
Python enforces an upper bound on recursive functions. It appears that your loop exceeds the upper bound.
You really want some kind of while loop in assign.
def assign(ini,mov):
"""The first is passenger no. and the second is the final seat he gets. So I keep on chaning the mov variable if the seat that he randomly picked was occupied too.
"""
while cio(rand[mov][2])== 1:
mov = random.randint(0,99)
assert cio(rand[mov][2])== 0
rand[mov][2] = 1
rand[mov][1] = ini
This may be more what you're trying to do.
Note the change to your comments. Triple-quoted string just after the def.
you may be able to find the exact solution using dynamic programming
http://en.wikipedia.org/wiki/Dynamic_programming
For this you will need to add memoization to your recursive function:
What is memoization and how can I use it in Python?
If you just want to estimate the probability using simulation with random numbers then I suggest you break out of your recursive function after a certain depth when the probability is getting really small because this will only change some of the smaller decimal places (most likely.. you may want to plot the change in result as you change the depth).
to measure the depth you could add an integer to your parameters:
f(depth):
if depth>10:
return something
else: f(depth+1)
the maximum recursion depth allowed by default is 1000 although you can change this you will just run out of memory before you get your answer