问题
The draw Board functions has an if statement to see which colour circle it should draw. But when the mouse button is clicked it draws the circle in the right x coordinate but in the opposite y coordinate. Also, the end is a little bit weird I want to display the winner and then wait using time.wait
but it waits and then prints the statement for a second. If you could run it, you would understand. I am also looking for general improvements that I could make.
import pygame, sys
import numpy as np
import math
pygame.init()
clock = pygame.time.Clock()
# Colours
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
ROW_COUNT = 3
COLUMN_COUNT = 3
SQUARE_SIZE = 100
RADIUS = int(SQUARE_SIZE/2 - 5)
WIDTH = COLUMN_COUNT * SQUARE_SIZE
HEIGHT = ROW_COUNT * SQUARE_SIZE
myfont = pygame.font.SysFont("monospace", 20)
PLAYER_COUNT = 2
screen = pygame.display.set_mode((WIDTH, HEIGHT))
screen.fill(WHITE)
class Player:
def __init__(self, number):
self.number = number
players = [Player(i) for i in range(1, PLAYER_COUNT + 1)]
class Board:
def __init__(self):
self.board_body = np.zeros((ROW_COUNT, COLUMN_COUNT), dtype=np.uint8)
self.remaining_spaces = 9
self.print_board()
self.draw_board()
def print_board(self):
print(np.flip(self.board_body, 0))
def draw_board(self):
one_x, one_y, one_end_x, one_end_y, two_x, two_y, two_end_x, two_end_y = 100, 0, 100, 300, 0, 100, 300, 100
for r in range(ROW_COUNT):
for c in range(COLUMN_COUNT):
pygame.draw.line(screen, BLACK, (one_x, one_y), (one_end_x, one_end_y), 3)
one_x += 100
one_end_x += 100
pygame.draw.line(screen, BLACK, (two_x, two_y), (two_end_x, two_end_y), 3)
two_y += 100
two_end_y += 100
for c in range(COLUMN_COUNT):
for r in range(ROW_COUNT):
if self.board_body[r][c] == 1:
pygame.draw.circle(screen, RED, (int(c * SQUARE_SIZE + SQUARE_SIZE / 2), HEIGHT - int(r * SQUARE_SIZE + SQUARE_SIZE / 2)), RADIUS)
elif self.board_body[r][c] == 2:
pygame.draw.circle(screen, GREEN, (int(c * SQUARE_SIZE + SQUARE_SIZE / 2), HEIGHT - int(r * SQUARE_SIZE + SQUARE_SIZE / 2)), RADIUS)
pygame.display.update()
def check_empty_space_and_place(self, row, column, number):
if self.board_body[row][column] == 0:
self.board_body[row][column] = number
self.remaining_spaces -= 1
def check_winning_move(self, board, piece):
# Horizontal
for c in range(COLUMN_COUNT - 1):
for r in range(ROW_COUNT - 1):
if board[r - 1][c] == piece and board[r][c] == piece and board[r + 1][c] == piece:
return True
# Vertical
for c in range(0, COLUMN_COUNT - 1):
for r in range(0, ROW_COUNT - 1):
if board[r][c - 1] == piece and board[r][c] == piece and board[r][c + 1] == piece:
return True
# Positively sloped diagonals
for c in range(0, COLUMN_COUNT - 1):
for r in range(0, ROW_COUNT - 1):
if board[r][c] == piece and board[r + 1][c + 1] == piece and board[r + 2][c + 2] == piece:
return True
# Negatively sloped diagonals
for c in range(COLUMN_COUNT - 1):
for r in range(ROW_COUNT - 1):
if board[r + 1][c + 1] == piece and board[r][c] == piece and board[r - 1][c - 1] == piece:
return True
def next_player():
while True:
for player in players:
yield player
player_generator = next_player()
board = Board()
run = True
while run:
if board.remaining_spaces == 0:
run = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
pos_of_mouse = pygame.mouse.get_pos()
posx = pos_of_mouse[0]
posy = pos_of_mouse[1]
column = int(posx // SQUARE_SIZE)
row = int(posy // SQUARE_SIZE)
p = player_generator.__next__()
board.check_empty_space_and_place(row, column, p.number)
board.draw_board()
if board.check_winning_move(board.board_body, p.number):
label = myfont.render("Player {} wins!!!!".format(p.number), False, WHITE)
screen.fill(BLACK)
screen.blit(label, (20, 50))
pygame.time.wait(3000)
run = False
board.print_board()
pygame.display.update()
clock.tick(60)```
回答1:
In the PyGame coordinate system the top left is (0, 0). You don't have to flip the y-axis or subtract the y-coordinate from the height. Remove the term HEIGHT -
in the method draw_board
of the class Board
:
class Board:
# [...]
def draw_board(self):
# [...]
for c in range(COLUMN_COUNT):
for r in range(ROW_COUNT):
if self.board_body[r][c] == 1:
pygame.draw.circle(screen, RED, (int(c * SQUARE_SIZE + SQUARE_SIZE / 2), int(r * SQUARE_SIZE + SQUARE_SIZE / 2)), RADIUS)
elif self.board_body[r][c] == 2:
pygame.draw.circle(screen, GREEN, (int(c * SQUARE_SIZE + SQUARE_SIZE / 2), int(r * SQUARE_SIZE + SQUARE_SIZE / 2)), RADIUS)
# [...]
If you just wait for some time, you can use pygame.time.wait or pygame.time.delay. However, if you want to display a message and then wait some time, you need to update the display beforehand. The display is updated only if either pygame.display.update() or pygame.display.flip()
is called. Further you've to handles the events by pygame.event.pump(), before the update of the display becomes visible in the window:
(See How to wait some time in pygame?)
screen.fill(BLACK)
screen.blit(label, (20, 50))
pygame.display.flip()
pygame.event.pump()
pygame.time.wait(3000)
Also, there are some mistakes when looking for a winner. Yo don't need nestes loops at all. There are just 2 diagonals. So you don't need any loops for the diagonals:
class Board:
# [...]
def check_winning_move(self, board, piece):
# Horizontal
for c in range(COLUMN_COUNT):
if board[0][c] == piece and board[1][c] == piece and board[2][c] == piece:
return True
# Vertical
for r in range(ROW_COUNT):
if board[r][0] == piece and board[r][1] == piece and board[r][2] == piece:
return True
# Positively sloped diagonals
if board[0][0] == piece and board[1][1] == piece and board[2][2] == piece:
return True
# Negatively sloped diagonals
if board[0][2] == piece and board[1][1] == piece and board[2][0] == piece:
return True
See also Pygame Tic Tak Toe Logic? How Would I Do It.
Complete code:
import pygame, sys
import numpy as np
import math
pygame.init()
clock = pygame.time.Clock()
# Colours
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
ROW_COUNT = 3
COLUMN_COUNT = 3
SQUARE_SIZE = 100
RADIUS = int(SQUARE_SIZE/2 - 5)
WIDTH = COLUMN_COUNT * SQUARE_SIZE
HEIGHT = ROW_COUNT * SQUARE_SIZE
myfont = pygame.font.SysFont("monospace", 20)
PLAYER_COUNT = 2
screen = pygame.display.set_mode((WIDTH, HEIGHT))
screen.fill(WHITE)
class Player:
def __init__(self, number):
self.number = number
players = [Player(i) for i in range(1, PLAYER_COUNT + 1)]
class Board:
def __init__(self):
self.board_body = np.zeros((ROW_COUNT, COLUMN_COUNT), dtype=np.uint8)
self.remaining_spaces = 9
self.print_board()
self.draw_board()
def print_board(self):
print(np.flip(self.board_body, 0))
def draw_board(self):
one_x, one_y, one_end_x, one_end_y, two_x, two_y, two_end_x, two_end_y = 100, 0, 100, 300, 0, 100, 300, 100
for r in range(ROW_COUNT):
for c in range(COLUMN_COUNT):
pygame.draw.line(screen, BLACK, (one_x, one_y), (one_end_x, one_end_y), 3)
one_x += 100
one_end_x += 100
pygame.draw.line(screen, BLACK, (two_x, two_y), (two_end_x, two_end_y), 3)
two_y += 100
two_end_y += 100
for c in range(COLUMN_COUNT):
for r in range(ROW_COUNT):
if self.board_body[r][c] == 1:
pygame.draw.circle(screen, RED, (int(c * SQUARE_SIZE + SQUARE_SIZE / 2), int(r * SQUARE_SIZE + SQUARE_SIZE / 2)), RADIUS)
elif self.board_body[r][c] == 2:
pygame.draw.circle(screen, GREEN, (int(c * SQUARE_SIZE + SQUARE_SIZE / 2), int(r * SQUARE_SIZE + SQUARE_SIZE / 2)), RADIUS)
pygame.display.update()
def check_empty_space_and_place(self, row, column, number):
if self.board_body[row][column] == 0:
self.board_body[row][column] = number
self.remaining_spaces -= 1
def check_winning_move(self, board, piece):
# Horizontal
for c in range(COLUMN_COUNT):
if board[0][c] == piece and board[1][c] == piece and board[2][c] == piece:
return True
# Vertical
for r in range(ROW_COUNT):
if board[r][0] == piece and board[r][1] == piece and board[r][2] == piece:
return True
# Positively sloped diagonals
if board[0][0] == piece and board[1][1] == piece and board[2][2] == piece:
return True
# Negatively sloped diagonals
if board[0][2] == piece and board[1][1] == piece and board[2][0] == piece:
return True
def next_player():
while True:
for player in players:
yield player
player_generator = next_player()
board = Board()
run = True
while run:
if board.remaining_spaces == 0:
run = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
pos_of_mouse = pygame.mouse.get_pos()
posx = pos_of_mouse[0]
posy = pos_of_mouse[1]
column = int(posx // SQUARE_SIZE)
row = int(posy // SQUARE_SIZE)
p = player_generator.__next__()
board.check_empty_space_and_place(row, column, p.number)
board.draw_board()
if board.check_winning_move(board.board_body, p.number):
label = myfont.render("Player {} wins!!!!".format(p.number), False, WHITE)
screen.fill(BLACK)
screen.blit(label, (20, 50))
pygame.display.flip()
pygame.event.pump()
pygame.time.wait(3000)
run = False
board.print_board()
pygame.display.update()
clock.tick(60)
来源:https://stackoverflow.com/questions/65522324/im-making-a-simple-tictactoe-in-pyjama-but-i-am-running-into-some-errors