#!/bin/python3

# ------------------------------------------------------------------------------
#
# Drof Computox tactic analysis
#
# ------------------------------------------------------------------------------


import argparse


# ------------------------------------------------------------------------------
# Globals

CS = "O"            # Computox square
PS = "X"            # Player square
ES = " "            # Empty square

# ------------------------------------------------------------------------------
# Square values

SA = 0
SB = 1
SC = 2
SD = 3
SE = 4
SF = 5
SG = 6
SH = 7
SJ = 8

# ------------------------------------------------------------------------------
# List of square names

squareNames = list("ABCDEFGHJ")

# ------------------------------------------------------------------------------
# Game result counts

computoxCount = 0
playerCount = 0
drawCount = 0
        

# ------------------------------------------------------------------------------
# Main function

def main():

    global tactic3, usedTactic3, tactic4, usedTactic4

    # Parse command line

    parser = argparse.ArgumentParser(description="""Script to assess which
        tactics are used by the Drof Computox.""")
    parser.add_argument("-b", "--beatable", action='store_true', 
        help="Computox is beatable")
    parser.add_argument("-c", "--computox", action='store_true', 
        help="Computox plays first")
    args = parser.parse_args()

    position = [ ES ] * 9
    moves = []
    
    if (args.beatable):
        tactic3 = tactic3s[0]
    else:
        tactic3 = tactic3s[1]
    
    usedTactic3 = [ False ] * int(len(tactic3) / 3)

    if (args.computox):
        tactic4 = tactic4s[0]
        usedTactic4 = [ False ] * len(tactic4)
        computoxMove(position, moves)
    else:
        tactic4 = tactic4s[1]
        usedTactic4 = [ False ] * len(tactic4)
        playerMove(position, moves)
    
    print()
    print("Tactic 1 used:", usedTactic1)
    print("Tactic 2 used:", usedTactic2)
    print("Tactic 3 used:", usedTactic3)
    print("Tactic 4 used:", usedTactic4)
    print("Computox win used:", usedComputoxWin)
    print("Player win used:", usedPlayerWin)
    print()
    print("Computox wins:", computoxCount)
    print("Player wins:", playerCount)
    print("Draws:", drawCount) 
    print()
        

# ------------------------------------------------------------------------------
# Play computox move 

def computoxMove(position, moves):

    global computoxCount, playerCount, drawCount

    positionNew = position.copy()
    movesNew = moves.copy()
    computoxStrategy(positionNew, movesNew)

    if (isWin(positionNew, CS)):
        reportResult("Computox win", positionNew, movesNew)
        computoxCount += 1
        return
        
    for square in range(9):
        if (positionNew[square] == ES):
            playerMove(positionNew, movesNew)
            return
            
    reportResult("Draw", positionNew, movesNew)
    drawCount += 1
        

# ------------------------------------------------------------------------------
# Apply Computox strategy

def computoxStrategy(position, moves):

    if (computoxTactic(position, tactic1, usedTactic1, CS, moves)):
        return

    if (computoxTactic(position, tactic2, usedTactic2, PS, moves)):
        return

    if (computoxTactic(position, tactic3, usedTactic3, PS, moves)):
        return

    for i in range(len(tactic4)):

        s1 = tactic4[i]
        if (position[s1] == ES):

            position[s1] = CS
            moves.append("o%s" % squareNames[s1])
            usedTactic4[i] = True
            return
        

# ------------------------------------------------------------------------------
# Try to use a Computox tactic   

def computoxTactic(position, tactic, foundTactic, testValue, moves):

    testCount = int(len(tactic) / 3)
    for i in range(testCount):

        j = i * 3
        s1 = tactic[j]
        s2 = tactic[j + 1]
        s3 = tactic[j + 2]

        if ((position[s1] == testValue) and (position[s2] == testValue)
            and (position[s3] == ES)):

            position[s3] = CS
            moves.append("o%s" % squareNames[s3])
            foundTactic[i] = True
            return True

    return False


# ------------------------------------------------------------------------------
# Play player move 

def playerMove(position, moves):

    global computoxCount, playerCount, drawCount

    found = False
    for square in range(9):

        if (position[square] == ES):

            found = True
            positionNew = position.copy()
            positionNew[square] = PS

            movesNew = moves.copy()
            movesNew.append("x%s" % squareNames[square])

            if (isWin(positionNew, PS)):
                reportResult("Player win", positionNew, movesNew)
                playerCount += 1
                continue

            computoxMove(positionNew, movesNew)

    if (not found):
        report(position, moves, "draw")
        drawCount += 1


