Something wrong without any error - Includes Tkinter

I'm not getting any error but the code doesn't do what I want so there must be somewhere in the code where I have made a mistake. What I want to do is if the words match then the words must be a pair and the two chosen cells should remain "self.hidden = False" and therefore the cells should still show the words behind the two cells. Else if the words doesn't match then the cells should be "self.hidden = True" and the two cells should show "---".

Here are the important parts:

from tkinter import *
import random

class Cell:
    def __init__(self, word, hidden):
        self.word = word
        self.hidden = hidden

    def show_word(self):
        """ Shows the word behind the cell """
        if self.hidden == True:
            self.hidden = False
        else:
            self.hidden = True

        self.button["text"] = str(self)

        if mem.choice1 == None:
            mem.choice1 = [self.word, self.hidden]
        else:
            mem.choice2 = [self.word, self.hidden]
            self.check(mem.choice1, mem.choice2)

    def check(self, choice1, choice2):
        """ Checks if the chosen words are a pair """
        tries = 0
        if choice1 == choice2:
            pass
        else:
            self.show_word

        tries += 1

    def __str__(self):
        """ Displays or hides the word """
        if self.hidden == True:
            return "---"
        else:
            return self.word

class Memory(Frame):
    """ GUI application that creates a Memory game """
    def __init__(self, master):
        super(Memory, self).__init__(master)
        self.grid()
        self.create_widgets()
        self.tries = 0
        self.choice1 = None
        self.choice2 = None

    def readShuffle(self):
        """ Creates and organizes (shuffles) the pairs in a list """
        # reads the file and creates a list of the words
        words_file = open("memo.txt","r")
        row = words_file.readline()
        words = list()
        while row != "":
            row = row.rstrip('\n')
            words.append(row)
            row = words_file.readline()
        words_file.close()

        # shuffles the words in the list
        random.shuffle(words)

        # creates 18 pairs of words in a new list
        the_pairs = list()
        for i in range(18):
            the_pairs.append(Cell(words[i],True))
            the_pairs.append(Cell(words[i],True))

        # shuffles the words in the new list
        random.shuffle(the_pairs)

        return the_pairs

    def create_widgets(self):
        """ Create widgets to display the Memory game """
        # instruction text
        Label(self,
              text = "- The Memory Game -",
              font = ("Helvetica", 12, "bold"),
              ).grid(row = 0, column = 0, columnspan = 7)

        # buttons to show the words
        column = 0
        row = 1
        the_pairs = self.readShuffle()
        for index in range(36):
            temp = Button(self,
                   text = the_pairs[index],
                   width = "7",
                   height = "2",
                   relief = GROOVE,
                   command = lambda x = index: Cell.show_word(the_pairs[x])
                   )
            temp.grid(row = row, column = column, padx = 1, pady = 1)
            column += 1
            the_pairs[index].button = temp
            if column == 6:
                column = 0
                row += 1

        # total tries
        self.label = Label(self)
        Label(self,
              text = "Total tries: 0",
              font = ("Helvetica", 11, "italic")
              ).grid(row = 7, columnspan = 7, pady = 5)

        # a quit button
        Button(self,
               text = "Quit",
               font = ("Helvetica", 10, "bold"),
               width = "25",
               height = "1",
               command = self.quit
               ).grid(row = 8, column = 0, columnspan = 7, pady = 5)

##    def update_tries(self):
##        """ Increase tries count and display new total. """
##        self.tries += 1
##        self.label["text"] = "Total Tries: " + str(self.tries)

    def quit(self):
        """ Ends the memory game """
        global root
        root.destroy()

# main
root = Tk()
root.title("Memory")
root.geometry("365x355")
mem = Memory(root)
root.mainloop()


Asked by: Paul778 | Posted: 30-11-2021






Answer 1

The immediate problem is that you're not calling self.show_word on line 136 in Cell.check.

def check(self, choice1, choice2):
    """ Checks if the chosen words are a pair """
    tries = 0
    if choice1 == choice2:
        pass
    else:
        self.show_word

    tries += 1

