I need help with an elevator simulator in Python and I don't have much experience. There should be a user entered amount of customers that have randomized start and destination floors. Right now I'm just coding the simple strategy of the elevator going all the way to the top, and then back to the bottom. When I run my code, the program infinitely loops. I can't figure out why. Also, I'm not sure how to code my building's output method, which I want to display which customers had which floors and how many floors the elevator visited. Thanks for your help.
import random
class Elevator(object):
def __init__(self, num_of_floors, register_list, direction = "up", cur_floor=1):
self.total_floors = num_of_floors
self.reg_list = register_list
self.floor = cur_floor
self.direct = direction
def move(self):
"""Moves the elevator one floor"""
if self.total_floors == self.floor:
self.direct = "down"
if self.direct == "up":
self.floor += 1
else:
self.floor -= 1
def register_customer(self, customer):
self.reg_list.append(customer)
def cancel_customer(self, customer):
self.reg_list.remove(customer)
class Building(object):
def __init__(self, num_of_floors, customer_list, elevator):
self.total_floors = num_of_floors
self.customers = customer_list
def run(self):
while elevator.floor != 0:
for customer in self.customers:
if elevator.floor == customer.on_floor:
elevator.reg_list.append(customer)
customer.indicator = 1
elif elevator.floor == customer.going_floor:
elevator.reg_list.remove(customer)
customer.indicator = 0
customer.fin = 1
elevator.move()
def output(self):
pass
class Customer(object):
def __init__(self, ID, num_of_floors, cur_floor=0, dst_floor=0, in_elevator=0, finished=0):
self.ident = ID
self.indicator = in_elevator
self.fin = finished
cur_floor = random.randint(1, num_of_floors)
self.on_floor = cur_floor
dst_floor = random.randint(1, num_of_floors)
while dst_floor == cur_floor:
dst_floor = random.randint(1, num_of_floors)
self.going_floor = dst_floor
customer_count = int(input("How many customers are in the building?: "))
floor_count = int(input("How many floors does the building have?: "))
cus_list = []
for i in range(1, customer_count+1):
cus_list.append(Customer(i, floor_count))
elevator = Elevator(floor_count, cus_list)
building = Building(floor_count, cus_list, elevator)
Your problem lies here:
def run(self):
while elevator.floor != 0:
print(elevator.floor)
for customer in self.customers:
print(customer)
if elevator.floor == customer.on_floor:
elevator.reg_list.append(customer)
customer.indicator = 1
elif elevator.floor == customer.going_floor:
elevator.reg_list.remove(customer)
customer.indicator = 0
customer.fin = 1
elevator.move()
When you do elevator.reg_list.append(customer), you are re-appending the customer to the list, increasing it size (self.customers is also a reference to this same list) so the "for customer in self.customers" loops forever.
Lets follow "cus_list" :
elevator = Elevator(floor_count, cus_list)
building = Building(floor_count, cus_list, elevator)
class Building(object):
def __init__(self, num_of_floors, customer_list, elevator):
self.total_floors = num_of_floors
self.customers = customer_list
class Elevator(object):
def __init__(self, num_of_floors, register_list, direction = "up", cur_floor=1):
self.total_floors = num_of_floors
self.reg_list = register_list # <-------- THIS IS "cus_list" reference
Finally in class Building:
elevator.reg_list.append(customer)
elevator is a global variable here created outside the scope of the class FYI.
A fix may be as follows
The elevator starts out empty right?
class Elevator(object):
def __init__(self, num_of_floors, register_list, direction = "up", cur_floor=1):
self.total_floors = num_of_floors
self.reg_list = []
Related
So I am creating a card game in python using classes. I got it all set up to the point where it should work. But when I ran it it just simply never stops running. I am not really sure how to make this code minimal and reproduceable, because I do not know where the issue is at.
Here is the code i have written.
It has to be in the play_uno() class object.
""" UNO Simulator """
import random
class card():
def __init__(self, value, color, wild):
'''
An UNO deck consists of 108 cards, of which there are 76 Number cards,
24 Action cards and 8 Wild cards. UNO cards have four color "suits",
which are red, yellow, blue and green.
'''
self.card_nums = ['0','1','2','3','4','5','6','7','8','9']
self.card_colors = ['red','blue','green','yellow']
self.spec_cards = ['draw2','reverse','skip']
self.wild_cards = ['wild','wild_draw_4']
if wild == False:
self.value = self.card_nums[value]
self.color = self.card_colors[color]
elif wild == 'special':
self.value = self.spec_cards[value]
self.color = self.card_colors[color]
elif wild == True:
self.value = self.wild_cards[value]
self.color = None
class generate_deck():
def __init__(self):
self.number_cards = self.get_num_cards()
self.special_cards = self.get_special_cards()
self.wild_cards = self.get_wild_cards()
self.cards = self.number_cards + self.special_cards + self.wild_cards
random.shuffle(self.cards)
def get_num_cards(self):
# only one zero per color
with_zeroes = [card(i,j,False) for i in range(10) for j in range(4)]
no_zeroes = [card(i,j,False) for i in range(1,10) for j in range(4)]
return no_zeroes + with_zeroes
def get_wild_cards(self):
wild_draw4s = [card(i,None,True) for i in range(2) for x in range(2)]
wilds = [card(i,None,True) for i in range(2) for x in range(2)]
return wilds + wild_draw4s
def get_special_cards(self):
return [card(i,j,'special') for i in range(3) for j in range(4) for x in range(2)]
class player():
def __init__(self, name):
self.wins = 0
self.name = name
self.cheater = False
self.cards = ''
self.turn = 0
self.uno = 0
class play_uno():
def __init__(self, num_players = 3, num_cheaters = 0, cards_per_player = 5):
# get started
self.rules = 'default'
self.status = 'ongoing'
self.deck = generate_deck().cards
self.played_cards = []
self.dro = 0
self.direction = 0
self.top_card = self.deck.pop() # random card as first card to play on
self.tot_turns = 0
# generate players, make cheaters later
self.players = [player('player' + str(i)) for i in range(num_players + num_cheaters)]
# give each player 7 cards to start
for _player_ in self.players:
_player_.cards = [self.draw_card() for i in range(cards_per_player)]
# start playing turns in order
# do not know how to reverse yet
"""
Right now it is endless for some reason.
"""
while self.status == 'ongoing':
for _player in self.players:
self.turn(_player)
def draw_card(self):
# draws random card from deck instead of card on top
if len(self.deck) == 0:
self.re_shuffle()
self.dro += 1
return self.deck.pop()
def re_shuffle(self):
self.deck = self.played_cards
random.shuffle(self.deck)
self.played_cards = []
return self.deck, self.played_cards
def play_card(self, player_cards, _card):
self.top_card = _card
return player_cards.remove(_card), self.played_cards.append(_card), self.top_card
def game_over(self, winner):
winner.wins += 1
self.game_status = 'over'
def turn(self, _player):
played = False
# check if someone played wild card last turn
if self.top_card.value in card(1,2,None).wild_cards:
self.top_card.color = random.choice(card.card_colors)
if self.top_card.value == 'wild_draw_4':
_player.cards += [self.draw_card() for i in range(4)]
self.tot_turns += 1
return _player
# check for special cards
elif self.top_card.value in card(1,2,None).spec_cards:
if self.top_card.value == 'draw2':
_player.cards += [self.draw_card() for i in range(4)]
self.tot_turns += 1
return _player
# for now we are treating reverse cards like skips
elif self.top_card.value == 'reverse' or self.top_card.value == 'skip':
played = True
self.tot_turns += 1
return _player
# If its a normal card, or regular wild
if played == False:
for _card in _player.cards:
if _card.color == self.top_card.color:
self.play_card(_player.cards, _card)
played = True
break
elif _card.value == self.top_card.value:
self.play_card(_player.cards, _card)
played = True
break
# if the player cannot play at all
# rn they just move on if they have to draw,
# cant play the card they just drew.
if played == False:
_player.cards += [self.draw_card()]
played = True
self.tot_turns += 1
# check if the player won or not
if len(_player.cards) == 0:
self.game_over(_player)
elif len(_player.cards) == 1:
_player.uno += 1
return _player.cards
In the function turn in the play_uno class you are checking for certain wild/special cards. If the value is reverse, for example, the function hits a return _player line which ends the execution of the function and the player is unable to play another card.
Move the return statements to the end of the function if you want to ensure the rest of the code is run.
I did not run the code, but I think you should test a player's number of cards before drawing again. Like this:
if len(_player.cards) == 0:
self.game_over(_player)
elif len(_player.cards) == 1:
_player.uno += 1
if played == False:
_player.cards += [self.draw_card()]
played = True
self.tot_turns += 1
Or are the rules of this game different? I sincerely don't remember them anymore.
The while loop at the end of play_uno's __init__ checks for status, which never changes.
The loop calls turn on each of players every iteration. You must change status somewhere or you must put an if ...: break in the while loop (e.g. if not _player.cards).
EDIT: It appears that you meant self.status instead of self.game_status, in game_over. Try changing game_status to status there.
Background
I am trying to ensure I am generating a unique credit card number. The credit card number needs to be 16 digits long with the last digit equal to the checksum which in this case is self.checksum = 1.
The first 6 digits of the credit card number must be 400000.
Since the last digit must be equal to the checksum or 1 in this case, I believe I need to implement a range in my code somehow to indicate when the maximum credit card number has been issued. In this case, the maximum credit card number is 40000009999999991. Anything after that would change the first 6 digits.
While the current solution "works" it does so by only adding 10 to the first possible credit card number initialized in the __init__ as self.credit_card_number = 4000000000000001.
Help needed
I am looking for help taking my existing code and implementing a range of some sort that can alert when the last credit card number in the range has been issued.
from random import randrange
class Accounts:
def __init__(self):
self.accounts_list = []
self.all_accounts = dict()
self.balance = 0
# Initial credit card number
self.credit_card_number = 4000000000000001
# Checksum is the last digit (16th) in the credit card number.
self.checksum = 1
# Pin number is generated in account_creation
self.pin = None
def main_menu(self):
while True:
main_menu_choice = input('1. Create an account\n'
'2. Log into account\n'
'0. Exit\n')
if main_menu_choice == '1':
self.account_creation()
def account_creation(self):
# Create credit card number ensuring it is unique by adding 1 to initialized value.
if len(self.accounts_list) == 0:
self.credit_card_number = self.credit_card_number
else:
self.credit_card_number = self.credit_card_number
self.credit_card_number = self.credit_card_number + 10
# Create pin number.
pin = int(format(randrange(0000, 9999), '04d'))
# Add credit card number to list used in the above if statement.
self.accounts_list.append(self.credit_card_number)
# Add the credit card number, pin, and balance to dictionary.
self.all_accounts[self.credit_card_number] = {'pin': pin, 'balance': self.balance}
# Print the output to make sure everything is OK.
print(self.accounts_list)
# Print the output to make sure everything is OK.
print(self.all_accounts)
print(f'\n'
f'Your card has been created\n'
f'Your card number:\n'
f'{self.credit_card_number}\n'
f'Your card PIN:\n'
f'{pin}'
f'\n')
Accounts().main_menu()
Can you update your init to generate credit cards:
def __init__(self):
# do you stuff
self.credit_card_first_6 = '400000'
self.checksum = '1'
# this will be used to create a unique credit card
self.count = 0
# middle numbers MUST be smaller than this
self.max_count = 1000000000
def account_creation(self):
#### do your stuff
# for this user they have a unique 9 digits in the middle
# this is then zero padded using zfill
unique_id = str(self.count).zfill(9)
# create the full credit card number
# note: store each bit as a str so we can concat then convert to int
credit_card_number = int(self.credit_card_first_6 + unique_id + checksum)
self.count += 1
# update your init values when your limit is reached
if self.count >= self.max_count:
self.count = 0
self.credit_card_first_6 = str(int(self.credit_card_first_6) + 1)
Since you marked Matt's answer as a valid I've added a quick refactor with some extra code that might be use full to you.
class Account:
balance = 0
__pin = None # this are
__number = None # private members
def __eq__(self, other):
return self.__number == other
def is_pin(self, pin):
return self.__pin == pin
def number(self):
return self.__number
# adding a 'is not none' makes
# it a 'write only once' variable,
# if a 'none' text is added as a input
# text is added not a None type
def set_pin(self, pin):
if self.__pin is None:
self.__pin = pin
return True
return False
def set_number(self, num):
if self.__number is None \
and len(str(num)) == 16:
self.__number = num
return True
return False
# eeextra simple checksum
def checksum(self):
ck_sum = 0
for i in str(self.__number):
ck_sum += int(i)
return int(str(ck_sum)[-1])
class Accounts:
base_num = 4000000000000000
def __init__(self):
self.accounts = []
self.num_offset = 0
#staticmethod
def dialog_choice():
choice = input(
'1. Create an account\n'
'2. Log into account\n'
'0. Exit \n \n'
)
return choice
def next_card_num(self):
self.num_offset += 1
return self.base_num + self.num_offset
def dialog_acount_creation(self):
card_pin = input('New pin ->')
card_num = self.next_card_num()
print('Card number ->', card_num)
return card_num, card_pin
#staticmethod
def dialog_login():
card_num = input('Card number ->')
card_pin = input('Card pin ->')
return int(card_num), card_pin
#staticmethod
def dialog_error(*args):
print('Error on acount', args[0])
def main_loop(self):
dia_map = {
'1': self.dialog_acount_creation,
'2': self.dialog_login,
}
cho_map = {
'1': self.account_creation,
'2': self.account_login,
}
err_map = {
'1': self.dialog_error,
'2': self.dialog_error,
}
while True:
o = self.dialog_choice()
if o == '0':
break
if o in cho_map:
q_dialog = dia_map[o]()
q_done = cho_map[o](*q_dialog)
if not q_done:
err_map[o](*q_dialog)
else:
print('Invalid option')
def account_login(self, num, pin):
for acc in self.accounts:
if acc == num and acc.is_pin(pin):
print('You are logged in !')
return True
return False
def account_creation(self, num, pin):
new_accaunt = Account()
new_accaunt.set_number(num)
new_accaunt.set_pin(pin)
self.accounts.append(new_accaunt)
return True
if __name__ == '__main__':
h_acc = Accounts()
h_acc.account_creation(4000000000000000, '1234')
h_acc.main_loop()
I have been programming a piece of code to try and carry through a class from one function to another (the code is also broken in other ways but those aren't the important ones). The major problem if you define a class in the enter function it then gives the error:
exec("""print({}.Show())""".format(x))
File "<string>", line 1, in <module>
NameError: name (whatever I have called the class title) is not defined
in the tr function.
import pickle
import traceback
import sys
classtitles = []
class Customer(object):
def __init__(self):
try:
self.load()
print(self.customer)
except:
None
def init2(self,customer_name,home_address,telephone_number):
self.customer = customer_name
self.address = home_address
self.phone = telephone_number
print(self.customer)
classtitles.append(self.customer)
def carpet_amounts(self, carpet_type, grippers_bool):
self.type = carpet_type
self.grippers = grippers_bool
def price(self, size, perimeter):
self.size = size
self.perimeter = perimeter
self.price = 0
if self.type == "First":
self.price = float(5.99) * self.size
if self.type == "Monarch":
self.price = float(7.99) * self.size
if self.type == "Royal":
self.price = int(60) * self.size
price_add = float(22.5) * self.size
if self.grippers == True:
price_add += self.perimeter * float(1.10)
hours = 0
while size >= 16:
hours += 1
size -= 16
self.hours = hours
price_add += hours * 65
self.price += price_add
def Show(self):
print("show")
if self.grippers == True:
grips = "with"
else:
grips = "without"
return ("the size is {}m^2 and with a {} undercarpet and {} grippers, totalling more than {} hours of work is {}".format(self.size,self.type,grips,self.hours,self.price))
def save(self):
"""save class as self.name.txt"""
file = open('ClassSave.txt','wb')
file.write(pickle.dumps(self.__dict__))
file.close()
def load(self):
"""try load self.name.txt"""
file = open('ClassSave.txt','r')
datapickle = file.read()
file.close()
self.__dict__ = pickle.loads(dataPickle)
def loadf():
f = open('classnames.txt','r')
mylist = f.read().splitlines()
for x in mylist:
exec("""{} = Customer()""".format(mylist[0]))
customs()
def customs():
try1 = input("Would you like to 1. Enter a new customer. 2. View all the customers. 3. Delete an old customer")
if try1 == '1':
enter()
elif try1 == 'q':
sys.exit()
else:
tr()
def enter():
name = input("What is thr customers name (no space i.e. 'JoeBloggs')? ")
address = input("What is their address")
phonenumber = str("What is their phone number")
exec("""{} = Customer()""".format(name))
exec("""{}.init2("{}","{}","{}")""".format(name,name,address,phonenumber))
print(classtitles)
carpet_type = input("What type of carpet would they like ('First','Monarch','Royal')? ")
grips = str(input("Would they like grips (1 = yes, 2 = no)? "))
if grips == '1':
grips = True
else:
grips = False
exec("""{}.carpet_amounts("{}",{})""".format(name,carpet_type,grips))
size = int(input("What is the m^2 size of their carpet? "))
perimeter = int(input("What is the m perimeter of their carpet? "))
exec("""{}.price({},{})""".format(name,size,perimeter))
exec("print({}.Show())".format(name))
file2 = open('classnames.txt','w')
for x in classtitles:
file2.write(x)
file2.close()
exec("{}.save()".format(name))
customs()
def tr():
x = input("name")
print(x)
exec("""print({}.Show())""".format(x))
customs()
loadf()
I haven't coded in python in a long time, since 2.7 came out. I am trying to make a simple tic tac toe game, but if I try to reference a attribute in TicTacToe object. It throws a run time exception saying that TicTacToe has no such attribute. Any ideas?
class TicTacToe(object):
def __init__(self):
'''
:return: TicTacToe object
'''
self.turn = 1
self.deckList = [Deck()]
self.player1 = Player()
self.player2 = Player()
def validateInput(self, num):
if type(num) is not int:
print('Not an integer 0-8')
return
elif num < 0 | num > 8:
print('Not between 0-8')
return
def getUserInput(self, turn):
if turn == 1:
choice = input('Player 1: Enter 0-8\n')
#turn = 2
elif turn == 2:
choice = input('Player 2: Enter 0-8\n')
#turn = 1
return choice
def startGame(self):
player1Name = input('Player 1: Enter your name\n')
player2Name = input('Player 2: Enter your name\n')
self.player1.Player.setName(player1Name)
self.player2.Player.setName(player2Name)
player1Mark = input('Player 1: Enter your mark\n')
player2Mark = input('Player 2: Enter your mark\n')
if player1Mark == player2Mark:
print('You both cannot have the same mark\n')
return
else:
self.player1.setMark(player1Mark)
self.player2.setMark(player2Mark)
while True: # Main loop
choice = self.getUserInput(self.turn)
Main
from TicTacToe import TicTacToe
if __name__ == '__main__':
game = TicTacToe
game.startGame(game)
pass
I have the other classes here, Player class and Deck(Board) class
import numpy as np
class Deck(object):
def __init__(self):
"""
:return: Deck
"""
board = np.matrix([-1,-1,-1],[-1,-1,-1],[-1,-1,-1])
player1Choices = []
player2Choices = []
def __str__(self):
return self.board
class Player(object):
def __init__(self):
"""
:return: A new Player
"""
name = None
mark = None
statistics = [0, 0, 0] # [Win, Tie, Lost]
def setName(self, name):
"""
:param name: Set name of player
"""
self.name = name
def setMark(self, mark):
"""
:param mark: Set mark of player
"""
self.mark = mark
def getScore(self):
"""
:return: Statistics of player
"""
score = ((self.statistics[0] * 2) + self.statistics[1] - self.statistics[2])
return score
def __str__(self):
"""
:return: String representation of values inside Player
"""
return "Name: " + self.name + "\nMark: " + self.mark + "\nScore: " + self.getScore() + "\n"
def __cmp__(self, player):
"""
:param: A Player
:return: Winner
"""
if self.getScore() > player.getScore():
return self
elif self.getScore() < player.getScore():
return player
else:
return None
game = TicTacToe
Constructors need parens (and optional arguments).
game = TicTacToe()
i posted this a while ago but i've cleaned it a bit and since then, the problem is still here because no one really gave a right answer.
so what my problem is, is that my varibles that were defined outside the class and loop stonepile and woodpile (that are inside a class) aren't adding stone/wood (which are also inside the same class) to itself multiple times, i know this because i get the stonepile/woodpile to be printed. i have tested that the problem is actually the stonepile/woodpile at the begining being reset every time it is told to add stone/wood to stonepile/woodpile. i know this because i did this with them:
y = random.randint(1,5)
x = random.randint(1,5)
woodpile = y
stonepile = x
and the results were that if the stone mined was 1 and the randint for x was 5, it would print 6. or something similar.
So is there any way this can be fixed please?
the whole code here:
import random
import time
idle = True
woodpile = 0
stonepile = 0
while True:
class Taskassigner:
def __init__(self,tasknum,stonepile,woodpile):
self.tasknum = tasknum
self.woodpile = woodpile
self.stonepile = stonepile
def choosejob(self,stonepile,woodpile):
if self.tasknum == 1:
self.chop(woodpile)
if self.tasknum == 2:
self.mine(stonepile)
def chop(self,woodpile):
wood = random.randint(1, 10)
print('chopping wood')
time.sleep(1.5)
print('you got', wood)
woodpile += wood
print(woodpile)
time.sleep(0.75)
def mine(self,stonepile):
stone = random.randint(1, 10)
print('mining for stone')
time.sleep(1.5)
print('you got', stone)
stonepile += stone
print(stonepile)
time.sleep(0.75)
while idle:
taskchance = random.randint(0,1)
if taskchance == 1:
tasknum = random.randint(0,2)
job = Taskassigner(tasknum,stonepile,woodpile)
job.choosejob(stonepile,woodpile)
print
else:
print('idle')
time.sleep(0.5)
If you want to modify a global in a function (or a class function), you need to use global
foo = 0
def afunc():
global foo
foo = 1
afunc()
print foo
The names of your globals are the same as inside of the class. I noticed some places where you done woodpile += wood when you might have wanted self.woodpile += wood
You can figure out a way to instantiate the variable outside of the while idle loop. I would try not including tasknum as one of your __init__ input variables
class Taskassigner:
def __init__(self,stonepile,woodpile):
self.tasknum = 0
self.woodpile = woodpile
self.stonepile = stonepile
also since you can't chop stone or mine wood, you don't have to include them in all your methods.
i.e.
def chop(self):
wood = random.randint(1, 10)
print('chopping wood')
time.sleep(1.5)
print('you got', wood)
self.woodpile += wood
print(self.woodpile)
time.sleep(0.75)
def choosejob(self):
if self.tasknum == 1:
self.chop()
if self.tasknum == 2:
self.mine()
then you can call:
job = Taskassigner(tasknum,stonepile,woodpile)
while idle:
taskchance = random.randint(0,1)
if taskchance == 1:
job.tasknum = random.randint(0,2)
job.choosejob()
print
else:
print('idle')
time.sleep
(0.5)
This is how my working code looks:
import random
import time
idle = True
woodpile=0
stonepile=0
class Taskassigner:
def __init__(self,tasknum):
self.tasknum = tasknum
self.choosejob(tasknum)
def choosejob(self,tasknum):
if self.tasknum == 1:
self.chop()
if self.tasknum == 2:
self.mine()
def chop(self):
global woodpile
wood = random.randint(1, 10)
print('chopping wood')
time.sleep(1.5)
print('you got', wood)
woodpile += wood
print(woodpile)
time.sleep(0.75)
def mine(self):
global stonepile
stone = random.randint(1, 10)
print('mining for stone')
time.sleep(1.5)
print('you got', stone)
stonepile += stone
print(stonepile)
time.sleep(0.75)
while idle:
taskchance = random.randint(0,1)
if taskchance == 1:
tasknum = random.randint(0,2)
Taskassigner(tasknum)
else:
print('idle')
time.sleep(0.5)
Here's what I think you're trying to do:
woodpile = 0
stonepile = 0
some_task = TaskAssigner(...)
some_task.chop()
woodpile == 3 # True
You really don't WANT this to be the case. You never want your methods or functions affecting things they're not explicitly handed, because it makes debugging very very hard. Instead you should do something like:
class Stockpile(object):
def __init__(self, starting_wood=0, starting_stone=0):
self.woodpile = starting_wood
self.stonepile = starting_stone
class TaskAssigner(object):
def __init__(self, stockpile):
self.stockpile = stockpile
def mine(self):
quantity = random.randint(1,5)
self.stockpile.stonepile += quantity
def chop(self):
quantity = random.randint(1,5)
self.stockpile.woodpile += quantity
def do_task(self):
if random.randint(0, 1): # 50% chance
random.choice([self.mine, self.chop])()
# do either self.mine or self.chop
stockpile = Stockpile()
taskmaster = TaskAssigner(stockpile)
while True:
if idle:
taskmaster.do_task()
You could probably make this a bit more modular by doing something like:
from types import MethodType
import random
class TaskAssigner(object):
def __init__(self, stockpile):
self.stockpile = stockpile
self.tasks = []
def make_task(self, attr_to_change, delta_min, delta_max, f_name):
def f(self):
qty = random.randint(delta_min, delta_max)
new_total = getattr(self.stockpile, attr_to_change) + qty
setattr(self.stockpile, attr_to_change, new_total)
f.__name__ = f_name
f = MethodType(f, self)
setattr(self, f_name, f)
self.tasks.append(f)
def do_task(self):
if random.randint(0, 1):
random.choice(self.tasks)()
Then you can do:
class Stockpile(object):
def __init__(self, starting_wood=0, starting_stone=0, starting_grain=0):
self.woodpile = starting_wood
self.stonepile = starting_stone
self.grainsilo = starting_grain
stockpile = Stockpile()
tasks = TaskAssigner(stockpile)
tasks.make_task('woodpile', 1, 5, 'chop_wood')
tasks.make_task('stonepile', 1, 5, 'mine_stone')
tasks.make_task('grainsilo', 2, 10, 'harvest_grain')
tasks.harvest_grain() # adds to stockpile.grain_silo!
tasks.do_task() # 50% does nothing, 50% does one of the three!
But be aware that this is pretty advanced and unless you deeply understand it, I would strongly recommend that you don't try this kind of metaprogramming at this time