So you're getting an error, it's best if you include this detail in your question.
pygame 2.0.1 (SDL 2.0.14, Python 3.6.9)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
File "./bad_noughts.py", line 47, in <module>
main()
File "./bad_noughts.py", line 44, in main
WIN.blit(Player_1, (72, 35))
NameError: name 'Player_1' is not defined
Inside the main() function, Python doesn't know about Player_1 because it's "local" to the function redraw_window() - that means that only the redraw_window() function knows about Player_1.
So how do you fix this?
The quickest and simplest way is to move the definition of Player_1 to the main program, giving it a "global" scope.
This fixes the error, but the 'X' still doesn't appear... why? The next problem is that you're only drawing the 'X' when the 1 event is received. Then (almost immediately) the background is re-painted again, covering it up. It's only on-screen for a split-second.
One way to fix this is to separate the state of the board with the drawing of the board.
Let's introduce a new list-of-lists board_state, which has 3 rows of 3 cells, one for each area of your nought-and-crosses board:
board_state = [ [ None, None, None ],
[ None, None, None ],
[ None, None, None ] ]
Using this, we can set and check the layout of the moves on the board by saying something like: board[0][0] (top-left) and board[2][2] (bottom-right). One important thing you just realised, is that lists are "zero-indexed", meaning the very first element is at number-0 (not 1)
So now when the player makes a move, we can just set the board state:
elif event.type == pygame.locals.KEYDOWN:
if event.key == K_1:
board_state[0][0] = 'x' # top-left
Now we need to adjust the window drawing function to look at the board-state, and draw what's needed:
def redraw_window():
global board_state
WIN.blit(BG, (0, 0))
WIN.blit(title_label1, (10, 10))
WIN.blit(title_label2, (10, 40))
WIN.blit(title_label3, (10, 70))
x_cursor = 0 # position on the board
y_cursor = 0
for row in ( 0, 1, 2 ):
x_cursor = 0
for col in ( 0, 1, 2 ):
# if there's a move on the board, draw it
if ( board_state[row][col] == 'x' ):
WIN.blit( Player_1, ( x_cursor, y_cursor ) )
elif ( board_state[row][col] == 'o' ):
WIN.blit( Player_2, ( x_cursor, y_cursor ) )
x_cursor += WIDTH//3 # move the cursor across
y_cursor += HEIGHT//3 # move the cursor down
pygame.display.update()
So the loops iterate through the rows and columns of the board_state. Using the (0, 1, 2) in the loop isn't best-practice, but I'm trying to keep it simple. As the loops move through the board, across then down, we also maintain a cursor-position where any player-move should be drawn.
If the board contains an 'x' or 'o', the correct bitmap is drawn. Except this code is a bit rough, so the co-ordinates will probably be a bit off, but I don't have your bitmaps, so that's the best we can do.
Reference Code:
import pygame
import os
import sys
from pygame.locals import *
pygame.init()
WIDTH, HEIGHT = 500, 500
P_WIDTH, P_HEIGHT = 100, 130
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
main_font = pygame.font.SysFont("Comic sans", 40)
#color = (255, 255, 255)
#light_color = (170, 170, 170)
#dark_color = (100, 100, 100)
BG = pygame.transform.scale(pygame.image.load(os.path.join("ox_board.png")).convert_alpha(), (WIDTH, HEIGHT))
Player_1 = pygame.transform.scale(pygame.image.load(os.path.join("ox_x.png")).convert_alpha(), (P_WIDTH, P_HEIGHT))
Player_2 = pygame.transform.scale(pygame.image.load(os.path.join("ox_o.png")).convert_alpha(), (P_WIDTH, P_HEIGHT))
title_label1 = main_font.render("Tic", True, (0, 0, 0))
title_label2 = main_font.render("Tac", True, (0, 0, 0))
title_label3 = main_font.render("Toe", True, (0, 0, 0))
# moves (or not) placed on the board
# None -> no move yet
# Or 'x', 'o'
board_state = [ [ None, None, None ],
[ None, None, None ],
[ None, None, None ] ]
def redraw_window():
global board_state
WIN.blit(BG, (0, 0))
WIN.blit(title_label1, (10, 10))
WIN.blit(title_label2, (10, 40))
WIN.blit(title_label3, (10, 70))
x_cursor = 0 # position on the board
y_cursor = 0
for row in ( 0, 1, 2 ):
x_cursor = 0
for col in ( 0, 1, 2 ):
# if there's a move on the board, draw it
if ( board_state[row][col] == 'x' ):
WIN.blit( Player_1, ( x_cursor, y_cursor ) )
elif ( board_state[row][col] == 'o' ):
WIN.blit( Player_2, ( x_cursor, y_cursor ) )
x_cursor += WIDTH//3 # move the cursor across
y_cursor += HEIGHT//3 # move the cursor down
pygame.display.update()
def main():
while True:
redraw_window()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit(0)
elif event.type == pygame.locals.KEYDOWN:
if event.key == K_1:
board_state[0][0] = 'x'
main()
The board_state also allows you to check whether a move has been made in the cell already. Assume the player pushes 5 (centre cell), you can just check board_state[1][1] != None to test if a move was already placed in that cell.