Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Object-Oriented Python Dice Roller RPG Roller

ghaith omar
ghaith omar
16,395 Points

Hand challenge in python

Hi I am stuck on this challenge, I wrote the code and its work in my work space, but for some reason it didn't pass the challenge:

This is the challenge Now update Hand in hands.py. I'm going to use code similar to Hand.roll(2) and I want to get back an instance of Hand with two D20s rolled in it. I should then be able to call .total on the instance to get the total of the two dice. I'll leave the implementation of all of that up to you. I don't care how you do it, I only care that it works.

I hope any one can help me. Thanks in advance

dice.py
import random


class Die:
    def __init__(self, sides=2):
        if sides < 2:
            raise ValueError("Can't have fewer than two sides")
        self.sides = sides
        self.value = random.randint(1, sides)

    def __int__(self):
        return self.value

    def __add__(self, other):
        return int(self) + other

    def __radd__(self, other):
        return self + other

class D20(Die):
    def __init__(self):
        super().__init__(sides=20)
hands.py
from dice import D20
class Hand(list):
    def roll(self, size=0, die_class=D20, *args, **kwargs):
        super().__init__()
        for _ in range(size):
            self.append(die_class())

        self.sort()
        return self





    @property
    def total(self):
        return sum(self)

2 Answers

Steven Parker
Steven Parker
231,275 Points

Here's a few hints:

  • you might try implementing roll as a class method, as it won't be called on an instance
  • remember to instantiate a new Hand and return it
  • you can't sort a Hand, because neither D20 or Die implement __cmp__ which it needs
  • the instructions don't require the hand to be sorted anyway
ghaith omar
ghaith omar
16,395 Points

Thanks for the answer.

I wasn't fully understand the classmethod, after some reading its now clear what the task request and what you say. so thanks for the explanation.

this is now my answer:

from dice import D20

class Hand(list):

def __init__(self, x):

    super().__init__()

    self.extend(x)

@property

def total(self):

    return sum(self)      

@classmethod

def roll(cls,size, die_class =D20):

  x = []

  for _ in range(size):

    x.append(die_class())

  return cls(x)
Casey Nord
Casey Nord
12,141 Points

This helped me a lot. I had very similar code to Ghaith's original post. I still don't understand class methods that well but after awhile I think I picked up on a hint in the challenge question:

"I'm going to use code similar to Hand.roll(2)"

The question asks to use the command Hand.roll() with a capital H. This would imply that we don't want to create an instance of the class, but that we want to be able to call the class directly, is that correct? That would point to using a class method. The expected output in the shell would be:

>>> Hand.roll(2)
[16, 20]

I played with it for a while though and couldn't figure out how to get my code to work. I found this post and it really helped me out, but there still a few other things I'm wondering about:

The original code I had been trying looked like this and didn't pass:

from dice import D20


class Hand(list):
    def __init__(self, size=0, die_class=D20, *args, **kwargs):
        super().__init__()

    @classmethod
    def roll(cls, size, die_class=D20):
        new_hand = []
        for _ in range(size):
            new_hand.append(die_class())
        return cls(hand)

    @property
    def total(self):
        return sum(self)

after finding this post I was able to correct my code to pass the challenge:

from dice import D20


class Hand(list):
    def __init__(self, new_hand):
        super().__init__()
        self.extend(new_hand)

    @classmethod
    def roll(cls, size, die_class=D20):
        new_hand = []
        for _ in range(size):
            new_hand.append(die_class())
        return cls(new_hand)

    @property
    def total(self):
        return sum(self)

The questions I still have are:

  • Including args and kwargs in the arguments of the init method was giving me a "Hand doesn't return the correct total" error. Why is this? I had to remove the arguments altogether to pass the challenge.
  • I didn't expect to use the .extend() in the init method. I'm confused as to exactly why it was necessary to move all of my original init arguments to my classmethod and why it was necessary to include the list I created (new_hand) in the arguments of the init method along with self.extend(new_hand).
Steven Parker
Steven Parker
231,275 Points

The answer to both questions is that by overriding __init__, you took on the responsibility for compatibility with what it did before, which meant both handling the passed argument the same way and not requiring additional ones.

ghaith omar
ghaith omar
16,395 Points

Hi I am glade that my question helped you. I think the answer of your second question that you cant roll the dice without the size and die class, so in order to roll the dice with class method you must take in the class method the 2 argument size and die class. In this case there is no need in your original class to use the size and die class as an argument again. your class method will return a list of 2 number as a value to the class to be used in the class, that's why you must use .extend not .append.

For your first question I don't think I can answer you, I hope that I was able to help you.

I like you, you research, Thanks for saving me a lot of time and posting a lot of examples.