(You should also just use != here, instead of having a pass statement in your if clause. Additionally, tries isn't doing anything here...)

However, even if you do call it (i.e. self.show_word() instead of self.show_word), you have bigger problems, as you'll set up an infinite loop if the words are not the same once you do.

check will call show_word which will then call check, etc, etc.

What you need to do is reset choice1 and choice2 and their respective buttons inside your else statement in Cell.check.

However, to do this, you need to have access to the cell objects in question. As it is, you only pass in their text values and whether or not they're hidden.

The quick fix is to pass around the cell objects themselves.

First, though, let's clean your functions up a bit... You have this:

def show_word(self):
    """ Shows the word behind the cell """
    if self.hidden == True:
        self.hidden = False
    else:
        self.hidden = True

    self.button["text"] = str(self)

    if mem.choice1 == None:
        mem.choice1 = [self.word, self.hidden]
    else:
        mem.choice2 = [self.word, self.hidden]
        self.check(mem.choice1, mem.choice2)

def check(self, choice1, choice2):
    """ Checks if the chosen words are a pair """
    tries = 0
    if choice1 == choice2:
        pass
    else:
        self.show_word

    tries += 1

This is equivalent to:

def show_word(self):
    """ Shows the word behind the cell """
    self.hidden = not self.hidden
    self.button["text"] = str(self)

    if mem.choice1 is None:
        mem.choice1 = [self.word, self.hidden]
    else:
        mem.choice2 = [self.word, self.hidden]
        self.check(mem.choice1, mem.choice2)

def check(self, choice1, choice2):
    """ Checks if the chosen words are a pair """
    if choice1 != choice2:
        self.show_word() # Infinite recursion!!

Now, let's pass around the Cell instances themselves, so that we can reset their displayed values.

def show_word(self):
    """ Shows the word behind the cell """
    self.hidden = not self.hidden
    self.button["text"] = str(self)

    if mem.choice1 is None:
        mem.choice1 = self
    else:
        mem.choice2 = self
        self.check(mem.choice1, mem.choice2)

def check(self, choice1, choice2):
    """ Checks if the chosen words are a pair """
    mem.choice1, mem.choice2 = None, None
    if choice1.word != choice2.word:
        for cell in (choice1, choice2):
            cell.hidden = True
            cell.button['text'] = str(cell)

Now, things will work as you intended. However, the second choice will never be displayed if it doesn't match the first one. (In fact, we could remove the mem.choice2 attribute entirely in this version.)

So, instead, let's only reset the two values on the third click, if they don't match.

def show_word(self):
    """ Shows the word behind the cell """
    self.hidden = not self.hidden
    self.button["text"] = str(self)

    if mem.choice1 is None:
        mem.choice1 = self
    elif mem.choice2 is None:
        mem.choice2 = self
    else:
        choice1, choice2 = mem.choice1, mem.choice2
        mem.choice1, mem.choice2 = self, None
        self.check(choice1, choice2)

def check(self, choice1, choice2):
    """ Checks if the chosen words are a pair """
    if choice1.word != choice2.word:
        for cell in (choice1, choice2):
            cell.hidden = True
            cell.button['text'] = str(cell)

Now, things will behave more or less how you want.

from tkinter import *
import random

class Cell:
    def __init__(self, word, hidden=True):
        self.word = word
        self.hidden = hidden

    def show_word(self):
        """ Shows the word behind the cell """
        self.hidden = not self.hidden
        self.button["text"] = str(self)

        if mem.choice1 is None:
            mem.choice1 = self
        elif mem.choice2 is None:
            mem.choice2 = self
        else:
            choice1, choice2 = mem.choice1, mem.choice2
            mem.choice1, mem.choice2 = self, None
            self.check(choice1, choice2)

    def check(self, choice1, choice2):
        """ Checks if the chosen words are a pair """
        if choice1.word != choice2.word:
            for cell in (choice1, choice2):
                cell.hidden = True
                cell.button['text'] = str(cell)

    def __str__(self):
        """ Displays or hides the word """
        if self.hidden == True:
            return "---"
        else:
            return self.word

class Memory(Frame):
    """ GUI application that creates a Memory game """
    def __init__(self, master):
        super(Memory, self).__init__(master)
        self.grid()
        self.create_widgets()
        self.tries = 0
        self.choice1 = None
        self.choice2 = None

    def readShuffle(self):
        """ Creates and organizes (shuffles) the pairs in a list """
        # reads a list of words from the file
        with open('memo.txt', 'r') as infile:
            words = [line.strip() for line in infile]

        # creates 18 pairs of words in a new list
        the_pairs = list()
        for i in range(18):
            the_pairs.extend([Cell(words[i]), Cell(words[i])])

        # shuffles the words in the new list
        random.shuffle(the_pairs)

        return the_pairs

    def create_widgets(self):
        """ Create widgets to display the Memory game """
        # instruction text
        Label(self,
              text = "- The Memory Game -",
              font = ("Helvetica", 12, "bold"),
              ).grid(row = 0, column = 0, columnspan = 7)

        # buttons to show the words
        column = 0
        row = 1
        the_pairs = self.readShuffle()
        for index in range(36):
            temp = Button(self,
                   text = the_pairs[index],
                   width = "7",
                   height = "2",
                   relief = GROOVE,
                   command = the_pairs[index].show_word
                   )
            temp.grid(row = row, column = column, padx = 1, pady = 1)
            column += 1
            the_pairs[index].button = temp
            if column == 6:
                column = 0
                row += 1

        # total tries
        self.label = Label(self)
        Label(self,
              text = "Total tries: 0",
              font = ("Helvetica", 11, "italic")
              ).grid(row = 7, columnspan = 7, pady = 5)

        # a quit button
        Button(self,
               text = "Quit",
               font = ("Helvetica", 10, "bold"),
               width = "25",
               height = "1",
               command = self.quit
               ).grid(row = 8, column = 0, columnspan = 7, pady = 5)


    def quit(self):
        """ Ends the memory game """
        global root
        root.destroy()

# main
root = Tk()
root.title("Memory")
root.geometry("365x355")
mem = Memory(root)
root.mainloop()

However, there's still a lot of cleanup and re-factoring that you could do. It would make much more sense to have the Memory class handle checking clicks, etc. Also, have a look at the new readShuffle function. You were reading in the file in an amazingly convoluted way. You should probably read over a few basic examples of file usage in python. It's much simpler than you think.

Answered by: Sarah894 | Posted: 01-01-2022



Similar questions

Large Python Includes

I have a file that I want to include in Python but the included file is fairly long and it'd be much neater to be able to split them into several files but then I have to use several include statements. Is there some way to group together several files and include them all at once?


import - Python includes, module scope issue

I'm working on my first significant Python project and I'm having trouble with scope issues and executing code in included files. Previously my experience is with PHP. What I would like to do is have one single file that sets up a number of configuration variables, which would then be used throughout the code. Also, I want to make certain functions and classes available globally. For example, the main file would i...


python - Put bar at the end of every line that includes foo

I have a list with a large number of lines, each taking the subject-verb-object form, eg: Jane likes Fred Chris dislikes Joe Nate knows Jill To plot a network graph that expresses the different relationships between the nodes in directed color-coded edges, I will need to replace the verb with an arrow and place a color code at the end of each line, thus, somewhat simplified: Jane -> Fred r...


python - How to check if phone number entered by user includes country code?

Is there an easy way to check whether a phone number entered by the user includes country code and to validate that the number is correct? I don't use any specific formats, the number itself must be only digits, no ('s, -'s and the like. Is such validation possible without asking user for a country? The trick is that I want to work with all numbers world-wide. I guess it can't be done with regex (googled a bit and...


python - PyCUDA: C/C++ includes?

Something that isn't really mentioned anywhere (at least that I can see) is what library functions are exposed to inline CUDA kernels. Specifically I'm doing small / stupid matrix multiplications that don't deserve to be individually offloaded to the GPU but am offloading a larger section of the algorithm which includes this multiplication. Noone ever liked using their own linalg functions since someone has always ...


python - Global includes in Django

I want to create a module containing different utility functions and classes to use across different apps. It's not going to define any models or views. What's the best way to do this?


python - my post method returns (u'') and django saves includes the (u'') string when saving it

This is how I retrieve the post data from the webpage. The person models can be saved but it includes the "(u'')" string. For example if change the firstname to "Alex", it gets the raw value u('Alex') and saves it. def submit_e(req, person_id=None): if(req.POST): try: person_id = req.POST['driver'] person = Person.objects.get(pk=person_id) ...


python - How do I return a string that includes new lines?

I have a question that requires I use return and I do not know how to return on multiple lines. I need to be able to get an output that looks like this Dear so and so, kjhagjkahgsdhgl;dslhglk jkasdhgjkdshkglhds;g kjdghksadjglkdjslkg kjgahkjsdhlgkdsjg;lsd where the gibberish are strings that I have


python - Celery beat queue includes obsolete tasks

I'm using periodic celery tasks with Django. I used to have the following task in my app/tasks.py file: @periodic_task(run_every=timedelta(minutes=2)) def stuff(): ... But now this task has been removed from my app/tasks.py file. However, I keep seeing call to this task in my celery logs: [2013-05-21 07:08:37,963: ERROR/MainProcess] Received unregistered task of type u'ap...


Python: mplot3d, plot a 3D solid shape that includes dots inside

I am trying to plot in python using mplot3d, a solid shape that includes inside, a group of dots that are represented in a 3d space. Perhaps the images will clarify my question. I was thinking of a sphere but also an irregular solid could work. If it is a sphe...






Still can't find your answer? Check out these communities...



PySlackers | Full Stack Python | NHS Python | Pythonist Cafe | Hacker Earth | Discord Python



top