How to iterate for loop with values in different methods? - python

I made this program. What I want to do now, is to make a new method in the class Star_cluster that will count and return all planets in the star cluster that are in danger. In this case, a planet in danger is a planet with a star that has a short lifespan. A star has a short lifespan when it's total mass is more than 9.5 solar masses.
class Planet:
def __init__ (self, a_str1, a_str2, a_float):
self.name = a_str1
self.type = a_str2
self.orbital_period = a_float
class Star:
def __init__ (self, a_float, a_planet_list):
self.total_mass = a_float # in solar masses
self.orbiting_planets = a_planet_list # list of Planet-objects
class Star_cluster:
def __init__ (self):
self.star_list = [] # list of Star-objects
def add(self, Star):
self.star_list.append(Star)
My problem is that I don't get how I should combine the values in the different methods to make one for loop.
For example, I tried to make something like this:
class Star_cluster:
def planets_in_danger (self):
for i in self.orbiting_planets:
if i.total_mass > 9.5:
k = self.orbiting_planets.count(i)
return k
But I can't get this working. I want to understand how I should approach this problem, because I know what to do, but not entirely sure about how to do it the best way.
Especially whether to use self and the fact that there are multiple methods involved and just one for loop, confuses me. Could someone point me in the right direction?

Loop over all the stars in the given cluster. If a star's total mass exceeds 9.5, count the amount of planets that belong to that star to the amount of endangered planets.
def planets_in_danger(self):
in_danger = 0
for star in self.star_list:
if star.total_mass > 9.5:
in_danger += len(star.orbiting_planets)
return in_danger
Or shorter:
def planets_in_danger(self):
return sum(len(star.orbiting_planets) for star in self.star_list if star.total_mass > 9.5)
edit: returning the count of endangered planets and the planets:
def planets_in_danger(self):
in_danger = []
for star in self.star_list:
if star.total_mass > 9.5:
in_danger.extend(star.orbiting_planets)
return (len(in_danger), in_danger)

Call the function planets_in_danger in Star_Cluster
class Planet:
def __init__ (self, a_str1, a_str2, a_float):
self.name = a_str1
self.type = a_str2
self.orbital_period = a_float
class Star:
def __init__ (self, a_float, a_planet_list):
self.total_mass = a_float # in solar masses
self.orbiting_planets = a_planet_list # list of Planet-objects
class Star_cluster:
def __init__ (self):
self.star_list = [] # list of Star-objects
def add(self, Star):
self.star_list.append(Star)
def planets_in_danger(self, stars_list):
result = []
solar_mass = 1.989 * (10**30)
for i in stars_list:
if i.total_mass > 9.5 * solar_mass:
result.append(i)
return result

Related

How can I automate the creation of instances of a class?

