Dec-13-2022, 10:29 PM
(This post was last modified: Dec-13-2022, 10:29 PM by deanhystad.)
As for playing against the computer, what have you tried? You should start with a regular 3x3 tic-tac-toe game.
About game rules: 3 in any row? Even wrapping around a corner? If you can bend around a corner, can you bend diagonally? I tried this and the first player always wins.
About game rules: 3 in any row? Even wrapping around a corner? If you can bend around a corner, can you bend diagonally? I tried this and the first player always wins.
import pygame class Square: """I am a square in a tic-tac-toe board in 3D""" def __init__(self, side, center=(0, 0, 0)): self.color = "white" 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 rotate(self, rotation): """Rotate square (rx, ry, rz) degrees. rx rotates about the x axis, ry about the y axis, rz about the z axis. """ 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.color, 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 Face: def __init__(self, side, center=(0, 0, 0), rotation=(0, 0, 0)): side = side / 3 gap = 8 self.squares = [ Square(side-gap, (-side, -side, 0)), Square(side-gap, (0, -side, 0)), Square(side-gap, (side, -side, 0)), Square(side-gap, (-side, 0, 0)), Square(side-gap, (0, 0, 0)), Square(side-gap, (side, 0, 0)), Square(side-gap, (-side, side, 0)), Square(side-gap, (0, side, 0)), Square(side-gap, (side, side, 0)) ] self.rotate(rotation) self.move(center) def reset(self): """Reset board to empty""" self.winner = None self.markers = [None] * 9 for square in self.squares: square.color = self.clear_color def move(self, offset): """Move square offset (dx, dy, dz) pixels""" for square in self.squares: square.move(offset) def rotate(self, rotation): """Rotate square (rx, ry, rz) degrees. rx rotates about the x axis, ry about the y axis, rz about the z axis. """ for square in self.squares: square.rotate(rotation) class Cube: winning_combos = ( (0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6), (1, 4, 7), (2, 5, 8), (0, 4, 8), (2, 4, 6), (9, 10, 11), (12, 13, 14), (15, 16, 17), (9, 12, 15), (10, 13, 16), (11, 14, 17), (9, 13, 17), (11, 13, 15), (18, 19, 20), (21, 22, 23), (24, 25, 26), (18, 21, 24), (19, 22, 25), (20, 23, 26), (18, 22, 26), (24, 22, 20), (1, 2, 9), (2, 9, 10), (4, 5, 12), (5, 12, 13), (8, 9, 16), (9, 16, 17), (3, 0, 18), (0, 18, 21), (4, 1, 19), (1, 19, 22), (5, 2, 20), (2, 20, 23), (12, 9, 20), (9, 20, 19), (13, 10, 23), (10, 23, 22), (14, 11, 26), (11, 26, 25), (3, 1, 20), (0, 19, 23), (5, 1, 18), (2, 19, 21), (1, 5, 15), (2, 12, 16), (7, 5, 9), (8, 12, 10), (19, 23, 11), (20, 10, 14), (25, 22, 9), (26, 10, 12) ) """A tic-tac-toe board plastered on the side of a cube""" def __init__(self, side): self.clear_color = "white" self.colors = ["red", "blue"] self.marker = 0 self.faces = [ Face(side, (0, 0, -side/2), (0, 0, 0)), Face(side, (side/2, 0, 0), (0, 270, 0)), Face(side, (0, -side/2, 0), (90, 0, 0)) ] self.squares = [] for face in self.faces: self.squares.extend(face.squares) for index, square in enumerate(self.squares): square.index = index square.marker = None self.reset() def click(self, point): """Find where to place marker""" def locate(point): for square in self.squares: if square.contains(point): return square return None if self.done: self.reset() return square = locate(point) print(square.index) if square and square.marker == None: square.marker = self.marker square.color = self.colors[self.marker] self.marker = (self.marker + 1) % 2 self.check_win(square) def check_win(self, square): def winner(squares): a, b, c = [self.squares[i].marker for i in squares] if a == b == c and a is not None: return a return None for combo in self.winning_combos: if square.index in combo and winner(combo) is not None: self.reset() self.done = True for index in combo: self.squares[index].color = self.colors[self.marker] break def reset(self): for square in self.squares: square.marker = None square.color = self.clear_color self.done = False def rotate(self, rotation): """Rotate square (rx, ry, rz) degrees. rx rotates about the x axis, ry about the y axis, rz about the z axis. """ for face in self.faces: face.rotate(rotation) def move(self, move): """Move square offset (dx, dy, dz) pixels""" for face in self.faces: face.move(move) def draw(self, surface): """Draw all the tic-tac-toe boards.""" 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() 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() if __name__ == "__main__": pygame.init() main() pygame.quit()A variation that might be playable is to play until all squares but 1 are filled (each player gets 13 squares). Then compute the number of winners for each player.