How to check for win in custom sized tic-tac-toe d

2019-08-17 17:44发布

问题:

I'm making a simple tic tac toe game, where user can specify the size of the grid (amount of columns and rows).
I need to create a function, that could check for a win in all the diagonals in the grid.

For the grid, I'm using a 2-dimensional list, that looks like this (3x3 example):

grid = [['x', '-', 'o'], 
        ['o', 'x', '-'], 
        ['-', '-', 'x']]
grid[row][col]

This should be a winning situation

I have already created a check for the vertical and horizontal win, but I can't quite figure out, how to check for the diagonals.

Here is how I check for row win in my code:

min_win_streak is the minimum winning streak (for example in classical 3x3 tic-tac-toe, it would be 3)

def check_rows(grid, min_win_streak):
    winner = '-'
    for row in grid:
        win_streak = 0
        for element in row:
            if element != '-':
                if element == winner:
                    win_streak += 1
                    winner = element
                    if win_streak >= min_win_streak:
                        return True, winner
                else:
                    win_streak = 1
                    winner = element
            else:
                win_streak = 0
                winner = '-'
    return False, None



I need the check_diags() function, the returns should be:

  • win for x, the function should return True, 'x'
  • win for o, the function should return True, 'x'
  • no win, the function should return False, None

回答1:

You can check for diagonals in a 2x2 using the following nested for loops:

for i in range(len(grid)-2):
    for j in range(len(grid)-2):
        if grid[i][j] == grid[i+1][j+1] == grid[i+2][j+2] and grid[i][j] != '-':
            print('Winner')
        elif grid[i][j+2] == grid[i+1][j+1] == grid[i+2][j] and grid[i][j+2] != '-':
            print('Winner')

Insert this into a function with the desired returns in place of the print statements if you desire. This should be extendable to 3x3, 4x4, etc. with fairly easy alterations.



回答2:

Thanks for posting your code. I replaced your win_streak check loop with the all function. The code below does more work than you'd want to use for a huge grid, but it's easy (easier) to understand and adapt, and it's fast enough to use for a game of go-moku (5 in a row on a 19x19 board).

I left in one tracing print statement to illustrate the diagonals it's checking. You should be able to adapt this to the NE-SW diagonals (check_slash_diag).

grid = [['x', '-', 'o', 'o'],
        ['o', 'x', 'o', '-'],
        ['-', 'o', 'x', 'x'],
        ['-', 'x', 'o', '-']]

def check_backslash_diag(grid, min_win_streak):

    grid_size = len(grid)
    grid_extra = grid_size - min_win_streak   # This is the "extra" space in a long line

    # This pair of loops will iterate through the upper-left square of side 
    #   grid_extra+1, starting points of any diagonals long enough to contain a win.
    for start_row in range(grid_extra+1):
        for start_col in range(grid_extra+1):
            # Extract a diagonal "row" of length min_win_streak
            diag = [grid[start_row+i][start_col+i] for i in range(min_win_streak)]
            print(start_row, start_col, diag)  # DEBUG: Display checked diagonals
            if all(diag[i] == diag[0] for i in range(min_win_streak)):
                print(diag[0], "wins on NW-SE diagonal at", start_row, start_col)

check_backslash_diag(grid, 3)

Output:

0 0 ['x', 'x', 'x']
x wins on NW-SE diagonal at 0 0
0 1 ['-', 'o', 'x']
1 0 ['o', 'o', 'o']
o wins on NW-SE diagonal at 1 0
1 1 ['x', 'x', '-']