Mar-10-2023, 07:07 PM
(This post was last modified: Mar-10-2023, 07:07 PM by freethrownucleus.)
Could someone help me with the next, please?
This is the cube model that I've got right now: https://gofile.io/d/RxqDYR .
I would like to change it to this: https://gofile.io/d/aL1srG (don't mind the painted squares).
The new model presents a cube net with 6 sides. Each of the sides presents one tic-tac-toe board.
Here is the game's code:
This is the cube model that I've got right now: https://gofile.io/d/RxqDYR .
I would like to change it to this: https://gofile.io/d/aL1srG (don't mind the painted squares).
The new model presents a cube net with 6 sides. Each of the sides presents one tic-tac-toe board.
Here is the game's code:
"""Tic-tac-toe with a computer opponent. Three boards played simultaneously""" import pygame import random PLAYER = 'X' ROBOT = 'O' EMPTY = ' ' background = "aliceblue" msg_color = "dodgerblue" colors = {EMPTY: 'dodger blue', PLAYER: 'green', ROBOT: 'red'} class Robot: def __init__(self, cube): self.boards = cube.boards def get_scores(self, board): """Get scores for all open squares on a board""" def minimax(mark, square, alpha=-1000, beta=1000, depth=0): """minimax algorithm with alpha/beta pruning""" # Place the mark and check for a win square.mark = mark if square.check_win(): # Give extra weight to earlier wins/losses score = 10 - depth if mark is ROBOT else depth - 10 board.depth = min(board.depth, depth) elif len(empty_squares := board.empty_squares()) == 0: # No plays left. Draw. score = 0 elif mark is PLAYER: # Pick best move for robot score = -1000 for s in empty_squares: score = max(score, minimax(ROBOT, s, alpha, beta, depth+1)) alpha = max(alpha, score) if alpha > beta: break else: # Guess what move player will make score = 1000 for s in empty_squares: score = min(score, minimax(PLAYER, s, alpha, beta, depth+1)) beta = min(beta, score) if alpha > beta: break # Remove mark and return score for the square square.mark = EMPTY return score # Collect scores for empty squares. If board is empty, # minimax will return 0 for all squares board.depth = 10 empty_squares = board.empty_squares() if len(empty_squares) == 9: board.scores = [[0, s] for s in empty_squares] else: # Calling minimax twice. The first is to find the square # giving us best chance to win board. Second is to prevent # abandoning board early and giving player an easy win. board.scores = [[minimax("O", s), s] for s in empty_squares] [minimax("X", s, depth=1) for s in empty_squares] def play(self): """Place robot mark.""" # Get scores for all empty squares depth = 10 for board in self.boards: self.get_scores(board) depth = min(depth, board.depth) # Select board with minimum depth. This is the board that # will win/lose in the least number of moves. scores = [] for board in self.boards: if board.depth <= depth: scores.extend(board.scores) # Randomly select from best scores on the selected board. max_score = max(score[0] for score in scores) squares = [score[1] for score in scores if score[0] >= max_score] return random.choice(squares) class Square: """A 3D square in a tic-tac-toe board""" def __init__(self, board, index, side, center=(0, 0, 0)): self.board = board self.index = index self.mark = EMPTY self.corners = [ 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""" for deg, axis in zip(rotation, ((1, 0, 0), (0, 1, 0), (0, 0, 1))): if deg: for corner in self.corners: corner.rotate_ip(deg, axis) return self def move(self, offset): """Move square offset (x, y, z) pixels""" x, y, z = offset for corner in self.corners: corner.x += x corner.y += y corner.z += z return self def projection(self): """Return corners projected on xy plane""" return [pygame.Vector2(p.x, p.y) for p in self.corners] def draw(self, surface): """Draw projection of square on xy plane""" pygame.draw.polygon(surface, colors[self.mark], self.projection()) def contains(self, point): """Return True if projection contains point.""" def 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 has_point(a, b, c, p): """Return True if triange ABC contains point p.""" return area(a, b, c) >= int(area(a, p, b) + area(b, p, c) + area(c, p, a)) a, b, c, d = self.projection() return has_point(a, b, c, point) or has_point(a, c, d, point) def check_win(self): return self.board.check_win(self) class Board: """A tic-tac-toe board""" winning_combos = ( (0, 2, 4, 6, 8), (1, 3, 5, 7), (0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6), (1, 4, 7), (2, 5, 8), ) def __init__(self, side): dx = side / 3 self.squares = [] for index in range(9): x = (index % 3 - 1) * dx y = (index // 3 - 1) * dx self.squares.append(Square(self, index, dx-3, (x, y, 0))) self.scores = None self.depth = 10 def empty_squares(self): """Return list of empty squares""" return [s for s in self.squares if s.mark is EMPTY] def check_win(self, square): """Return winning squares from last move, else None""" for combo in self.winning_combos: if square.index in combo: squares = [self.squares[i] for i in combo] if all(square.mark == s.mark for s in squares): return squares return None class Cube: """Three tic-tac-toe boards plastered on the faces of a cube""" def __init__(self, side): def make_board(center, rotation): board = Board(side) for square in board.squares: square.rotate(rotation).move(center) return board self.boards = [ make_board((0, 0, -side/2), (0, 0, 0)), make_board((side/2, 0, 0), (0, 270, 0)), make_board((0, -side/2, 0), (90, 0, 0)) ] self.squares = [s for b in self.boards for s in b.squares] self.winner = None self.mark = PLAYER self.reset() def click(self, point): """Try to place player's mark in clicked square.""" if self.mark is PLAYER: for square in self.squares: if square.contains(point): if square.mark is EMPTY: self.play(square, self.mark) return square break return None def play(self, square, mark): """Place mark in square. Test if is a winning move""" square.mark = mark self.mark_count += 1 if winner := square.check_win(): self.winner = winner for square in self.squares: if square not in winner: square.mark = EMPTY self.mark = PLAYER if mark is ROBOT else ROBOT def done(self): """Return True if there is a winner or draw""" return self.winner or self.mark_count >= 27 def reset(self): """Reset all boards to empty""" self.mark_count = 0 self.winner = None for square in self.squares: square.mark = EMPTY def main(): """Play tic-tac-toe""" def blit_text(surface, msg, pos, font, color = pygame.Color('dodgerblue')): x, y = pos m = msg.split('\n') for line in m: text = pygame.font.Font(None, 48).render(line, True, msg_color) width, height = text.get_size() surface.blit(text, (x - width/2, y - height * 2)) y += height + 2. def refresh_screen(surface, msg = None): """Draw the cube and an optional message""" surface.fill(background) for square in cube.squares: square.draw(surface) text_player1 = pygame.font.Font(None, 48).render("You", True, 'green') text_vs = pygame.font.Font(None, 48).render("vs", True, 'dodgerblue') text_player2 = pygame.font.Font(None, 48).render("Computer", True, 'red') surface.blit(text_player1, (text_player1.get_width(), text_player1.get_height())) surface.blit(text_vs, (center.x - text_vs.get_width() / 2, text_vs.get_height())) surface.blit(text_player2, (center.x + text_player2.get_width(), text_player2.get_height())) if msg: text = pygame.font.Font(None, 48).render(msg, True, msg_color) pos = (350, 700) blit_text(surface, msg, pos, None, color = pygame.Color('dodgerblue')) pygame.display.flip() pygame.display.set_caption("3D-Tic-Tac-Toe") surface = pygame.display.set_mode((700, 750)) center = pygame.Vector3(350, 350, 0) # Move cube for pretty orthogonal view at center of screen cube = Cube(300) for square in cube.squares: square.rotate((0, 45, 0)).rotate((30, 0, 0)).move(center) robot = Robot(cube) refresh_screen(surface, None) running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.MOUSEBUTTONDOWN: if cube.done(): # Start a new game cube.reset() if cube.mark is ROBOT: cube.play(robot.play(), ROBOT) refresh_screen(surface, None) elif cube.click(pygame.Vector2(event.pos)): # Player selected square. Robot's turn, if not cube.done(): refresh_screen(surface, None) cube.play(robot.play(), ROBOT) # Is the game over? if cube.done(): refresh_screen(surface, "Ready for another play?\nJust click on the screen!") else: refresh_screen(surface, None) pygame.event.clear() if __name__ == "__main__": pygame.init() main() pygame.quit()Thanks in advance!