I've created a Noughts and Crosses game in Python using pygame, and I'm quite pleased with the result that I've produced. I've managed to reduce the code to what it is now, as it used to be much longer, and I'd like to submit it here for review. I know that it's common practice to not have more than 79 characters on any one line, but I'm not too bothered about this. I don't know what sort of things could possibly be done to improve the code further, or to correct any other things that I've done that go against the PEP 8 style guide.import os, sys, pygame, classes.sprite #Imports the necessary modules as well a custom sprite classfrom pygame.locals import *pygame.init() #Initialises the pygame modulepath, fname = os.path.split(__file__)path        = os.path.join(path, 'data') #Defines the path that stores all of the data (Images)#Define some constantsWIDTH  = 800HEIGHT = 600SCREEN = pygame.display.set_mode((WIDTH,HEIGHT))CLOCK  = pygame.time.Clock()FPS    = 30FONT   = 'LovelyK'ICON   = pygame.transform.scale(pygame.image.load(os.path.join(path, 'icon.png')).convert_alpha(), (32, 32))tick   = 0#Initialise the custom sprite moduleclasses.sprite.init(SCREEN, FPS)#Sets the game's icon and caption    pygame.display.set_icon(ICON)pygame.display.set_caption('Noughts and Crosses')#Some variables needed for the gameturn = 0wins = [0, 0]grid = [0, 0, 0,        0, 0, 0,        0, 0, 0]winning_lines = [[0, 1, 2], [3, 4, 5], [6, 7, 8],                 [0, 3, 6], [1, 4, 7], [2, 5, 8],                 [0, 4, 8], [2, 4, 6]]p1_colour, p2_colour = (237,  28,  36), ( 62,  72, 204)def print_to_screen(text, position = (0, 0), centered = False, size =  30, colour = (255, 255, 255), font = 'Courier New'):    '''Prints text to the screen'''    FONT = pygame.font.SysFont(font, size)    label = FONT.render(str(text), 1, colour)    if centered == True:        position = label.get_rect(center = position)    SCREEN.blit(label, position)def Quit():    '''Shuts down the game if it's closed'''    for event in pygame.event.get():        if event.type == QUIT:            print('Quit the game...')            pygame.quit()            sys.exit()        if event.type == KEYDOWN:            if event.key == K_ESCAPE:                print('Quit the game...')                pygame.quit()                sys.exit()def wait(seconds):    '''Pauses the program for the specified amout of time'''    for i in range(int(seconds * FPS)):        Quit()        pygame.display.update()        CLOCK.tick(FPS)def reset_grid():    '''Resets the playing grid'''    global grid    grid = [0, 0, 0,            0, 0, 0,            0, 0, 0]def test_for_win():    '''Tests to see if one of the players has won'''    global grid    for i in winning_lines:        if grid[i[0]] == grid[i[1]] == grid[i[2]]:            if grid[i[0]] == 0: continue            elif grid[i[0]] == 'X':                print_to_screen('Winner!', ( 15, 450), False, 80, p1_colour, FONT)                wins[0] += 1            elif grid[i[0]] == 'O':                print_to_screen('Winner!', (570, 450), False, 80, p2_colour, FONT)                wins[1] += 1            wait(2)            reset_grid()def test_for_draw():    '''Tests to see if the game results in a tie'''    global grid    finish = 0    for i in grid:        if i == 0: finish += 1    if finish == 0:        print_to_screen('It\'s a draw!', (400, 550), True, 100, OLIVE, FONT)        wait(2)        reset_grid()def main():    global turn, grid, wins    clicked = False #Used to stop holding the mouse down from affecting the program    #Create the game board using the custom sprite class    boards = [classes.sprite.Sprite(x = x, y = y) for x, y in [[250, 200], [350, 200], [450, 200],                                                               [250, 300], [350, 300], [450, 300],                                                               [250, 400], [350, 400], [450, 400]]]    #Set the image to be shown for each tile (image size: 100px, 100px)    for board in boards: board.set_image('board.png')    #Custom sprite group class, allow all the sprites to be rendered in one method    board_group = classes.sprite.SpriteGroup(boards)    #Creates instance of the sprite class to show the logo    logo = classes.sprite.Sprite(100, 20)    logo.set_image('logo.png')    while True: #Main loop        SCREEN.fill(MAROON)        #Closes the game if the 'X' is clicked or is ESC is pressed        Quit()        #Changes the colour of the lettering depending on the turn        if turn == 0:            p1_colour = (237,  28,  36)            p2_colour = ( 36,  44, 134)        else:            p1_colour = (157,  13,  20)            p2_colour = ( 62,  72, 204)        #Updates the image of a tile if the mouse hovers over it        i = 0        for board in boards:            if board.mouse_hover() and grid[i] == 0:                if   turn == 0: board.set_image('cross.png')                elif turn == 1: board.set_image('nought.png')            else:                if grid[i] == 0:  board.set_image('board.png')            i += 1        #Updates grid with player's turn when tile is clicked        if pygame.mouse.get_pressed()[0]:            if clicked == False:                clicked = True                i = 0                for board in boards:                    if board.mouse_click() and grid[i] == 0:                        if  turn == 0:                            board.set_image('cross.png')                            grid[i] = 'X'                            turn = 1                        elif turn == 1:                            board.set_image('nought.png')                            grid[i] = 'O'                            turn = 0                    i += 1        else: clicked = False        #Prints whose turn it is and scores to the screen        print_to_screen('P1', ( 40, 200), False, 250, p1_colour, FONT)        print_to_screen('P2', (570, 200), False, 250, p2_colour, FONT)        print_to_screen(wins[0], (110, 550), True, 100, p1_colour, FONT)        print_to_screen(wins[1], (670, 550), True, 100, p2_colour, FONT)        #Renders the board tiles and the logo        board_group.draw()        logo.render()        test_for_win()        test_for_draw()        #Update the display        pygame.display.update()        CLOCK.tick(FPS)if __name__ == '__main__':    main()Here's an image of what the game looks like when played:
Noughts and Crosses in Python using the pygame module
python;python 3.x;tic tac toe;pygame
I'd remove those comments, because they don't really add anything (having something like Initialises the pygame module near pygame.init() is not really helpful). The only one I'd keep is clicked = False  # Used to stop holding the mouse down from affecting the program because you're actually explaining why you're doing something, not what.The constants for WIDTH and HEIGHT are used only once, so there's no real need for them.You're not using fname anywhere, you can just remove it and use something likepath = os.path.split(__file__)[0]The line p1_colour, p2_colour = (237,  28,  36), (62,  72, 204) suggests that you want an array or list, so just use it. If you want to change based on both turn and player, you can use lists.colours = [[(237,  28,  36), (36,  44, 134)], [(62,  72, 204), (36, 44, 134)]]And later you do:print_to_screen('P1', (40, 200), False, 250, colours[0][turn], FONT)print_to_screen('P2', (570, 200), False, 250, colours[1][turn], FONT)print_to_screen(wins[0], (110, 550), True, 100, colours[0][turn], FONT)print_to_screen(wins[1], (670, 550), True, 100, colours[1][turn], FONT)So there's no need for the if turn == 0: when setting colours.The test_for_draw() is useless, you can just keep track of how many turns are happening, because the only possible draw is when the players made 9 moves in total.The function Quit() has a bad name, because it looks as if you want to quit the game, while in reality you're checking. Maybe rename it quit_if_needed() ?When the game ends you're resetting the grid (which you can do with a grid = [0] * 9), but you're not resetting the turn, so you don't know which player will be the first, next time (you could say it's the loser of the previous game, but what if it's a draw?).Checking the win/loss can be done differently (maybe with sums, or concatenated strings) but even the way it's now, I think it's good enough.