-1

For my computer science class, I'm working on an end of year project and I chose to create a Yahtzee game using Python and Tkinter. I've started the code but what I have so far is not working and I'm not sure why, can someone help me?

The code after the "#roll1","#roll2",etc. is to create the dots for each roll possibility on the five dice. They are stored in definitions which I do not know much about. The checkboxes are used to determine which dice the player wants to roll, but when I tested out the roll button with the possibility of rolling a 1, it hasn't been working. Also I wanted the checkboxes to be organized horizontally but for some reason they are vertically. Someone please help!

from Tkinter import *
import random


root = Tk()

drawpad = Canvas(root, width=600, height=600, background='white')
dice1 = drawpad.create_rectangle(10, 10, 110, 110, fill="white")
dice2 = drawpad.create_rectangle(130, 10, 230, 110, fill="white")
dice3 = drawpad.create_rectangle(250, 10, 350, 110, fill="white")
dice4 = drawpad.create_rectangle(370, 10, 470, 110, fill="white")
dice5 = drawpad.create_rectangle(490, 10, 590, 110, fill="white")
check1 = False
check2 = False
check3 = False
check4 = False
check5 = False

# roll 1
roll1 = []
for i in range(1, 6, 1):
    x = (120 * i) - 65
    y = x + 10
    roll1.append(drawpad.create_oval(x, 55, y, 65, fill="red", state=HIDDEN))
# roll 2
roll2 = {}
for i in range(1, 6, 1):
    x = (120 * i) - 98
    y = x + 10
    x2 = (120 * i) - 33
    y2 = x2 + 10
    roll2[i] = [drawpad.create_oval(x, 23, y, 33, fill="red", state=HIDDEN), drawpad.create_oval(
        x2, 87, y2, 97, fill="red", state=HIDDEN)]
# roll3
roll3 = {}
for i in range(1, 6, 1):
    x = (120 * i) - 65
    y = x + 10
    x2 = (120 * i) - 98
    y2 = x2 + 10
    x3 = (120 * i) - 33
    y3 = x3 + 10
    roll3[i] = [drawpad.create_oval(x, 55, y, 65, fill="red", state=HIDDEN), drawpad.create_oval(
        x2, 23, y2, 33, fill="red", state=HIDDEN), drawpad.create_oval(x3, 87, y3, 97, fill="red", state=HIDDEN)]
# roll4
roll4 = {}
for i in range(1, 6, 1):
    x = (120 * i) - 98
    y = x + 10
    x2 = (120 * i) - 33
    y2 = x2 + 10
    roll4[i] = [drawpad.create_oval(x, 23, y, 33, fill="red", state=HIDDEN), drawpad.create_oval(x2, 23, y2, 33, fill="red", state=HIDDEN), drawpad.create_oval(
        x2, 87, y2, 97, fill="red", state=HIDDEN), drawpad.create_oval(x, 87, y, 97, fill="red", state=HIDDEN)]
# roll5
roll5 = {}
for i in range(1, 6, 1):
    x = (120 * i) - 98
    y = x + 10
    x2 = (120 * i) - 33
    y2 = x2 + 10
    x3 = (120 * i) - 65
    y3 = x3 + 10
    roll5[i] = [drawpad.create_oval(x, 23, y, 33, fill="red", state=HIDDEN), drawpad.create_oval(x2, 23, y2, 33, fill="red", state=HIDDEN), drawpad.create_oval(
        x2, 87, y2, 97, fill="red", state=HIDDEN), drawpad.create_oval(x, 87, y, 97, fill="red", state=HIDDEN), drawpad.create_oval(x3, 55, y3, 65, fill="red", state=HIDDEN)]
# roll6
roll6 = {}
for i in range(1, 6, 1):
    x = (120 * i) - 98
    y = x + 10
    x2 = (120 * i) - 33
    y2 = x2 + 10
    roll6[i] = [drawpad.create_oval(x, 23, y, 33, fill="red", state=HIDDEN), drawpad.create_oval(x2, 23, y2, 33, fill="red", state=HIDDEN), drawpad.create_oval(x2, 87, y2, 97, fill="red", state=HIDDEN), drawpad.create_oval(
        x, 87, y, 97, fill="red", state=HIDDEN), drawpad.create_oval(x, 55, y, 65, fill="red", state=HIDDEN), drawpad.create_oval(x2, 55, y2, 65, fill="red", state=HIDDEN)]


