Python Object-Oriented Python Dice Roller RPG Roller

I'm not sure where I'm going wrong. Die roller challenge

I've tried to understand what exactly this challenge is looking for but no dice. It seems to function perfectly fine, what do I need to do?

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 __init__(self, *args, **kwargs):
        super().__init__()

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

    def roll(self, number):
        for _ in range(number):
            self.append(D20())

5 Answers

roll needs to be a classmethod of Hand that returns a new instance of a Hand containing number amount of D20s

Thanks Alex! Figured it out thanks to that

Mark Chesney
Mark Chesney
11,249 Points

Can you please help me with mine? The issue is that if I run my_hand.total, then my_hand.roll(2), then again my_hand.total, the new total won't correspond to the fresh reroll -- it's stuck on the total from when Hand() was instantiated.

Thanks.

class Hand(list):
    def __init__(self, size=0, die_class=None, *args, **kwargs):
        if not die_class:
            raise ValueError("Please pass in a die_class")
        super().__init__()

        for _ in range(size):
            self.append(die_class())
        #self.sort()

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

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

You are instantiating your class and giving it to the variable my_hand. my_hand has the original instance of Hand as a result. When you call your class method you are simply returning a class instance but not assigning it to my_hand therefore my_hand remains the same as it was to begin with.

The challenge asks you to make a class which, when the classmethod roll is called on it, returns an instance of itself, which yours should do, if you have imported your D20 class, but I'm not sure what you're using the output variable for.

Mark Chesney
Mark Chesney
11,249 Points

Hi Dominic. Thanks for your help.

I can accept that my output list is wrong; I'm still unaware of what code would make it correct. I borrowed output=[] and output.append(D20()) from the @classmethod lesson:

    @classmethod
    def create_bookcase(cls, book_list):
        books = []
        for title, author in book_list:
            books.append(Book(title, author))
        return cls(books)

My hands.py begins with this:

from dice import D20

My dice.py ends with this (which gets me to pass task 1 of 2):

class D20(Die):
    def __init__(self):
        super().__init__(sides=20)

I've made countless code permutations in my attempts to self-debug this. I can't show them all here. I just need a hint, that the Code Challenge doesn't provide directly.

Thanks

As you can see in that @classmethod lesson they create a class called bookcase and have to create a list object, books, to store the book_list items in. In our case, however, we are given the Hand class which Inherits from List, therefore you can use list methods on Hand instances themselves.

Your first solution was really very close! Just remember you're trying to devise a class where the statement Hand.roll(2) will return a Hand instance with 2 D20 and that cls in your classmethod represents the class Hand itself.

Mark Chesney
Mark Chesney
11,249 Points

Thanks Dominic.

Everything you said makes sense. There's some error and I can't find it.

I'm assuming cls is an instance of a Hand, which inherits from list. But then do you know why I get the error Can't get the length of a Hand ?

Also I ran Python Debugger (pdb), and I see these things:

type(cls)
# >>> <class 'type'>
TypeError: descriptor append requires a list object but received a type

Thanks

from dice import D20

class Hand(list):
    def __init__(self, size=0, die_class=None, *args, **kwargs):
        if not die_class:
            raise ValueError("Prohibited: User must specify a die_class")
        super().__init__()

        for _ in range(size):
            self.append(die_class())
        #self.sort()

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

    @classmethod
    def roll(cls, size=2, die_class=D20):
        # import pdb; pdb.set_trace()
        for _ in range(size):
            cls.append(die_class())
        return cls(size, die_class)

You're very close! Pay close attention to what you're doing in your roll method, what are you creating and what are you returning? What is that loop you're doing, doing? What are you appending to? A big hint is that cls represents the class but cls() represents a class instance.

Mark Chesney
Mark Chesney
11,249 Points

Thank you very much Dominic. Very, very much. I've passed the challenge :)

from dice import D20

class Hand(list):
    def __init__(self, num_of_items=0, die_class=D20, *args, **kwargs):
        if not num_of_items:
            raise ValueError("NUMBER OF ITEMS must be specified.")
        super().__init__(*args, **kwargs)
        for _ in range(num_of_items):
            self.append(D20())

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

    @classmethod
    def roll(cls, num_of_items):
        return cls(num_of_items)