pythontkinterbuttonnim-game

Python - tkinter - Button - wrong command - what is wrong?


I'm creating a game called NIM in Python

stack = heap

This was my previous code with fixed amount of stacks (heaps) and everything is working fine

class Game:
    def __init__(self):
        self.pack_kwargs = {'fill' : BOTH, 'expand' : True, 'padx' : ['0', '0'], 'pady' : ['0', '0']}
    def player1(self):
        def chooseStack(stack):
            self.stack = stack
            window_player1_stack.destroy()

        btn1 = Button(window_player1_stack, text = '1', bd = '2', command = lambda: chooseStack(0))  
        btn2 = Button(window_player1_stack, text = '2', bd = '2', command = lambda: chooseStack(1))  
        btn3 = Button(window_player1_stack, text = '3', bd = '2', command = lambda: chooseStack(2))

        if self.stacks[0]: btn1.pack(**self.pack_kwargs)
        if self.stacks[1]: btn2.pack(**self.pack_kwargs)
        if self.stacks[2]: btn3.pack(**self.pack_kwargs)

but I want to make it possible play with any amount of stacks (instead of fixed), and it doesn't work - it always chooses last stack, not the one I've chosen

for i in range(len(self.stacks)):
    Button(window_player1_stack, text = f'{i+1}', bd = '2', command = lambda: chooseStack(i)).pack(**self.pack_kwargs)

Stack chosing

Chosing amount of stones to take

I tried doing like this and still didn't work

buttons = []
for i in range(len(self.stacks)):
    button = Button(window_player1_stack, text = f'{i+1}', bd = '2', command = lambda: chooseStack(i))
    buttons.append(button)

if self.stacks[0]: buttons[0].pack(**self.pack_kwargs)
if self.stacks[1]: buttons[1].pack(**self.pack_kwargs)
if self.stacks[2]: buttons[2].pack(**self.pack_kwargs)

I'm sorry if my english is not very good


Solution

  • It seems you have common problem with lambda in loop.

    It doesn't send value from i to lambda but only reference to variable i
    and it gets value from i when you press button but at this moment variable i has last value from for-loop - so all buttons get the same value from i.
    You have to use lambda x=i: chooseStack(x)... to copy value to another variable.

    for i in range(len(self.stacks)):
        button = Button(window_player1_stack, text=f'{i+1}', bd='2', 
                          command=lambda x=i: chooseStack(x))
        buttons.append(button)