Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Basic Object-Oriented Python Creating a Memory Game Game Class Part 3

Trang Nguyen
Trang Nguyen
446 Points

Grid doesn't show up like in the video lecture

My idea for this game is allowing user to input an even number for the grid size (min = 4, max = 12). Here's my code

import random
import string

class Card:
    def __init__(self, value, location):
        self.value = value
        self.location = location
        self.matched = False

    def __eq__(self, other):
        return self.value == other.value

    def __str__(self):
        return f'{self.value}'


class Game:
    def __init__(self, size=0):
        print('--- Welcome to Memory Game! ---')
        print('--- Please enter an even number for the board size! ---')
        self.size = size
        self.locations = []
        self.cards = []

        while self.size < 4 or self.size > 12 or self.size % 2 != 0:
            self.size = int(input('Enter valid size of the board: '))

        self.card_options = ['Add', 'Boo', 'Cat', 'Dev',  'Egg', 'Far',
                             'Gum', 'Hut', 'Foo', 'Dog', 'Bar', 'Baz']  # maximum of 12 cards
        self.columns = list(string.ascii_uppercase)[:self.size]

        for column in self.columns:
            for num in range(1, self.size + 1):
                self.locations.append(f'{column}{num}')

    def create_cards(self):
        used_locations = []
        used_cards = []

        for num in range(self.size):
            random_card = random.choice(self.card_options)
            used_cards.append(random_card)
            self.card_options.remove(random_card)

        for card in used_cards:
            for i in range(2):
                random_location = random.choice(
                    list(set(self.locations) - set(used_locations)))
                used_locations.append(random_location)
                game_card = Card(card, random_location)
                self.cards.append(game_card)

    def create_rows(self, num):
        row = []

        for column in self.columns:
            for card in self.cards:
                if card.location == f'{column}{num}':
                    if card.matched:
                        row.append(str(card))
                    else:
                        row.append('   ')

        return row

    def create_board(self):
        header = ' |  ' + '  |  '.join(self.columns) + '  |'
        print(header)

        for row in range(1, (self.size + 1)):
            print_row = f'{row}| '
            get_row = self.create_rows(row)
            print_row += ' | '.join(get_row) + ' |'

            print(print_row)

    def check_match(self, loc1, loc2):
        pass

    def start():
        pass


if __name__ == '__main__':
    game = Game()
    print(game.create_cards())
    print(game.create_board())

OUTPUT Outputs are different everytime, but they're not all closed as expected

 |  A  |  B  |  C  |  D  |
1|     |
2|     |
3|     |     |     |
4|     |     |     |

EXPECTED OUTPUT

 |  A  |  B  |  C  |  D  |
1|     |     |     |     |
2|     |     |     |     |
3|     |     |     |     |
4|     |     |     |     |

2 Answers

Trang Nguyen
Trang Nguyen
446 Points

I figured out a mistake in my logic when picking random cards from card_options in create_cards(self). My initial logic is to choose size number of words which only fill up all the locations if size = 4. So I change the logic to:

    def create_cards(self):
        number_of_words_required = int((self.size ** 2) / 2)
        used_locations = []
        used_cards = []

        for num in range(number_of_words_required):
            random_card = random.choice(self.card_options)
            used_cards.append(random_card)
            self.card_options.remove(random_card)

        for card in used_cards:
            for i in range(2):
                random_location = random.choice(
                    list(set(self.locations) - set(used_locations)))
                used_locations.append(random_location)
                game_card = Card(card, random_location)
                self.cards.append(game_card)

And I realized the maximum size = 12 so the maximum words in card_options has to be 72 words

self.card_options = ['Add', 'Boo', 'Cat', 'Dev',  'Egg', 'Far',
                             'Gum', 'Hut', 'Foo', 'Dog', 'Bar', 'Baz',
                             'Sea', 'Sue', 'Fur', 'Doo', 'Ear', 'Poo',
                             'Rob', 'Saw', 'See', 'Car', 'Hoo', 'Yes']  # maximum of 72 words

My output is now as expected... Phewwww, I struggled days doing this. Been feeling so bad about myself :(

In __init__ in the Game class,

        for column in self.columns:
            for num in range(1, self.size + 1):
                self.locations.append(f'{column}{num}')

there are self.size * self.size possible locations. In create_cards in the Game class, self.size * 2 cards are assigned a location. This leaves self.size * (self.size - 2) locations without an assigned card, and nothing is printed for those locations.

If the grid does not need to be symmetric, you could change for num in range(1, self.size + 1): to for num in range(1, 3):in __init__ to have a grid with self.size columns and 2 rows so that no locations would be empty.