# ------------------------------------------------------------------------------
# Is the current position a win for the specified player?

def isWin(position, player):

    for i in range(int(len(win) / 3)):

        j = i * 3
        p1 = win[j]
        p2 = win[j + 1]
        p3 = win[j + 2]

        if ((position[p1] == player) and (position[p2] == player) 
            and (position[p3] == player)):
            
            if (player == CS):
                usedComputoxWin[i] = True
            else:
                usedPlayerWin[i] = True
                
            return True

    return False

        
# ------------------------------------------------------------------------------
# Report game result

def reportResult(result, board, moves):

    print("%-12s  " % result, end=" ")
    
    for r in range(3):
        
        print("  ", end="")
        
        for c in range(3):
            print(board[r * 3 + c], end="")
        
    print("   ", end="")

    for m in moves:
        print(" ", m, end="")
    
    print()    

################################################################################
# Computox strategies  

tactic1 = [
    SE, SJ, SA,     # Computox start - unused (Computox plays A on move 1)
    SA, SC, SB,
    SE, SH, SB,     # Computox start - unused
    SA, SB, SC,     # Computox start - unused
    SE, SG, SC,     # Computox start - unused
    SE, SF, SD,     # Computox start - unused 
    SA, SG, SD,
    SA, SJ, SE,     # Player start   - unused (Computox plays E on move 1)
    SC, SG, SE,     # Player start   - unused (Computox plays E on move 1)
    SB, SH, SE,     # Either start   - unused (Computox plays E on move 1)  
    SA, SD, SG,
    SC, SE, SG,
    SH, SJ, SG,     # Either start   - unused
    SD, SE, SF,     # Computox start - unused  
    SC, SJ, SF,
    SB, SE, SH,     # Computox start - unused 
    SG, SJ, SH,
    SC, SF, SJ,
    SA, SE, SJ,
    SH, SG, SJ      # Computox start - unused 
]
usedTactic1 = [ False ] * int(len(tactic1) / 3)

tactic2 = [
    SA, SC, SB,     # Computox start - unused (Computox plays A on move 1)
    SE, SH, SB,     # Computox start - unused
    SA, SB, SC,     # Computox start - unused (Computox plays A on move 1)
    SF, SJ, SC,     # Computox start - unused
    SE, SG, SC,     # Computox start - unused
    SE, SF, SD,      
    SA, SG, SD,     # Computox start - unused (Computox plays A on move 1)
    SB, SH, SE,     # Player start   - unused (Computox plays E on move 1)
    SD, SE, SF,
    SC, SJ, SF,     # Computox start - unused
    SA, SD, SG,     # Computox start - unused (Computox plays A on move 1)
    SC, SE, SG,
    SH, SJ, SG,     # Computox start - unused
    SB, SE, SH,
    SG, SJ, SH,     # Computox start - unused
    SC, SF, SJ,     # Computox start - unused
    SG, SH, SJ      # Computox start - unused
]
usedTactic2 = [ False ] * int(len(tactic2) / 3)

tactic3s = [ 
    [ 
        SB, SF, SE,     # Player start   - unused (Computox plays E on move 1)
    ], [
        SF, SH, SJ,     # Computox start - unused when unbeatable
        SC, SH, SJ,     # Computox start - unused when unbeatable
        SF, SG, SJ,     
        SA, SJ, SH,     # Computox start - unused (Computox plays A on move 1)
        SC, SG, SH,     # Computox start - unused
        SB, SF, SE      # Player start   - unused (Computox plays E on move 1)
    ]
]
tactic3 = None
usedTactic3 = None

tactic4s = [ 
    [ 
        SA, SC, SJ, SG, 
        SB,         # Computox start - unused when beatable
        SH,         # Computox start - unused
        SD          # Computox start - unused when beatable
    ], [ 
        SE, SA, SJ, SC, SG, SB, 
        SH,         # Player start   - unused
        SD 
    ] 
]
tactic4 = None
usedTactic4 = None

win = [
    SE, SC, SG,
    SE, SA, SJ,
    SE, SD, SF,     # Computox start - unused
    SE, SH, SB,     # Computox start - unused, possible player win 
    SA, SC, SB,
    SA, SD, SG,
    SJ, SH, SG,     # Player start   - possible player win
    SJ, SC, SF
]
usedComputoxWin = [ False ] * int(len(win) / 3)
usedPlayerWin = usedComputoxWin.copy()

main()