class MyApp(object):

    def __init__(self, parent):
        global drawpad
        self.myParent = parent
        self.myContainer1 = Frame(parent)
        self.myContainer1.pack()

        # Roll Button
        self.rollButton = Button(self.myContainer1)
        self.rollButton.configure(text="Roll", background= "green")
        self.rollButton.grid(row=0,column=0)

        # Stop Button
        self.stop = Button(self.myContainer1)
        self.stop.configure(text="End Turn", background= "green")
        self.stop.grid(row=0,column=1)

        # Dice Checkboxes
        self.var1 = IntVar()
        c = Checkbutton(root, text="Dice 1",variable = self.var1,command=self.cb)
        c.grid(row=1,column=0)
        self.var2 = IntVar()
        c2 = Checkbutton(root, text="Dice 2",variable = self.var2,command=self.cb2)
        c2.grid(row=1,column=1)
        self.var3 = IntVar()
        c3 = Checkbutton(root, text="Dice 3",variable = self.var3,command=self.cb3)
        c3.grid(row=1,column=2)
        self.var4 = IntVar()
        c4 = Checkbutton(root, text="Dice 4",variable = self.var4,command=self.cb4)
        c4.grid(row=1,column=3)
        self.var5 = IntVar()
        c5 = Checkbutton(root, text="Dice 5",variable = self.var5,command=self.cb5)
        c5.grid(row=1,column=4)

        self.rollButton.bind("<Button-1>", self.rollButtonClick)

        c.pack()
        c2.pack()
        c3.pack()
        c4.pack()
        c5.pack()
        drawpad.pack()

    def cb(self):
        global check1
        if(self.var1.get() == 1):
            check1 = True
        else:
            check1 = False

    def cb2(self):
        global check2
        if(self.var2.get() == 1):
            check2 = True
        else:
            check2 = False

    def cb3(self):
        global check3
        if(self.var3.get() == 1):
            check3 = True
        else:
            check3 = False

    def cb4(self):
        global check4
        if(self.var4.get() == 1):
            check4 = True
        else:
            check4 = False

    def cb5(self):
        global check5
        if(self.var5.get() == 1):
            check5 = True
        else:
            check5 = False

    def rollButtonClick(self, event):   
        global drawpad
        global roll1
        global check
        global check2
        global check3
        global check4
        global check5
        dice1=0
        dice2=0
        dice3=0
        dice4=0
        dice5=0
        diceValues = [dice1,dice2,dice3,dice4,dice5]
        if(check1==True):
            dice1 = random.randint(1,6)
        if(check2==True):
            dice2 = random.randint(1,6)
        if(check3==True):
            dice3 = random.randint(1,6)
        if(check4==True):
            dice4 = random.randint(1,6)
        if(check5==True):
            dice5 = random.randint(1,6)
        for i in (0,4,1):
            if(diceValues[i]==1):
                drawpad.itemconfig(roll1[i],state=NORMAL)


