Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Cube drawing
#29
Could you please implement that in the whole code? I tried it now, made text a global variable in the refresh() function because of "UnboundLocalError: local variable 'text' referenced before assignment" but still can't make it work. I don't get all the logic ...

"""A tic-tac-toe game"""
import pygame
import random

PLAYER = 'X'
ROBOT = 'O'
colors = {None: 'gray30', ROBOT: 'red', PLAYER: 'green'}
 

class Robot:
    """Computer tic-tac-toe player"""
    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):
            """Compute a score for the square.  Uses using minimax
            algorithm with alpha/beta pruning.
            """
            # Place the marker and compute a score for the square.
            # Score is a win, a loss, a draw, or the score from
            # the next play.
            square.mark = mark
            if square.check_win():
                # Give extra weight to earlier wins/losses
                score = 10 - depth if mark == ROBOT else depth - 10
                board.depth = min(board.depth, depth)
            else:
                empty_squares = board.empty_squares()
                if not empty_squares:
                    score = 0  # Draw
                elif mark == 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 we think 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
            # Undo play and return score
            square.mark = None
            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
        pygame.time.wait(1000)
        depth = 10
        for board in self.boards:
            self.get_scores(board)
            depth = min(depth, board.depth)
 
        # Select board(s) with minimum depth.  This is the board(s) 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(s).
        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:
    """I am a square in a tic-tac-toe board in 3D"""
    def __init__(self, board, index, side, center=(0, 0, 0)):
        self.board = board
        self.index = index
        self.mark = None
        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)
 
    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
 
    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 3x3 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 None]
 
    def check_win(self, square):
        """Return winning combination 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 sides of a cube"""
    def __init__(self, side):
        def make_board(center, rotation):
            board = Board(side)
            for square in board.squares:
                square.rotate(rotation)
                square.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 mark in clicked square."""
        if self.mark == PLAYER:
            for square in self.squares:
                if square.contains(point):
                    if square.mark is None:
                        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 = None
        self.mark = PLAYER if mark == 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 = None
 
    def draw(self, surface):
        """Draw all the tic-tac-toe boards."""
        surface.fill("gray95")
        for square in self.squares:
            square.draw(surface)
        pygame.display.flip()
 

def refresh(surface, cube, msg=None):
    """Draw all the tic-tac-toe boards."""
    global text
    surface.fill("white")
    for square in cube.squares:
        square.draw(surface)
    if msg:
        text = pygame.font.Font(None, 100).render(text, True, 'white')
        rect = text.get_rect()
        pos = ((surface.get_width() - rect.width) / 2, (surface.get_height() - rect.height) / 2)
        surface.blit(text, pos)
    pygame.display.flip()
 
def main():
    """Play tic-tac-toe"""
    pygame.display.set_caption("Tic-Tac-Toe")
    surface = pygame.display.set_mode((750, 750))
    cube = Cube(300)
    center = surface.get_rect()
    font = pygame.font.SysFont('Times New Roman', 40)
    for square in cube.squares:
        square.rotate((0, 45, 0))
        square.rotate((30, 0, 0))
        square.move((center.centerx, center.centery, 0))
    robot = Robot(cube)
    cube.draw(surface)

    refresh(surface, cube)
    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():
                    # Game over.  Start a new game
                    cube.reset()
                    if cube.mark == ROBOT:
                        cube.play(robot.play(), ROBOT)
                    refresh(surface, cube)
                else:
                    if cube.click(pygame.Vector2(event.pos)):
                        # Player selected square.  Robot's turn,
                        if not cube.done():
                            refresh(surface, cube)
                            cube.play(robot.play(), ROBOT)
                        # Is the game over?
                        refresh(surface, cube, "Game Over" if cube.done() else None)
                        pygame.event.clear()
 
if __name__ == "__main__":
    pygame.init()
    main()
    pygame.quit()
Also, is there any similar logic by which, during the game, I can display for example "your turn" and "computer's turn" so that I don't have to make a new function?
Reply


Messages In This Thread
Cube drawing - by freethrownucleus - Dec-11-2022, 11:49 PM
RE: Cube drawing - by deanhystad - Dec-13-2022, 04:22 AM
RE: Cube drawing - by freethrownucleus - Dec-13-2022, 12:51 PM
RE: Cube drawing - by ClaytonMorrison - Apr-12-2023, 08:04 AM
RE: Cube drawing - by deanhystad - Dec-13-2022, 10:29 PM
RE: Cube drawing - by freethrownucleus - Dec-14-2022, 12:01 AM
RE: Cube drawing - by deanhystad - Dec-14-2022, 05:13 AM
RE: Cube drawing - by freethrownucleus - Dec-14-2022, 11:06 AM
RE: Cube drawing - by deanhystad - Dec-14-2022, 01:14 PM
RE: Cube drawing - by freethrownucleus - Dec-14-2022, 02:09 PM
RE: Cube drawing - by deanhystad - Dec-14-2022, 08:05 PM
RE: Cube drawing - by freethrownucleus - Dec-14-2022, 10:10 PM
RE: Cube drawing - by deanhystad - Dec-14-2022, 11:44 PM
RE: Cube drawing - by freethrownucleus - Dec-16-2022, 07:49 PM
RE: Cube drawing - by deanhystad - Dec-19-2022, 04:54 AM
RE: Cube drawing - by freethrownucleus - Dec-20-2022, 01:18 PM
RE: Cube drawing - by deanhystad - Dec-21-2022, 12:01 AM
RE: Cube drawing - by freethrownucleus - Dec-21-2022, 12:43 PM
RE: Cube drawing - by deanhystad - Jan-01-2023, 04:36 AM
RE: Cube drawing - by freethrownucleus - Jan-01-2023, 10:25 PM
RE: Cube drawing - by deanhystad - Jan-02-2023, 02:17 PM
RE: Cube drawing - by freethrownucleus - Jan-02-2023, 09:39 PM
RE: Cube drawing - by deanhystad - Jan-02-2023, 10:07 PM
RE: Cube drawing - by freethrownucleus - Jan-02-2023, 10:41 PM
RE: Cube drawing - by deanhystad - Jan-03-2023, 04:31 AM
RE: Cube drawing - by freethrownucleus - Jan-03-2023, 04:01 PM
RE: Cube drawing - by deanhystad - Jan-03-2023, 07:21 PM
RE: Cube drawing - by freethrownucleus - Jan-03-2023, 09:18 PM
RE: Cube drawing - by deanhystad - Jan-03-2023, 10:19 PM
RE: Cube drawing - by freethrownucleus - Jan-04-2023, 08:28 PM
RE: Cube drawing - by deanhystad - Jan-04-2023, 08:29 PM
RE: Cube drawing - by freethrownucleus - Jan-04-2023, 08:53 PM
RE: Cube drawing - by deanhystad - Jan-04-2023, 09:15 PM
RE: Cube drawing - by freethrownucleus - Jan-04-2023, 09:20 PM
RE: Cube drawing - by deanhystad - Jan-04-2023, 09:34 PM
RE: Cube drawing - by freethrownucleus - Jan-05-2023, 01:59 PM
RE: Cube drawing - by deanhystad - Jan-05-2023, 06:06 PM
RE: Cube drawing - by freethrownucleus - Jan-05-2023, 06:26 PM
RE: Cube drawing - by deanhystad - Jan-05-2023, 07:35 PM
RE: Cube drawing - by freethrownucleus - Jan-05-2023, 08:32 PM
RE: Cube drawing - by deanhystad - Jan-05-2023, 09:16 PM
RE: Cube drawing - by freethrownucleus - Jan-05-2023, 09:32 PM
RE: Cube drawing - by deanhystad - Jan-05-2023, 10:03 PM
RE: Cube drawing - by freethrownucleus - Jan-05-2023, 10:18 PM
RE: Cube drawing - by deanhystad - Jan-05-2023, 10:23 PM
RE: Cube drawing - by freethrownucleus - Jan-05-2023, 11:24 PM
RE: Cube drawing - by deanhystad - Jan-06-2023, 07:15 PM
RE: Cube drawing - by freethrownucleus - Jan-07-2023, 08:44 PM
RE: Cube drawing - by deanhystad - Jan-07-2023, 11:19 PM
RE: Cube drawing - by freethrownucleus - Jan-08-2023, 12:25 AM
RE: Cube drawing - by deanhystad - Jan-08-2023, 05:11 PM
RE: Cube drawing - by freethrownucleus - Jan-08-2023, 06:29 PM

Possibly Related Threads…
Thread Author Replies Views Last Post
  Drawing a net of a cube freethrownucleus 26 5,640 May-05-2023, 10:23 PM
Last Post: freethrownucleus
  2D-Cube-Tic-Tac-Toe freethrownucleus 0 1,223 Mar-10-2023, 07:07 PM
Last Post: freethrownucleus
  PyGlet Trouble Drawing Cube. Windspar 3 5,840 Jan-02-2018, 06:37 PM
Last Post: Windspar

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020