<p>Given a Tic-Tac-Toe board as a string array <code>board</code>, return <code>true</code> if and only if it is possible to reach this board position during the course of a valid tic-tac-toe game.</p>

<p>The board is a <code>3 x 3</code> array that consists of characters <code>&#39; &#39;</code>, <code>&#39;X&#39;</code>, and <code>&#39;O&#39;</code>. The <code>&#39; &#39;</code> character represents an empty square.</p>

<p>Here are the rules of Tic-Tac-Toe:</p>

<ul>
	<li>Players take turns placing characters into empty squares <code>&#39; &#39;</code>.</li>
	<li>The first player always places <code>&#39;X&#39;</code> characters, while the second player always places <code>&#39;O&#39;</code> characters.</li>
	<li><code>&#39;X&#39;</code> and <code>&#39;O&#39;</code> characters are always placed into empty squares, never filled ones.</li>
	<li>The game ends when there are three of the same (non-empty) character filling any row, column, or diagonal.</li>
	<li>The game also ends if all squares are non-empty.</li>
	<li>No more moves can be played if the game is over.</li>
</ul>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2021/05/15/tictactoe1-grid.jpg" style="width: 253px; height: 253px;" />
<pre>
<strong>Input:</strong> board = [&quot;O  &quot;,&quot;   &quot;,&quot;   &quot;]
<strong>Output:</strong> false
<strong>Explanation:</strong> The first player always plays &quot;X&quot;.
</pre>

<p><strong class="example">Example 2:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2021/05/15/tictactoe2-grid.jpg" style="width: 253px; height: 253px;" />
<pre>
<strong>Input:</strong> board = [&quot;XOX&quot;,&quot; X &quot;,&quot;   &quot;]
<strong>Output:</strong> false
<strong>Explanation:</strong> Players take turns making moves.
</pre>

<p><strong class="example">Example 3:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2021/05/15/tictactoe4-grid.jpg" style="width: 253px; height: 253px;" />
<pre>
<strong>Input:</strong> board = [&quot;XOX&quot;,&quot;O O&quot;,&quot;XOX&quot;]
<strong>Output:</strong> true
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>board.length == 3</code></li>
	<li><code>board[i].length == 3</code></li>
	<li><code>board[i][j]</code> is either <code>&#39;X&#39;</code>, <code>&#39;O&#39;</code>, or <code>&#39; &#39;</code>.</li>
</ul>

class Solution:  
    def validTicTacToe(self, board: List[str]) -> bool:
        # Valid amount of chars

        OCount = XCount = 0
        O, X = "O", "X"
        charIdx = {X:1, O:0}
        diagonal_wins = [0,0]
        vertical_wins = [0,0]
        horizontal_wins = [0,0]

        for line in board:
            for c in line: 
                if c == X: XCount += 1
                elif c == O: OCount += 1
                else: continue
        if abs(XCount - OCount) > 1 or XCount < OCount: return False
        if not XCount and not OCount: return True

        # Valid start
        if XCount == 0 and O: return False

        def horizontal_win(idx):
            return len(set(board[idx])) == 1 and board[idx][0] in "OX"

        def vertical_win(idx):
            return board[0][idx] == board[1][idx] and board[1][idx] == board[2][idx] and board[2][idx] in "OX"

        def diagonal_win():
            return board[0][0] == board[1][1] and board[2][2] == board[1][1] and board[1][1] in "OX"

        def inverted_diagonal_win():
            return board[0][2] == board[1][1] and board[2][0] == board[1][1] and board[1][1] in "OX"

        def different_players_win(wins):
            return all(win > 0 for win in wins)
        
        def player_won_twice(wins):
            return any(win > 1 for win in wins)

        def first_player_win_and_count_dont_match(wins):
            return wins[charIdx[X]] != 0 and not XCount > OCount

        def check_horizontal_win(idx):
            if horizontal_win(idx): 
                letterIdx = charIdx[board[idx][0]]
                horizontal_wins[letterIdx] += 1

        def check_vertical_win(idx):
            if vertical_win(idx): 
                letterIdx = charIdx[board[0][idx]]
                vertical_wins[letterIdx]+=1

        # Horizontal wins
        for idx in range(3):
            check_horizontal_win(idx)            
            check_vertical_win(idx)
        
        if different_players_win(horizontal_wins) or player_won_twice(horizontal_wins):  return False        
        if first_player_win_and_count_dont_match(horizontal_wins): return False
        if different_players_win(vertical_wins) or player_won_twice(vertical_wins):  return False
        if first_player_win_and_count_dont_match(vertical_wins):  return False

        # Diagonal wins
        if diagonal_win(): diagonal_wins[charIdx[board[1][1]]]+=1
        if inverted_diagonal_win(): diagonal_wins[charIdx[board[1][1]]]+=1
        if diagonal_wins[charIdx[X]] != 0 and XCount <= OCount: return False

        all_wins_arrays = [ horizontal_wins, vertical_wins, diagonal_wins ]

        total_wins = [0,0]
        total_wins[charIdx[O]] = sum(win[charIdx[O]] for win in all_wins_arrays)
        total_wins[charIdx[X]] = sum(win[charIdx[X]] for win in all_wins_arrays)

        if XCount > OCount and total_wins[charIdx[O]] != 0: return False

        return True
28