How to fix the int error in a matching game using python?
Question: Okay, I've been trying this forever now. Keep getting stuck on a 'int' error.

Description:

A common memory matching game played by young children is to start with a deck
of cards that contains identical pairs. For example, given six cards in the
deck, two might be labeled 1, two labeled 2 and two labeled 3. The cards are
shuffled and placed face down on a board. A player then selects two cards that
are face down, turns them face up, and if the cards match they are left face
up. If the two cards do not match, they are returned to their original face
down position. The game continues until all cards are face up.

Sample input/output:

> > > main()

You input number of rows and columns... Enter number of rows: 3

Enter number of columns: 2

    
    
    * *
    * *
    * *
    

Then you input coords like so...

Enter coordinates for first card: 1 1

Enter coordinates for second card: 3 1

Not an identical pair. Found 2 at (1,1) and 1 at (3,1)

    
    
    * *
    * *
    * *
    

Enter coordinates for first card: 1 2

Enter coordinates for second card: 2 2

Not an identical pair. Found 2 at (1,2) and 3 at (2,2)

    
    
    * *
    * *
    * *
    

Enter coordinates for first card: 1 1

Enter coordinates for second card: 1 2

    
    
    2 2
    * *
    * *
    

Enter coordinates for first card: 3 1

Enter coordinates for second card: 3 2

Not an identical pair. Found 1 at (3,1) and 3 at (3,2)

    
    
    2 2
    * *
    * *
    

Enter coordinates for first card: 2 1

Enter coordinates for second card: 3 1

    
    
    2 2
    1 *
    1 *
    

Enter coordinates for first card: 3 2

Enter coordinates for second card: 2 2

    
    
    2 2
    1 3
    1 3
    

> > > Requirements:

Design Requirments: You need to use three classes: Card, Deck and Game. Card
stores both the card's value and face (a string or Boolean variable to
indicate whether the card is facing up or down). Deck contains the cards
needed for the game. It will contain among its methods a method to deal a
card, another for shuffling the deck, and a method that returns number of
cards left in the deck. These two classes are not identical to the classes
Card and Deck discussed in the book but have many things in common. The class
Game simulates playing a single game and represents the interaction between
the user and the other classes. Its instance members store a 2D list (of card
objects) representing the game board where the cards are placed, number of
rows and number of columns of the game board. Among the instance methods of
the Game class: play(), which simulates playing the game; isGameOver(), which
checks whether or not the game is over; displayBoard(), which displays the
board; populateBoard(), which creates the initial 2D list of identical pairs
of cards with all the cards facing down. Most probably, you will need to write
other instance methods as you see appropriate.

