Reputation: 6796
The initial problem: for a given 3x3 tic tac toe board check if one of the players has won.
The simplest solution I have come up so far is rotating the matrix and summing up each row:
board
[[0, 1, 2], [3, 4, 5], [6, 7, 8]]
pr(board)
0 1 2
3 4 5
6 7 8
pr(zip(*board))
0 3 6
1 4 7
2 5 8
0..9 numbers above are just for showing positions on the board, normally they would be filled with 1 for player 1 and -1 for player 2 and 0 for unfilled position. Go row by row and if it sums up to 3 or -3 this is the winning block.
However, diagonals are not checked. Is there some way to extract diagonals from such matrix in elegant + highly performant way? I don't mean using trivial indexes "manually" (0, 1, 2), but rather get diagonal of n x n matrix.
P.S. pr is just a helper function for printing 2d list:
def pr(x):
for row in x:
print ' '.join(map(str, row))
Upvotes: 4
Views: 14049
Reputation: 1
tmp_diagonals = [set(), set()]
num = 0
for idx in range(len(board) - 1, -1, -1):
tmp_diagonals[0].add(board[num][num])
tmp_diagonals[1].add(board[num][idx])
num += 1
Upvotes: -1
Reputation: 123541
The diagonals on a square board lie either where the indices are equal, so for a 3x3 board they are
board[0][0]
, board[1][1]
, and board[2][2]
or where the two sum to the board size-1 (3 places in this case): such as board[0][2]
, board[1][1]
, and board[2][0]
-- notice that board[1][1]
is included in both sets, as it should be. These facts makes it fairly easy to write Python code to compute them:
board = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
BOARD_SIZE = len(board)
diags1 = [board[i][i] for i in xrange(BOARD_SIZE)]
diags2 = [board[i][BOARD_SIZE-1-i] for i in xrange(BOARD_SIZE)]
print diags1
print diags2
Output:
[0, 4, 8]
[2, 4, 6]
Upvotes: 2
Reputation: 1903
Number your game field with a magic square
2|9|4
7|5|3
6|1|8
Now sum up after three moves and check if the sum is 15 --> Winner. You have to check this for every player. Surely you have to recheck after 4th move and 5th move (only the player that started the game)
This is how I solved this problem in my first Java class.
Upvotes: 4
Reputation: 1134
This will give you a list containing the diagonal elements of one direction (top left to bottom right):
[board[i][i] for i in range(len(board))]
This will do the same for the opposite direction:
[board[i][len(board)-i-1] for i in range(len(board))]
Upvotes: 1
Reputation: 78630
You can get one diagonal with:
[r[i] for i, r in enumerate(board)]
# [0, 4, 8]
And the opposite diagonal with:
[r[-i-1] for i, r in enumerate(board)]
# [2, 4, 6]
Upvotes: 12
Reputation: 10891
Probably what you need is in numpy
, see Get all the diagonals in a matrix/list of lists in Python. Maybe you can use this, and flip it like you did to get the other solution.
if sum(board[i][i] for i in (0, 1, 2)) in (-3, 3):
true
Upvotes: 2