So in python 3 I am having trouble creating multiple instances of a class automatically. I am trying to make monopoly and here is the code sample that is giving me problems.
def numplayer():
numplayer = int(input('How many players would you like? (up to four)'))
while numplayer > 4 or numplayer < 1:
numplayer = int(input('How many players would you like? (up to
four)'))
for i in range(numplayer):
PlayerMoney.append(1500)
What I want to do is also add something that will create the number of players that numplayers equals to in the for i in range(numplayer) function. I have the player as a class but I don't want to manually create every single class for every player. If there is a solution to this, please do tell. Thanks!
EDIT: So I think this might be bad wording in the title but I'm trying to create multiple instances of a single class (the player).
Here is the code for the player class:
class Player:
def __init__(self, name, money, position):
self.name = name
self.money = money
self.position = position
def DiceRoll(self):
x = random.randint(1, 6)
y = random.randint(1, 6)
sum = x + y
return [sum, x, y]
def getName(self):
return sef.name
def getMoney(self):
return self.money
def getPosition(self):
return self.position
# Create Class
class Player:
def greating(self):
print 'Hello!'
# List to store instanses
l = []
for i in range(4):
l.append(Player())
# Call Instance #1 methods
l[0].greating()
Here we have a player class and 4 instances from this class stored in l list.
I would advise you structure your code as below. It's usually a good idea for your function to return something.
def setup():
n = int(input('How many players would you like? (up to 4)'))
names = [input('Give name #{0}'.format(i)) for i in range(1, n+1)]
return [Player(name, 1500, 0) for name in names]
players = setup()

Why is this returning a pop index out of range error?

So I'm trying to simulate the NBA lottery and when I create an array of teams and attempt to assign each team its combinations within a for loop, I get a pop index out of bounds error in this line:
combos.append(self.combinations.pop(randint(0,len(self.combinations))))
However, if I simply assign one team item its combinations, no error occurs. The error occurs when I try to assign its combinations iteratively.
from Team import *
from LotteryMachine import *
"""Main class"""
lotteryMachine = LotteryMachine()
"""Initialize Teams"""
teams = [Team('Lakers', '81-0',1),Team('Wizards', '81-0',2)]
for team in teams:
team.combinations=
lotteryMachine.assignCombinations(team.numCombinations)
Team class:
class Team():
combination_dict={1:250, 2:199, 3:156, 4:119, 5:88, 6:63, 7:43, 8:28, 9:17, 10:11, 11:8, 12:7, 13: 6, 14:5}
def __init__(self, name, record, standing):
self.name=name
self.record = record
self.standing = standing
self.numCombinations= Team.combination_dict[self.standing]
def __str__(self):
return self.name
Lottery Machine Class:
from random import *
class LotteryMachine():
def __init__(self):
self.combinations = list(self.createCombinations([x for x in range(1,15)],4))
self.deleteRandom()
self.copyCombinations = self.combinations
def combination(self,n,k):
return int(self.factorial(n)/(self.factorial(k)*self.factorial(n-k)))
def factorial(self,n):
assert n>=0
if n==0 or n==1:
return 1
return n*self.factorial(n-1)
def createCombinations(self,elements,length):
for i in range(len(elements)):
if length==1:
yield [elements[i],]
else:
for next in self.createCombinations(elements[i+1:len(elements)],length-1):
yield [elements[i],]+next
def deleteRandom(self):
self.combinations.pop(randint(0,len(self.combinations)))
def assignCombinations(self,length):
combos=[]
for x in range(length):
combos.append(self.combinations.pop(randint(0,len(self.combinations))))
return combos
#error occurs in above line
def drawCombinations(self):
combos=[]
for x in range(3):
combos.append(self.copyCombinations.pop(randint(0, len(self.copyCombinations))))
return combos
def __str__(self):
return "NBA Lottery Machine"
The randint function returns a random integer from a range up to and including the upper bound. If you want it to generate random indexes into a list, you probably want randrange instead, which selects from a half-open interval (including the lower bound, but excluding the upper bound).

Competition registration program using classes

I have an assignment to create a code that would define 2 classes, a player and a team each of these having some parameters. Player is supposed to have a name, a number of skis, a number of sledges and a player index(number of games played by the player before).
I managed to define these attributes of the class but I'm having a hard time implementing the team class. Team is supposed to hold the name of the team and the number of players-the players cannot be just their names it must link to the class instance(player). I don't understand how to use the information provided in the player instance to implement team. Here's my code so far:
class Player:
def __init__(self, name, skis, index):
self.name = name
self.sledges = []
self.skis = []
self.index = index
pass
class Team:
def __init__(self, name, players):
self.name = name
self.players = [Player]
pass
def get_players_count()
def get_transport_capacity()
def get_average_index()
*Update
Thank you for your help, I have one more function to add, a function that would return the number of passengers a team could accommodate. I've tried something like this but I don't think the syntax is correct. The user inputs the number of places in each sledge so I need to iterate over the values in the list to get the number of places.
def get_transport_capacity(self):
skis = len(Player.skis)
for i in Player.sledges:
sledges += Player.sledges[i]
capacity = skis + sledges
return capacity
class Player:
def __init__(self, name, index):
self.name = name
self.sledges = []
self.skis = []
self.index = index
class Team:
def __init__(self, name, players):
self.name = name
self.players = players
def get_players_count(self):
return len(self.players)
def add_player(self, player):
self.players.append(player)
def get_average_index(self):
indexes = sum(list(map(lambda p: p.index, self.players)))
count = self.get_players_count()
return float(indexes) / count
Usage:
a = Player('AName', 2)
b = Player('BName', 11)
team = Team('TeamName', [a, b])
instead of
self.players = [Player]
why not:
self.players = []
And then have a method to add players to the team as in:
def add_player(self, player):
# ensure optionally that player is a PLayer instance
assert type(player) == Player
self.players += player

How to delete an object from a list inside a list?

Let's say there are three lists, the third being a list containing the first two:
Friendly_List = list()
Enemy_List = list()
Battle_Space = list([Friendly_List, Enemy_List])
And a goblin class:
class Goblin(object):
def __init__(self):
self.Name = "Goblin"
self.HP = random.randint(15,20)
self.Damage = random.randint(5,10)
I create an instance of the Goblin class:
x = Goblin()
Then put it into Friendly_List:
Friendly_List.append(x)
Now let's say the goblin dies heroically and must be removed from the battlefield. If I do Friendly_List.remove(x), the goblin is removed without issue.
If I do Battle_Space.remove(x), it says that x is not in the list - even though x is in one of the lists that is part of the Battle_Space list.
I guess what I'm trying to ask really is: what is the proper way to achieve the desired behavior of Battle_Space.remove(x)? To remove an instance that is a layer deep?
The simple but maybe not-so-clean way is Battle_Space[0].remove(x). You would have to ensure that the first list is the friendly list.
My suggestion for readability would be to consider putting friendly_list and enemy_list in a BattleSpace object so you can refer to them by name. You can also create a method in that object to remove a target from any child list:
class BattleSpace(object):
def __init__(self):
self.friendly_list = []
self.enemy_list = []
def remove(self, target):
if target in self.friendly_list:
self.friendly_list.remove(target)
if target in self.enemy_list:
self.enemy_list.remove(target)
battle_space = BattleSpace()
battle_space.friendly_list.append(x)
battle_space.remove(x) # can also do battle_space.friendly_list.remove(x)
Edit: Just read the OP's comment that the desire is to remove anywhere in the list. Modified code.
If you know the index of the nested list, you can index from the parent list and call remove:
Battle_Space[0].remove(x)
To remove x from anywhere it appears, you can use a list comprehension:
Battle_Space = [[j for j in innerlist if j!=x] for innerlist in Battle_Space]
Just filter those damm goblins out, for instance:
import random
class Goblin(object):
def __init__(self):
self.Name = "Goblin"
self.HP = random.randint(15, 20)
self.Damage = random.randint(5, 10)
x = Goblin()
Friendly_List = list()
Enemy_List = list()
Battle_Space = list([Friendly_List, Enemy_List])
Friendly_List.append(x)
Friendly_List.append(x)
Friendly_List.append(x)
Enemy_List.append(x)
print Battle_Space
for index, army in enumerate(Battle_Space):
Battle_Space[index] = filter(lambda entity: entity != x, army)
print Battle_Space
The code will remove that damm duplicated goblin from all armies of your intergalactic battle.
I'm not a big fan of galactic battles, can goblins replicate themselves magically? :')
EDIT
If you wanted a more OOP approach, you'd transform the above code in something more like this:
import random
class Goblin(object):
def __init__(self):
self.Name = "Goblin"
self.HP = random.randint(15, 20)
self.Damage = random.randint(5, 10)
class Army(object):
def __init__(self):
self.entities = []
def remove(self, target):
if target in self.entities:
self.entities.remove(target)
def filter(self, target):
self.entities = filter(
lambda entity: self.entities != entity, self.entities)
class BattleSpace(object):
def __init__(self):
self.armies = []
def remove(self, target):
for index, army in enumerate(self.armies):
army.remove(target)
def filter(self, target):
for index, army in enumerate(self.armies):
army.filter(target)
x = Goblin()
battle_space = BattleSpace()
Friendly_List = Army()
Enemy_List = Army()
battle_space.armies = [Friendly_List, Enemy_List]
Enemy_List.entities.append(x)
print "Initial setup"
print Enemy_List.entities
print Friendly_List.entities
print "After removing"
battle_space.remove(x)
print Enemy_List.entities
print Friendly_List.entities
This way you could extend easily your BattleSpace to zillion of intergalactic armies from different planets

