2

sorry if this is really basic! i'm in first year computer science.

i am trying to write a function to check if there is a win on a tictactoe board of NxN size (so i can't hardcode any values); the win has to be from the top left, to the bottom right.

i've already written a function for the upwards diagonal, so i'ved based it around that, but with a list like this: [ [ 'X' , ' ' ] , [ ' ' , ' ' ] ] the function returns True - which it definitely should not.

here's what i have right now, but i have tried many things:

#these can be anything but here's just an example of what i'm using to test
cur = [['X',' '],[' ',' ']] 
player= 'X'

def check_down_diag(cur, player):
  columncount = 0

  for row in cur:
    if row[columncount] != player:
      columncount += 1
      return False
    else:
      return True
spaced
  • 21
  • 2
  • 1
    You're returning True after exactly one comparison. Walk through the code line by line in your head or on paper. – Jonathon Reinhart Nov 15 '21 at 21:21
  • i've been looking and tinkering since you've said this, i understand that but i cannot wrap my head around how to fix it right now. It feels like no matter whati try,the for loop is only running for one row? – spaced Nov 15 '21 at 21:57
  • _"the for loop is only running for one row"_ Because (like Jonathon said), you `return True` after exactly one comparison.. You want to `return True` _only after you've checked all rows!_ [How to debug small programs.](//ericlippert.com/2014/03/05/how-to-debug-small-programs/) | [What is a debugger and how can it help me diagnose problems?](//stackoverflow.com/q/25385173/843953) – Pranav Hosangadi Nov 15 '21 at 23:04

3 Answers3

0

The first step to figure out is the logic. You have a player symbol (here 'X') and a Tic-Tac-Toe size ('N', usually 3 for TTT). So to see if there is a diagonal winner, you would check the two diagonals:

(0, 0), (1, 1), (2, 2), ... (N-1, N-1)

and:

(N-1, 0), (N-2, 1), (N-3, 2) ... (0, N-1)

which are the indeces into the fields to check.

So now you know the two sets of locations to check, and you know which symbol to check for. So write a function which accepts an N for size/dimension and a symbol for which player, and you should be good to go. You can check for both diagonals in one loop, or you can check them in separate loops to start. If you do one loop, you must go through the whole loop once until both checks fail. If you do one loop/diagonal at a time, you should break from the loop as soon as you find a single failure condition, to improve performance.

GaryMBloom
  • 5,350
  • 1
  • 24
  • 32
0

A while back I wrote a function for pattern finding in 2d arrays specifically for something like this:

def find_pattern(array, pattern, value):
    for row in range(len(array)):
        for column in range(len(array[0])):
            try:
                for y, x in pattern:
                    _value = array[y + row][x + column]
                    if value != _value:
                        break
                else:
                    return pattern, (pattern[0][0] + row, pattern[0][1] + column)
            except IndexError:
                break
    return None

The patterns are formed like so (these specific ones are for the standard tic tac toe board (all win conditions)):

win_patterns = [
    ((0, 0), (0, 1), (0, 2)),
    ((0, 0), (1, 0), (2, 0)),
    ((0, 0), (1, 1), (2, 2)),
    ((0, 2), (1, 1), (2, 0)),
]

The way it works is simple, it is just a tuple of (x, y) coordinates in the grid, starting from 0, so the first pattern would search for straight lines horizontally, second for vertical lines, third and fourth for both diagonals.

Then you can loop over the patterns, pass them to the function along with the 2d array of the board and the value that has to be found in this pattern (' ' values don't mean anything they are there so that the array is more readable):

board = [
    ['x', ' ', 'x', ' ', ' '],
    [' ', 'x', ' ', ' ', ' '],
    [' ', ' ', 'x', ' ', 'x'],
    [' ', ' ', ' ', ' ', ' '],
    [' ', ' ', 'x', ' ', ' '],
]

for pattern in win_patterns:
    found = find_pattern(board, pattern, 'x')
    if found:
        print(found)
        break
Matiiss
  • 5,970
  • 2
  • 12
  • 29
0

For the main diagonal, check that all the values that are at the same row and column (i.e. the main diagonal) are equal to the player's symbol:

def check_down_diag1(cur, player):
    return all( cur[i][i]==player for i in range(len(cur)) )

For the other diagonal, simply invert one of the dimensions:

def check_down_diag2(cur, player):
    return all( cur[i][-1-i]==player for i in range(len(cur)) )

You could also check both diagonals at the same time:

def check_down_diags(cur, player):
    return all( cur[i][i]==player for i in range(len(cur)) ) \
        or all( cur[i][-1-i]==player for i in range(len(cur)) )
Alain T.
  • 40,517
  • 4
  • 31
  • 51