Diagonal wins
Diagonal sums are only updated when the move falls on the main diagonal (r == c) or anti-diagonal (r + c == 2). Corner cells affect both.
Two players take turns marking a 3×3 grid in a casual mobile game. Rather than scanning the entire board after every tap, the app tracks running signed counters — one per row, one per column, and one for each diagonal. Player A adds +1, Player B adds −1. If any counter reaches +3 or −3, that player wins immediately. After all moves, a full board with no winner is a draw; otherwise the game is still pending.
Maintain a score for each row, each column, and both diagonals. A's moves add +1; B's moves add −1. If any counter reaches +3 or −3, that player has completed a line and wins.
A move at (r, c) updates row[r] and col[c]. If r == c, it also updates the main diagonal. If r + c == 2, it updates the anti-diagonal. The center cell (1,1) sits on both diagonals.
Instead of scanning the board after each move, we maintain running sums for every row, column, and both diagonals. A sum of ±3 means a player owns an entire line.
Create rows[3], cols[3], mainDiag, and antiDiag, all initialized to zero.
Player A (even turns) scores +1. Player B (odd turns) scores −1.
For each move, add the score to the row, column, and diagonals (if applicable). If any counter reaches +3 or −3, that player wins.
After all moves: if no winner and 9 moves were played, it's a draw. Otherwise, it's pending.
Understanding boundary behavior is as important as the main algorithm path.
Diagonal sums are only updated when the move falls on the main diagonal (r == c) or anti-diagonal (r + c == 2). Corner cells affect both.
A draw requires exactly 9 moves with no winner. If fewer moves have been played and no winner exists, the game is still pending.
Time: O(n) — at most 9 moves, each updating O(1) counters.
Space: O(1) — six counters (3 rows + 3 columns + 2 diagonals).