app = MyApp(root)
root.mainloop()
nbro
  • 15,395
  • 32
  • 113
  • 196
  • That code full of `globals` is crazy. That's the downside of Python, you do a lot of bad programming... Also you might consider to have a list for the long enumeration of variables that you have through your code... – nbro May 21 '15 at 20:29
  • 1
    @Xenomorph I don't think the OP's bad design is Python's fault... – jonrsharpe May 21 '15 at 20:30
  • @Xenomorph I really don't know what I'm doing, please help! And a list for which variables? – Kimberly Martin May 21 '15 at 20:32
  • @jonrsharpe What should I do to fix it?? – Kimberly Martin May 21 '15 at 20:33
  • @jonrsharpe It helps you to write worse programs than in other languages such as Java, because Python is too permissive. Of course the OP is a bit lost and needs some help. – nbro May 21 '15 at 20:36
  • @KimberlyMartin My advice: do not start a such a big program for you, if you have not grasped the basic concepts of the language (or library: tkinter), in this case Python. You cannot expect to write a program in an hour or so if you do not even know what you are doing (as you said). Try to understand each part of your program, why you are using certain tools.. – nbro May 21 '15 at 20:42
  • @Xenomorph The thing is I have about two weeks to finish this but I did not realize how difficult this project would be. I understand most of what's happening, I am just confused on dictionaries and why this is not working mainly. – Kimberly Martin May 21 '15 at 20:44
  • 1
    @Xenomorph you're entitled to your opinion, but do recognise *"too permissive"* as such (see e.g. http://dirtsimple.org/2004/12/python-is-not-java.html for a dissenting view). It's perfectly possible to write great code in Python. – jonrsharpe May 21 '15 at 20:45
  • @KimberlyMartin I will try to help, but later, because now I have also other things to do. In the meantime, I hope somebody can help or that you figure out by yourself... If the problem are the dictionaries, try to see around how dictionaries work in Python... – nbro May 21 '15 at 20:46
  • @KimberlyMartin *"The thing is I have about two weeks to finish this but I did not realize how difficult this project would be"* then talk to your lecturer; this is neither a code-writing nor tutorial service. If you have a *specific problem*, provide a [minimal example](http://stackoverflow.com/help/mcve). – jonrsharpe May 21 '15 at 20:47
  • @jonrsharpe Do not misunderstand me, Python is a fantastic language, but it has its downsides, for example the one I mentioned. Of course this is my opinion, which I think it is not too much subjective. – nbro May 21 '15 at 20:51
  • I see that you're familiar with the `list` and `dict` types - use them if you find yourself creating a whole bunch of very similar variables. I see that you are also familiar with loops - use them whenever you find yourself doing a very similar thing multiple times. – TigerhawkT3 May 21 '15 at 21:11
  • This code is uber-confusing. I noticed that you never unhide the dice dots inside the `roll2`, `roll3`, etc. variables and tried to write an answer around that, but the code is so confusing that I couldn't tell if that was genuinely a bug or not. Try to clean up and simplify your code; not only will that make it easier on us, it also might help you find the bugs yourself. Start by getting rid of globals and repeated code. – tsleyson May 21 '15 at 21:20
  • 1
    To clarify: the problems with your code aren't typos or obscure gotchas. They are fundamental programming mistakes (particularly violation of DRY), and the best way to fix that is to ask your professor for help or discuss it with your classmates. – TigerhawkT3 May 21 '15 at 21:23

2 Answers2

3

Here's what I suggest:

Focus on one thing, and one thing only. Don't try to get all of the dice working at once. Figure out how to get one dice working. Nothing else. No game logic, no other dice. Right now it's like you're learning to juggle by starting out with 10 balls. You need to start with the simplest thing possible.

In fact, don't worry about all of the dice functionality. Pick one aspect of a die and solve that. Figure out how to draw one. OR, figure out how to compute a random role. Solve just one of those problems.

Once you solve that problem, move on to the next. So, if you can draw a die, figure out how to compute a roll and redraw the die. Get that working 100%. Then, add a function that returns the current value of the die.

Next, figure out how to take all that you've done and put it into a class. You want to be able to write your main logic to do this (and only this):

<import the Die class, or define it here>
root = Tk()
drawpad = Canvas(...)
die = Die(drawpad, x, y) # draw a die at coordinate (x,y)
die.roll() # roll the die, and redraw it with the value
print(die.value()) # print out the value

Once you have all that, then you can start focusing on creating the other dice in a simple loop. Once you have that, then you can focus on the other parts of the game - the menus, buttons, etc.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
0

As stated above, start out with one thing. The following is code for one die. You would call this from another class but for simplicity it is stand alone below. I use a formula with multipliers to calculate the positions of the dots on the die as it is simpler this way, and does not require duplicate code X 5 for six die. The 6 different colors are there for testing to tell which die is being acted upon. Note also that everything relating to the die is contained in the class.

from Tkinter import *
import random


class OneDie():
    def __init__(self, drawpad, x1, x2, color):
        self.drawpad=drawpad
        self.x1=x1
        self.x2=x2
        self.color=color
        self.dots_location={1:[[0.5, 0.5]],
                            2:[[0.25, 0.25], [0.75, 0.75]],
                            3:[[0.25, 0.25], [0.5, 0.5], [0.75, 0.75]],
                            4:[[0.25, 0.25], [0.25, 0.75], [0.75, 0.25], [0.75, 0.75]],
                            5:[[0.5, 0.5], [0.25, 0.25], [0.25, 0.75], [0.75, 0.25], [0.75, 0.75]],
                            6:[[0.25, 0.25], [0.25, 0.75], [0.75, 0.25], [0.75, 0.75], [0.50, 0.25], [0.50, 0.75]]} 
        self.die = self.drawpad.create_rectangle(x1, 10, x2, 110, fill="red")
        self.update_this_die(6)  ## initialize every die to 6

    def roll_this_die(self):
        num=random.randint(1, 6)
        self.update_this_die(num)

    def update_this_die(self, num):
        self.drawpad.delete(self.die)
        self.die = self.drawpad.create_rectangle(self.x1, 10, self.x2, 110, fill="red")
        location_list = self.dots_location[num]
        for ctr in range(len(location_list)):
           multiplier_x_y = location_list[ctr]
           x=(self.x2-self.x1)*multiplier_x_y[0]+self.x1-10  ## 10 is 1/2 of circle size
           y=(110-10)*multiplier_x_y[1]
           self.drawpad.create_oval(x, y, x+20, y+20, fill=self.color, outline="red")

root = Tk()

drawpad = Canvas(root, width=600, height=300)
drawpad.grid()
Button(root, text="Exit", command=root.quit, bg="orange").grid(row=100)

instance_list=[]
x1=10
x2=110
colors=["white", "lightblue", "yellow", "black", "green"]  ## identify each die while testing
for ctr in range(5):
    OD=OneDie(drawpad, x1, x2, colors[ctr])
    x1 += 120
    x2 += 120
    instance_list.append(OD)

## roll each die once
for instance in instance_list:
    instance.roll_this_die()
root.mainloop()