Strange: (A -or B) doesn't deliver same result as (B -or A)

My code:

enum GameStatus{
        WIN
        ONGOING
        DRAW
}
    
Function Get-StateOfTicTacToe() {
    <#
    .SYNOPSIS
    Implement a program that determines the state of a tic-tac-toe game.

    .DESCRIPTION
    The games is played on a 3×3 grid represent by an array of 3 strings.
    Players take turns to place `X`s and `O`s on the grid.
    The game ends:
    - when one player has won by placing three of marks in a row, column, or along a diagonal of the grid
    - when the entire grid is filled up

    In this exercise, we will assume that `X` always starts first.

    .PARAMETER Board
    An array of 3 strings represeting the board in the form of 3x3 grid.

    .EXAMPLE
    $board = @(
        "XXO",
        "X  ",
        "X  "
    )
    Get-StateOfTicTacToe -Board $board
    Returns: [GameStatus]::WIN
    #>
    [CmdletBinding()]
    Param(
        [string[]]$Board
    )

    function CheckTurnOrder {
        $xCount = 0
        $oCount = 0

        foreach ($row in $Board) {
            foreach ($char in $row.ToCharArray()) {
                if ($char -eq 'X') {
                    $xCount++
                } elseif ($char -eq 'O') {
                    $oCount++
                }  
            }
        }

        if ($oCount -gt $xCount) {
            throw "Wrong turn order: O started"
        }

        if ($xCount - $oCount -eq 2) {
            throw "Wrong turn order: X went twice"
        }

        if ($oCount - $xCount -eq 2) {
            throw "Wrong turn order: O went twice"
        }
    }

    function CheckWin($Player) {
        if ($Player -ne 'X' -and $Player -ne 'O') {
            throw "error"
        }

        # Rows and columns
        for ($i = 0; $i -lt 3; $i++) {
            if (($Board[$i][0] -eq $Player) -and
                ($Board[$i][1] -eq $Player) -and
                ($Board[$i][2] -eq $Player)) {
                    return $true
            }

            if (($Board[0][$i] -eq $Player) -and
                ($Board[1][$i] -eq $Player) -and
                ($Board[2][$i] -eq $Player)) {
                    return $true
            }
        }

        # Diagonals
        if (($Board[0][0] -eq $Player) -and
            ($Board[1][1] -eq $Player) -and
            ($Board[2][2] -eq $Player)) {
                return $true
        }

        if (($Board[0][2] -eq $Player) -and
            ($Board[1][1] -eq $Player) -and
            ($Board[2][0] -eq $Player)) {
                return $true
        }

        return $false
    } 

    # Continued playing after win
    if (CheckWin('O') -and CheckWin('X')) {
        throw "Impossible board: game should have ended after the game was won"
    }

    CheckTurnOrder

    Write-Host "CheckWin('X') = $(CheckWin 'X')"
    Write-Host "CheckWin('O') = $(CheckWin 'O')"

    Write-Host "CheckWin('O') -or CheckWin('X') = $((CheckWin 'O') -or (CheckWin 'X'))"
    Write-Host "CheckWin('X') -or CheckWin('O') = $((CheckWin 'X') -or (CheckWin 'O'))"

    if (CheckWin('O') -or CheckWin('X')) {
        Write-Host "CASE1"
        return [GameStatus]::WIN
    }

    if (CheckWin('X') -or CheckWin('O')) {
        Write-Host "CASE2"
        return [GameStatus]::WIN
    }

    return [GameStatus]::ONGOING
}

$grid = @("XOO",
          "X  ",
          "X  ")
$got  = Get-StateOfTicTacToe -Board $grid
echo $got

The output:

CheckWin('X') = True
CheckWin('O') = False
CheckWin('O') -or CheckWin('X') = True
CheckWin('X') -or CheckWin('O') = True
CASE2
WIN

(CheckWin 'X') -or (CheckWin 'O') and (CheckWin 'O') -or (CheckWin 'X') should be logically equivalent, but why CASE1 is not reached?

Unlike most languages, the parameters of a function call should not be in parentheses. I think if you use (CheckWin 'X') -or (CheckWin 'O') instead of CheckWin('X') -or CheckWin('O'), you’ll get the result you expect.

Maybe someone with more experience in this language can provide a good explanation as to what is going on.

1 Like