0

I'm trying to make a chopsticks game. Here's a wikipedia link to the game https://en.wikipedia.org/wiki/Chopsticks_(hand_game). So far I just added a couple methods so that one hand can attack another hand using the 'attack' method. I feel like the code I wrote is very verbose, ugly and maybe even wrong though. How can I write this more elegantly?

class game:
    def __init__(self):
        self.x_left = 1
        self.x_right = 1
        self.o_left = 1
        self.o_right = 1  

    def set_x_left(self, num):
        self.x_left = num

    def set_x_right(self, num):
        self.x_right = num

    def set_o_left(self, num):
        self.o_left = num

    def set_o_right(self, num):
        self.o_right = num    

    def dict_func(self, hand):        
        self.func= {'x_left': self.set_x_left, 'x_right': self.set_x_right,
             'o_left': self.set_o_left, 'o_right': self.set_o_right}

        return self.func[hand]

    def dict_hand(self, hand):
        self.hands = {'x_left': self.x_left, 'x_right': self.x_right,
             'o_left': self.o_left, 'o_right': self.o_right}     

        return self.hands[hand]

    def attack(self, from_hand, to_hand):
        self.dict_func(to_hand)(self.dict_hand(from_hand) + self.dict_hand(to_hand))
Jonathan
  • 247
  • 3
  • 11

1 Answers1

1

your code seems to have some unnecessary methods. You can get rid of the methods that set the variables with a number:

def set_x_left(self, num):
    self.x_left = num

When you create an instance of game you can use dot notation to set the values:

chopsticks = game()
#   ^^^ that's the instance

chopsticks.set_x_left(0)
# is the same as 
chopsticks.x_left = 0

As you can see it's quicker to type, doesn't require any methods. It's just attribute assignments. Doing this will affect you dict_func method, so you can create an anonymous function instead:

def dict_func(self, hand):        
    self.func = {'x_left': lambda self, x: self.x_left = x,
                 'x_right': lambda self, x: self.x_right = x,
                 'o_left': lambda self, x: self.o_left = x,
                 'o_right': lambda self, x: self.o_right = x}

    return self.func[hand]

In fact you can declare the self.func self.hands attributes in __init__ to make sure that they're only assigned to once. Then in the function you can just write return self.func[hand]

Your dict_hand method is also slightly over complicated. Your aim is to get the attribute from the instance dict, so you can do:

def dict_hand(self, hand):
    return getatttr(self, hand)

(You may want to rename this function :))

N Chauhan
  • 3,407
  • 2
  • 7
  • 21
  • I put those in for the purpose of my attack method. – Jonathan Aug 29 '18 at 22:32
  • I don't think this works actually. From what I've read and the errors I'm encountering, you can't make an assignment statement with lambda. Also, I think that syntax might be wrong. – Jonathan Aug 29 '18 at 23:06
  • see here: https://stackoverflow.com/questions/50090868/why-are-assignments-not-allowed-in-pythons-lambda-expressions – Jonathan Aug 29 '18 at 23:08
  • Hmm I believe you're entirely correct. Didn't know about that. But I think your `dict_hand` method should work with `getattr` instead – N Chauhan Aug 30 '18 at 10:10