# TicTacToe Version 6
# Checks for a winner and draws the line.

from zellegraphics import *
import time

# Default values for global constants
BOARDSIZE  = 3                   # number of rows and columns
BOARDRANGE = range(BOARDSIZE)    # range of rows and columns
PPS        = 150                 # pixels per square
WINDOWSIZE = PPS * BOARDSIZE     # width and height of window
INSET      = 15                  # num white pixels around X's and O's in squares
win        = None                # Everything is displayed in this window, initialized in main()

# Constants for who is occupying a board position
EMPTY   = -1
# XFILLED = 0  (but these never need to be explicitly used)
# OFILLED = 1

def drawGrid():
    for i in range (1, BOARDSIZE):
        Line(Point(0, i*PPS), Point(WINDOWSIZE, i*PPS)).draw(win)
        Line(Point(i*PPS, 0), Point(i*PPS, WINDOWSIZE)).draw(win)

# ---- Functions to get various locations within the squares

def rectCenter(row, col):
    'coordinates of center of square'
    return Point(PPS*col +PPS/2, PPS*row + PPS/2)

def rectUpperLeft(row, col):
    'coordinates of top left of inset X or O'
    return Point(PPS*col + INSET, PPS*row + INSET)

def rectLowerRight(row, col):
    'coordinates of bottom right of inset X or O'
    return Point(PPS*(col+1) - INSET, PPS*(row+1) - INSET)

def rectUpperRight(row, col):
    'coordinates of top right of inset X or O'
    return Point(PPS*(col+1) - INSET, PPS*row + INSET)

def rectLowerLeft(row, col):
    'coordinates of bottom left of inset X or O'
    return Point(PPS*col + INSET, PPS*(row+1) - INSET)

# ----- Functions to draw an X and an O in a particular square.

def drawX(row, col):
    'Draw an X in the given square'
    Line(rectUpperLeft(row, col), rectLowerRight(row, col)).draw(win)
    Line(rectLowerLeft(row, col), rectUpperRight(row, col)).draw(win)

def drawO(row, col):
    'Draw an O in the given square'
    Circle(rectCenter(row, col), PPS/2-INSET).draw(win);

drawList = [drawX, drawO] # makes it possible to use '% 2' in main() instead of if.

# ----- Coordinate conversion.                 
def boardCoord(pixelCoord):
    'Find out row or colum number that corresponds to this pixel coordinate'
    return pixelCoord // PPS;


# ----- Functions to test for a Winning move.  If so, returns the endpoints of the line to be drawn.

def checkWinner(row, col):
    'Check to see if the latest move resulted in a win'
    xo = squareState[row][col]
    if checkRow(row, xo):
        return [rectUpperLeft(row, 0), rectLowerRight(row, BOARDSIZE - 1)]
    if checkCol(col, xo):
        return [rectUpperLeft(0, col), rectLowerRight(BOARDSIZE - 1, col)]
    if row == col and checkMainDiagonal(xo):
        return [rectUpperLeft(0, 0), rectLowerRight(BOARDSIZE - 1, BOARDSIZE - 1)]
    if row + col == BOARDSIZE-1 and checkOtherDiagonal(xo):
        return [rectUpperRight(0, BOARDSIZE - 1), rectLowerLeft(BOARDSIZE - 1, 0)]
    return False

def checkRow(row, xo):
    return checkGeneral(row, 0, 0, 1, xo)
def checkCol(col, xo):
    return checkGeneral(0, col, 1, 0, xo)
def checkMainDiagonal(xo):
    return checkGeneral(0, 0, 1, 1, xo);
def checkOtherDiagonal(xo):
    return checkGeneral(0, BOARDSIZE-1, 1, -1, xo)

def checkGeneral(row, col, rowIncrement, colIncrement, xo):
    for i in BOARDRANGE:
        if squareState[row][col] != xo:
            return False
        row += rowIncrement
        col += colIncrement
    return True

    
def main():
    global win, BOARDSIZE, BOARDRANGE, WINDOWSIZE, squareState
    
    # First ask for boardsize and set the global parameters
    userSize = raw_input('Enter board size (Press Enter for 3): ')
    if userSize != '':
        BOARDSIZE  = eval(userSize)    
        BOARDRANGE = range(BOARDSIZE)
        WINDOWSIZE = PPS * BOARDSIZE     # width and height of window
    win = GraphWin("TicTacToe version 6", WINDOWSIZE, WINDOWSIZE)

    # initialize the board state with all empty spaces
    squareState = [[EMPTY for j in BOARDRANGE] for i in BOARDRANGE]

    drawGrid()
    turnCount = 0
   

    while turnCount < BOARDSIZE * BOARDSIZE:
        clickPoint = win.getMouse()
        row, col = boardCoord(clickPoint.getY()), boardCoord(clickPoint.getX())
        if squareState[row][col] == EMPTY: # if already filled, do nothing.
            drawList[turnCount%2](row, col)
            squareState[row][col] = turnCount%2
            turnCount = turnCount + 1
            winner = checkWinner(row, col)
            if winner:
                winLine = apply(Line,winner);
                winLine.setOutline('red')
                winLine.setWidth(4)
                winLine.move(6,0)
                winLine.draw(win)
                break
 
    time.sleep(3)
    win.close()

main()