Dec-20-2022, 01:18 PM
(This post was last modified: Jan-06-2023, 12:42 AM by Yoriz.
Edit Reason: removed unnecessary quote of previous post
)
Alright, ty!
I tried to change a multi-player game to a one playing against computer, but I don't know how to block multiple clicks (for example, I start a game and make a move (a click), then computer does, then my turn again etc. but if I click multiple times before computer plays no matter I click on the same field or a new one, computer will also play that many times (as many as I click) and I don't know how to solve it).
I tried to change a multi-player game to a one playing against computer, but I don't know how to block multiple clicks (for example, I start a game and make a move (a click), then computer does, then my turn again etc. but if I click multiple times before computer plays no matter I click on the same field or a new one, computer will also play that many times (as many as I click) and I don't know how to solve it).
import asyncio from random import * from time import sleep import pygame class Square: """I am a square in a tic-tac-toe board in 3D""" colors = {None: "white", 0: "green", 1: "red"} def __init__(self, side, center=(0, 0, 0)): self.marker = None self.points = [ pygame.Vector3(-1, -1, 0) * side / 2, pygame.Vector3(1, -1, 0) * side / 2, pygame.Vector3(1, 1, 0) * side / 2, pygame.Vector3(-1, 1, 0) * side / 2 ] self.move(center) def empty(self): """Return True if square not filled""" return self.marker is None def rotate(self, rotation): """Rotate square (rx, ry, rz) degrees""" for degrees, vector in zip(rotation, ((1, 0, 0), (0, 1, 0), (0, 0, 1))): if degrees: for point in self.points: point.rotate_ip(degrees, vector) def move(self, offset): """Move square offset (dx, dy, dz) pixels""" for point in self.points: dx, dy, dz = offset point.x += dx point.y += dy point.z += dz def projection(self): """Return points projected on xy plane""" return [pygame.Vector2(point.x, point.y) for point in self.points] def draw(self, surface): """Draw self""" pygame.draw.polygon(surface, self.colors[self.marker], self.projection()) def contains(self, point): """Return True if my xy projection contains point.""" def t_area(a, b, c): """Compute area of triangle""" return abs((a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y)) / 2.0) def t_contains(a, b, c, p): """Return True if triangle ABC contains point p.""" # Create 3 triangles that have p as a vertex. If the sum of the area of these # triangles = area of the triangle ABC, then p is inside the triangle area = t_area(a, b, c) a1 = t_area(a, p, b) a2 = t_area(b, p, c) a3 = t_area(c, p, a) return area >= int(a1 + a2 + a3) # Compensate for numerical errors # Split projected polygon into two triangles. Test if point is inside either triangle. a, b, c, d = self.projection() return t_contains(a, b, c, point) or t_contains(a, c, d, point) class Cube: # Now supports X and diamond patterns winning_combos = ( (0, 2, 4, 6, 8), (9, 11, 13, 15, 17), (18, 20, 22, 24, 26), (1, 3, 5, 7), (10, 12, 14, 16), (19, 21, 23, 25), (0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6), (1, 4, 7), (2, 5, 8), (9, 10, 11), (12, 13, 14), (15, 16, 17), (9, 12, 15), (10, 13, 16), (11, 14, 17), (18, 19, 20), (21, 22, 23), (24, 25, 26), (18, 21, 24), (19, 22, 25), (20, 23, 26), ) """A tic-tac-toe board plastered on the side of a cube""" def __init__(self, side): def make_squares(move, rotation): """Make all the squares on a face. Rotate and the move the squares so they are on the "face" of the cube. """ dx = side / 3 gap = 6 squares = [ Square(dx - gap, (-dx, -dx, 0)), Square(dx - gap, (0, -dx, 0)), Square(dx - gap, (dx, -dx, 0)), Square(dx - gap, (-dx, 0, 0)), Square(dx - gap, (0, 0, 0)), Square(dx - gap, (dx, 0, 0)), Square(dx - gap, (-dx, dx, 0)), Square(dx - gap, (0, dx, 0)), Square(dx - gap, (dx, dx, 0)) ] for square in squares: square.rotate(rotation) square.move(move) return squares self.squares = [ *make_squares((0, 0, -side / 2), (0, 0, 0)), *make_squares((side / 2, 0, 0), (0, 270, 0)), *make_squares((0, -side / 2, 0), (90, 0, 0))] for index, square in enumerate(self.squares): square.index = index self.marker = 0 self.reset() def find_square(self, point): """Return square that was clicked, or None""" for square in self.squares: if square.contains(point): return square if square.empty() else None return None def click(self, point): self.marker = 0 """Place marker on clicked square""" if self.done: # Start now game self.reset() elif square := self.find_square(point): # Place marker and check for a win square.marker = self.marker self.marker_count += 1 self.done = self.check_win(square) or self.marker_count >= 27 def bot_move(self): self.marker = 1 if self.done: # Start now game self.reset() # get random market positon that is unchecked square: Square = choice([square for square in self.squares if square.empty()]) square.marker = self.marker self.marker_count += 1 self.done = self.check_win(square) or self.marker_count >= 27 def check_win(self, square): """Check if most recent move results in a win""" def all_match(marker, combo): """Return True if all squares in combo match marker""" return all((self.squares[i].marker == marker for i in combo)) marker = square.marker for combo in self.winning_combos: if square.index in combo and all_match(marker, combo): self.reset() self.done = True for i in combo: self.squares[i].marker = marker return True return False def reset(self): """Reset all squares to empty""" for square in self.squares: square.marker = None self.done = False self.marker_count = 0 def rotate(self, rotation): """Rotate cube (rx, ry, rz) degrees """ for square in self.squares: square.rotate(rotation) def move(self, move): """Move cube offset (dx, dy, dz) pixels""" for square in self.squares: square.move(move) def draw(self, surface): """Draw all the squares.""" for square in self.squares: square.draw(surface) def main(): pygame.display.set_caption("Tic-Tac-Toe") surface = pygame.display.set_mode((500, 500)) # Make 3 sides of a cube, and rotate so you can see all three sides cube = Cube(300) cube.rotate((0, 45, 0)) cube.rotate((22.5, 0, 0)) center = surface.get_rect() cube.move(pygame.Vector3(center.centerx, center.centery, 0)) cube.draw(surface) pygame.display.flip() turn = 0 running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.MOUSEBUTTONDOWN: cube.click(pygame.Vector2(event.pos)) surface.fill("black") cube.draw(surface) pygame.display.flip() turn += 1 if turn % 2 == 1: pygame.time.wait(1000) cube.bot_move() surface.fill("black") cube.draw(surface) pygame.display.flip() turn += 1 if __name__ == "__main__": pygame.init() main() pygame.quit()