-1

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)
Adam Smith
  • 52,157
  • 12
  • 73
  • 112
Flying Nat
  • 31
  • 5
  • 7
    Why is your class definition *inside* of a loop? – Scott Hunter Jul 16 '15 at 18:13
  • 1
    in your `__init__()` you are assigning `self.woodpile` two consecutive times, why? – Iron Fist Jul 16 '15 at 18:14
  • i fixed it, but its still not doing what i want it doing – Flying Nat Jul 16 '15 at 18:19
  • Hey @FlyingNat , I was the one who answered your [last question](http://stackoverflow.com/questions/30245153/how-do-i-change-variables-inside-classes-in-python). What did I leave unclear? – Adam Smith Jul 16 '15 at 18:28
  • Hello again, well i probably didn't make myself clear, i just wanted to get this working so i know i can code things right and make it work the way i want it to work. im sorry because i feel like you will not like me because i didn't use your idea. i am a teen so please excuse my grammar and my childishness. please read the question if you wanna know my issue. – Flying Nat Jul 16 '15 at 18:34
  • Im sorry @ScottHunter, but what are you saying? – Flying Nat Jul 16 '15 at 18:37
  • @FlyingNat @ScottHunter is asking why use the `while True` to define the Class? That loop doesn't appear to be necessary – Sam Cohen-Devries Jul 16 '15 at 18:42
  • ah, well i put the class in the loop to try and stop the var's stonepile and woodpile being REdefined, so if i defined the var's outside the loop i thought it might work. this is my problem, can you fix it please? – Flying Nat Jul 16 '15 at 18:46
  • Did i accidently delete your comment @Samcd? either way, could you turn it into an answer? – Flying Nat Jul 16 '15 at 18:56

4 Answers4

1

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

Robert Jacobs
  • 3,266
  • 1
  • 20
  • 30
  • Thank you, i will improve my coding and if it works i'll approve of the answer. Thank you again. – Flying Nat Jul 16 '15 at 19:03
  • although this will work, it's a poor design choice. You should avoid `global` whenever you can, because it breaks encapsulation. – Adam Smith Jul 16 '15 at 19:21
  • IT WORKS!!! Thank you for your help. I made both variables global inside the class but it came up with this: "SyntaxError: name 'woodpile' is paramerter and global." so i removed both variables from all parameter of the class and now it works how i want it to – Flying Nat Jul 16 '15 at 19:26
0

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)
Sam Cohen-Devries
  • 2,025
  • 2
  • 18
  • 35
0

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)
Flying Nat
  • 31
  • 5
0

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

Adam Smith
  • 52,157
  • 12
  • 73
  • 112
  • i fixed it up a tiny bit and i got this still: random.choice(self.mine, self.chop)() TypeError: choice() takes 2 positional arguments but 3 were given – Flying Nat Jul 16 '15 at 19:41
  • @FlyingNat oops, fixed. I always think `random.choice` accepts `*args` but it actually accepts a single list of the options. – Adam Smith Jul 16 '15 at 19:54
  • what is "object" for? – Flying Nat Jul 16 '15 at 20:01
  • BTW, thank you for all your help! you were a massive help this time round. im not trying to be mean, sorry. – Flying Nat Jul 16 '15 at 20:04
  • @FlyingNat You don't sound mean! Asking questions is good! http://stackoverflow.com/questions/54867/what-is-the-difference-between-old-style-and-new-style-classes-in-python should answer why I use `class Name(object)` instead of `class Name`. It's really just habit, now, since Python3 uses new-style classes by default. – Adam Smith Jul 16 '15 at 20:06