Classes, objects and lists in python

so I'm trying to create a program but I still have difficulties with classes. The program (which isn't finished of course) will print a random number of Villages. Each village(second Class) will have a random number of Clans(the first Class). Anyway my problem is the Village class. How do I make sure to add the areas and family size into the Village class? How do I insert the counter from the Clan class to the Village class? As you can see when I've randomized a number of Clans the areas and family sizes should add up into the Village class. What should I do? What is wrong with my Village class?
class Clan:
counter = 0
def __init__(self):
r = random.randrange(20, 101)
self.area = r
s = random.randrange(1, 6)
self.familySize = s
Clan.counter += 1
self.counter = Clan.counter
def getArea(self):
return self.area
def getFamilySize(self):
return self.familySize
class Village:
counter = 0
def __init__(self):
self.clan_list = []
for i in range(random.randrange(3, 7)):
self.clan_list += [Clan()]
def getclan_list(self):
return self.clan_list
def getArea(self):
return self.area
def getPopulation(self):
pass
So, you want the village class to calculate how many families are in the village?
families = 0
for clan in self.clan_list
families += clan.getFamilySize()
Since the values of area and population are dependent on the clans in clan_list you should compute these values each time they are needed. The alternative is much more complicated -- having to control how clans are added and removed from the village and how the area and family size of a clan can be changed and having those changes reflected in the village.
Below is an example of how you might compute both village area and population. The first using a getter method, and the second using a more python-esque property.
import random
class Clan:
counter = 0
def __init__(self):
r = random.randrange(20, 101)
self.area = r
s = random.randrange(1, 6)
self.familySize = s
Clan.counter += 1
self.counter = Clan.counter
# removed getters
# Unless your getter or setter is doing something special,
# just access the attribute directly.
class Village:
def __init__(self):
self.clan_list = []
for i in range(random.randrange(3, 7)):
self.clan_list.append(Clan())
# for a village, area is a computed value, so use a getter
def getArea(self):
total_area = 0
for clan in self.clan_list:
total_area += clan.area
return total_area
# the prefered alternative to getters (and setters) are properties
# note that the function is named as if it was an attribute rather than function
#property
def population(self):
# use sum and generator rather than a for loop
return sum(clan.familySize for clan in self.clan_list)
# How to use a village instance
v = Village()
# get area
print("area:", v.getArea())
# get population
print("population:", v.population)
# note how population is accessed as if it was an attribute rather than called
# like a function

Categories

Resources