2

I am trying to create a game (tic tac toe) and I have to create a board (called tab) using 3 tuples that each has 3 elements that represent a position on a line. A "X" is represented by the number 1, a "O" by -1 and an empty space by 0. I am trying to create a function that receives an argument (in this case the board is the argument) and says if it represents a valid board or not, however it always gives me the wrong answer (in this case says it's false) and I don't know why.

tab = ((1, -1, 0), (0, 0, 1), (0, -1, 1))

def eh_tabuleiro(tab):
    if len(tab) == 3:
        if len(tab[0]) == 3 and len(tab[1]) == 3 and len(tab[2]) == 3:
            if tab[0][0] or tab[0][1] or tab[0][2] or tab[1][0] or tab[1][1] or tab[1][2] or tab[2][0] or tab[2][1] or tab[2][2] != 1 or -1 or 0:
                return False
            else:
                return True           
            
        else:
            return False
    else:
        return False  

For a board to be valid it needs to be a tuple with three tuples and 3 elements inside each smaller tuple. If it has 2 elements or instead of 1/-1/0 has a "-1" or any other thing the function returns False. As you can see my board is correct and it says it is not. Can anyone help me?

Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
Pedro
  • 143
  • 8
  • You're almost there. The `or` expression is wrong. Do 2 for loops, one for the rows, other nested for the columns, and check if the current position is different from 1, -1 or 0. – Niloct Nov 18 '20 at 15:15
  • That big `if` doesn't evaluate as you want it to. A more Pythonic way to express that condition is: `if not all(tab[i][j] in (1, -1, 0) for i in range(3) for j in range(3))` – Tomerikoo Nov 18 '20 at 15:31

2 Answers2

1

The problem is with the long chain of or statements. Compare the following:

if 1 or 2 == 3:  # Python reads this as `if 1 or (2 == 3):`
    print('oops')

# prints 'oops'
if (1 == 3) or (2 == 3):
    print('oops')

# does not print

Suggestion for a more readable implementation:

def is_valid(tab):
    if not isinstance(tab, tuple):
        return False

    if len(tab) != 3:
        return False

    for row in tab:
        if not isinstance(row, tuple):
            return False

        if len(row) != 3:
            return False
        
        for element in row:
             if element not in (-1, 0, 1):
                 return False

    return True
peter554
  • 1,248
  • 1
  • 12
  • 24
1

Do not try to invent a new syntax. It does not matter that you (or I) can guess what is expected, what matter is what Python understand.

This line:

if tab[0][0] or tab[0][1] or tab[0][2] or tab[1][0] or tab[1][1] or tab[1][2] or tab[2][0] or tab[2][1] or tab[2][2] != 1 or -1 or 0:

will return True as soon as one of the elements between or is True, and the integer values 1 or -1 give True in a boolean context.

What you want is to know whether the set produced by all values is a subset of (0, 1, -1). Just test that instead:

...
if (set(tab[0]) | set(tab[1]) | set(tab[2])).issubset({1, 0, -1}):
    return True
else:
    return False
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252