My code so far:

    
    
    import random
    
    class Card(object):
        '''A card object with a suit and face'''
    
        def __init__(self, value):
            '''Stores both the card's value and face'''   
            self._value = value
            self._face = False
    
        def getValue(self):
            '''Get the value of the card'''
            return self._value
    
        def getFace(self):
            '''Get the face of the card'''
            return self._face
        def setFace(self):
            self._face = True
    
    class Deck(object):
    
        def __init__(self, pairs):
            self._pairs = pairs
            self._cards = []
            for cards in range(self._pairs):
                c1 = Card(cards)
                self._cards.append(c1)
                c2 = Card(cards)
                self._cards.append(c2)
    
        def deal(self):
            if len(self) == 0:
               return None
            else:
               return self._cards.pop(0)
    
        def shuffle(self):
            '''Shuffels the cards.'''
            random.shuffle(self._cards)
    
        def __len__(self):
            '''Returns the number of cards in the deck'''
            return len(self._cards)
    
    class Game(object):
    
        def __init__(self, rows, columns):
            self._deck = Deck((rows * columns)//2)
            self._rows = rows
            self._columns = columns
            self._board = []
            for row in range(self._rows):
                self._board.append([0] * columns)
    
        def populateBoard(self):
            self._deck_shuffle()
            for columns in self._columns:
                for rows in self._rows:
                    self._board[rows][columns] = self._deck_deal()
    
        def displayBoard(self):
            for rows in self._rows:
                for columns in self._columns:
                    if self._board[rows][columns]._getFace() == False:
                        print('*')
                    else:
                        print(self._board[rows][columns._getValue()])
                    print()
    
        def play(self):
            while True:
                if self.isGameOver() == False:
                    break
                self.displayBoard()              
                coord1 = input('Enter coordinates for the first card: ')
                coord2 = input('Enter coordinates for the second card: ')
                newCoord1 = coord1.split(" ")
                newCard1 = self._board[int(newCoord1[0])][int(newCoord1[1])].getValue()
                newCoord2 = coord2.split(" ")
                newCard2 = self._board[int(newCoord2[0])][int(newCoord2[1])].getValue()
                if newCard1 != newCard2:
                    print("Not an identical pair. Found", newCard1, "at", newCoord1, "and", newcard2, "at", newCoord2)
                else:
                    self._board[int(newCoord1[0])][int(newCoord1[1])].setFace()
                    self._board[int(newCoord2[0])][int(newCoord2[1])].setFace()
    
        def isGameOver(self):             
            face = False
            for rows in self._rows:
                for columns in self._columns:
                    if self._board[row][column] == False:
                        face = True
            return face
    
    def main():
    
        while True:
            # Force user to enter valid value for number of rows
            while True:
                rows = input("Enter number of rows ")
                if rows.isdigit() and ( 1 <= int(rows) <= 9):
                    rows = int(rows)
                    break
                else:
                    print ("    ***Number of rows must be between 1 and 9! Try again.***")
                    # Adding *** and indenting error message makes it easier for the user to see
    
            # Force user to enter valid value for number of columns
            while True:
                columns = input("Enter number of columns ")
                if columns.isdigit() and ( 1 <= int(columns) <= 9):
                    columns = int(columns)
                    break
                else:
                    print ("    ***Number of columns must be between 1 and 9! Try again.***")
    
            if rows * columns % 2 == 0:
                break
            else:
                print ("    ***The value of rows X columns must be even. Try again.***")
    
        game = Game(rows, columns)
        game.play()
    
    if __name__ == "__main__":
        main()
    

Sorry for the format Problems. This site confuses me with it. Lol. If anyone
can help me out, that'd be great.

EXACT TRACEBACKS:

    
    
    Traceback (most recent call last):
      File "C:\Users\River\Desktop\Hw-3.py", line 135, in <module>
        main()
      File "C:\Users\River\Desktop\Hw-3.py", line 132, in main
        game.play()
      File "C:\Users\River\Desktop\Hw-3.py", line 84, in play
        self.displayBoard()
      File "C:\Users\River\Desktop\Hw-3.py", line 74, in displayBoard
        if self._board[rows][columns].getFace() == False:
    AttributeError: 'int' object has no attribute 'getFace'
    

and sometimes this

    
    
    Traceback (most recent call last):
      File "C:\Users\River\Desktop\Hw-3.py", line 130, in <module>
        main()
      File "C:\Users\River\Desktop\Hw-3.py", line 127, in main
        game.play()
      File "C:\Users\River\Desktop\Hw-3.py", line 79, in play
        self.displayBoard()
      File "C:\Users\River\Desktop\Hw-3.py", line 67, in displayBoard
        for rows in self._rows:
    TypeError: 'int' object is not iterable
    

Maybe a **str** method? Not sure. If it is, not sure how to write one for
this..


Answer: I fixed most of your problems. See comments within. Your code is not
considered "Pythonic", but I've left most of it as it is.

Your choice of variable and method names can be improved. For e.g., when
iterating over the rows and columns of the board, use `row` and `col` for the
iterating variables.

Also, the `getFace()` method in `Card` class can perhaps be better renamed as
`isFaceUp()`, or something to that effect. In this case, doing away with
comparison with `False` will also read more naturally.

Another issue is your use of setters/getters. They are not considered
"Pythonic" as others have already suggested in the comments.

With errors in different methods, some elementary, it seems that you were
trying to write everything at one shot. It is often a good idea to
write/test/debug small pieces of code at a time.

    
    
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    from __future__ import print_function  # I'm using Python 2.7 so need this
    
    import random
    
    
    class Card(object):
        '''A card object with a suit and face'''
    
        def __init__(self, value):
            '''Stores both the card's value and face'''
            self._value = value
            self._face = False
    
        # Getters and setters are not Pythonic
        # Consider using property
        def getValue(self):
            '''Get the value of the card'''
            return self._value
    
        def getFace(self):
            '''Get the face of the card'''
            return self._face
    
        def setFace(self):
            self._face = True
    
        def __str__(self):
            '''Override str to return printable result. Useful for debugging.'''
            return ", ".join(("Value: ", str(self._value), "Face: ", str(self._face)))
    
    
    class Deck(object):
    
        def __init__(self, pairs):
            self._pairs = pairs
            self._cards = []
            for cards in range(self._pairs):
                c1 = Card(cards)
                self._cards.append(c1)
                c2 = Card(cards)
                self._cards.append(c2)
    
        def deal(self):
            if len(self) == 0:
               return None
            else:
               return self._cards.pop(0)
    
        def shuffle(self):
            '''Shuffles the cards.'''
            random.shuffle(self._cards)
    
        def __len__(self):
            '''Returns the number of cards in the deck'''
            return len(self._cards)
    
    
    class Game(object):
    
        def __init__(self, rows, columns):
            self._deck = Deck((rows * columns)//2)
            self._rows = rows
            self._columns = columns
            self._board = []
            for row in range(self._rows):
                self._board.append([0] * self._columns)
    
            self.populateBoard()
            # self.revealBoard()  # For debugging
    
    
        def populateBoard(self):
            self._deck.shuffle()
            # For debugging
            # print("Deck: {}".format(map(str, self._deck._cards)))
            # self._board = [[self._deck.deal() for _ in range(self._columns)]
            #                for _ in range(self._rows)]
    
            # Consider renaming variables as col and row. Similar for others
            # elsewhere
            for columns in range(self._columns):
                for rows in range(self._rows):
                    self._board[rows][columns] = self._deck.deal()
    
    
        def revealBoard(self):
            """For debugging. Reveal the cards for the board"""
            for rows in range(self._rows):
                for columns in range(self._columns):
                    print(str(self._board[rows][columns].getValue()) + " ", end="")
    
                print("")
    
    
        def displayBoard(self):
            for rows in range(self._rows):
                for columns in range(self._columns):
                    if self._board[rows][columns].getFace() == False:
                        print('* ', end="")
                    else:
                        # print(self._board[rows][columns._getValue()])
                        print(str(self._board[rows][columns].getValue()) + " ", end="")
    
                print("")  # Print newline after each row
    
    
        def play(self):
            while not self.isGameOver():
                self.displayBoard()
                coord1 = raw_input('Enter coordinates for the first card: ')
                coord2 = raw_input('Enter coordinates for the second card: ')
                newCoord1 = map(int, coord1.strip().split())
                newCard1 = self._board[newCoord1[0]][newCoord1[1]].getValue()
                newCoord2 = map(int, coord2.strip().split())
                newCard2 = self._board[newCoord2[0]][newCoord2[1]].getValue()
    
                # Need to check that user has entered valid data here
    
                # newCoord1 = coord1.split(" ")
                # newCard1 = self._board[int(newCoord1[0])][int(newCoord1[1])].getValue()
                # newCoord2 = coord2.split(" ")
                # newCard2 = self._board[int(newCoord2[0])][int(newCoord2[1])].getValue()
                if newCard1 != newCard2:
                    print("Not an identical pair. Found", newCard1, "at", newCoord1, "and", newCard2, "at", newCoord2)
                else:
                    self._board[newCoord1[0]][newCoord1[1]].setFace()
                    self._board[newCoord2[0]][newCoord2[1]].setFace()
                    # self._board[int(newCoord1[0])][int(newCoord1[1])].setFace()
                    # self._board[int(newCoord2[0])][int(newCoord2[1])].setFace()
    
            print("Game Over")
            self.displayBoard()
    
        def isGameOver(self):
            for rows in range(self._rows):
                if not all(card.getFace() for card in self._board[rows]):
                    return False
                # for columns in range(self._columns):
                #     # If there is still one card facing down then
                #     # game is not over yet
                #     if self._board[rows][columns].getFace() == False:
                #         return False
            return True
    
    
    def getUserInput(input_type):
        while True:
            try:
                val = int(raw_input("Enter number of {}: ".format(input_type)))
                if 1 <= val <= 9:
                    return val
                else:
                    raise ValueError
            except ValueError:
                print ("    ***Number of {} must be between 1 and 9! Try again.***".format(input_type))
    
    
    def main():
    
        while True:
            # Force user to enter valid value for number of rows and columns
            rows = getUserInput("rows")
            columns = getUserInput("cols")
    
            if rows * columns % 2 == 0:
                break
            else:
                print ("    ***The value of rows X columns must be even. Try again.***")
    
        game = Game(rows, columns)
        game.play()
    
    if __name__ == "__main__":
        main()
    

