Jaden's Python Game v 1.8.7

To run the games, you need to pip install pygame, random, sys and time
        


# MADE BY JADEN
# Version 1.8.7 - Update from 4/06/2025

# FUTURE UPDATES
# Adding Hangman as game 6


#----------------------------------------------------------------------------------------------------


# PONG UPDATE 1.8.7
# 1.8.7 - Fixed a bug where the player would not move when the arrow keys were pressed in pong
# 1.8.7 - Fixed a bug where the ball would not move when the player scored a point in pong
# 1.8.7 - Fixed a bug where the screen would blank out when loading pong


# QUALITY OF LIFE CHANGES 1.8.6
# 1.8.6 Fixed arrow keys not working

# QUALITY OF LIFE CHANGES 1.8.5
# 1.8.5 Re-made main screen

# 1.8.4 - 1.2.1 NOT RECORDED

# 1.1.5 BREAKOUT UPDATE
# 1.1.5 Fixed a bug where the ball leaves the screen when arrow keys pressed
# 1.1.5 Fixed a bug where the breakout blocks don't break early game

# 1.1.4 

#Games: Snake, Tic Tac Toe, Pong, Breakout, Minesweeper, Text Adventure RPG


import pygame
import sys
import random
import time

pygame.init()
pygame.display.set_caption("Jaden's Python Games")

WIDTH, HEIGHT = 800, 600
SCREEN = pygame.display.set_mode((WIDTH, HEIGHT))
CLOCK = pygame.time.Clock()
FONT = pygame.font.SysFont("arial", 24)
BIG_FONT = pygame.font.SysFont("arial", 48)

WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (200, 200, 200)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
ORANGE = (255, 165, 0)

# ----------- UTILITIES -----------

def draw_text(text, font, color, surface, x, y):
    txt = font.render(text, True, color)
    surface.blit(txt, (x, y))

def wait_for_key():
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.KEYDOWN:
                return event.key
        CLOCK.tick(30)

# ---------- MAIN MENU -----------

class Menu:
    def __init__(self, options, title=""):
        self.options = options
        self.title = title
        self.selected = 0

    def draw(self):
        SCREEN.fill(BLACK)
        if self.title:
            draw_text(self.title, BIG_FONT, WHITE, SCREEN, WIDTH//2 - BIG_FONT.size(self.title)[0]//2, 40)

        for i, option in enumerate(self.options):
            color = YELLOW if i == self.selected else WHITE
            draw_text(option, FONT, color, SCREEN, WIDTH//2 - FONT.size(option)[0]//2, 150 + i*40)


        draw_text("Use UP/DOWN to select, ENTER to confirm", FONT, GRAY, SCREEN, WIDTH//2 - 200, HEIGHT - 50)
        pygame.display.flip()
        print("Opening Main Menu")

    def run(self):
        while True:
            self.draw()
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_UP:
                        self.selected = (self.selected - 1) % len(self.options)
                    elif event.key == pygame.K_DOWN:
                        self.selected = (self.selected + 1) % len(self.options)
                    elif event.key == pygame.K_RETURN:
                        return self.selected
            CLOCK.tick(30)

# ----------- GAME 1: Snake -----------

class Snake:
    def __init__(self):
        self.snake_pos = [(WIDTH // 2, HEIGHT // 2)]
        self.snake_dir = (0, -20)
        self.food_pos = self.spawn_food()
        self.score = 0
        self.game_over = False
        print("Opening Snake")

    def spawn_food(self):
        x = random.randint(0, (WIDTH // 20) - 1) * 20
        y = random.randint(0, (HEIGHT // 20) - 1) * 20
        while (x, y) in self.snake_pos:
            x = random.randint(0, (WIDTH // 20) - 1) * 20
            y = random.randint(0, (HEIGHT // 20) - 1) * 20
        return (x, y)

    def draw(self):
        SCREEN.fill(BLACK)
        for pos in self.snake_pos:
            pygame.draw.rect(SCREEN, GREEN, pygame.Rect(pos[0], pos[1], 20, 20))
        pygame.draw.rect(SCREEN, RED, pygame.Rect(self.food_pos[0], self.food_pos[1], 20, 20))
        draw_text(f"Score: {self.score}", FONT, WHITE, SCREEN, 10, 10)
        draw_text("ESC to return to menu", FONT, GRAY, SCREEN, 10, HEIGHT - 30)
        pygame.display.flip()

    def run(self):
        while not self.game_over:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        return
                    elif event.key == pygame.K_UP and self.snake_dir != (0, 20):
                        self.snake_dir = (0, -20)
                    elif event.key == pygame.K_DOWN and self.snake_dir != (0, -20):
                        self.snake_dir = (0, 20)
                    elif event.key == pygame.K_LEFT and self.snake_dir != (20, 0):
                        self.snake_dir = (-20, 0)
                    elif event.key == pygame.K_RIGHT and self.snake_dir != (-20, 0):
                        self.snake_dir = (20, 0)

            # Move snake
            new_head = (self.snake_pos[0][0] + self.snake_dir[0], self.snake_pos[0][1] + self.snake_dir[1])

            # Check collisions with walls
            if (new_head[0] < 0 or new_head[0] >= WIDTH or
                new_head[1] < 0 or new_head[1] >= HEIGHT):
                self.game_over = True
                continue

            # Check collisions with itself
            if new_head in self.snake_pos:
                self.game_over = True
                continue

            self.snake_pos.insert(0, new_head)

            # Check food collision
            if new_head == self.food_pos:
                self.score += 1
                self.food_pos = self.spawn_food()
            else:
                self.snake_pos.pop()

            self.draw()
            CLOCK.tick(10)

        # Game Over screen
        SCREEN.fill(BLACK)
        draw_text("Game Over!", BIG_FONT, RED, SCREEN, WIDTH//2 - 120, HEIGHT//2 - 60)
        draw_text(f"Score: {self.score}", BIG_FONT, WHITE, SCREEN, WIDTH//2 - 80, HEIGHT//2)
        draw_text("Press any key to return", FONT, GRAY, SCREEN, WIDTH//2 - 130, HEIGHT//2 + 80)
        pygame.display.flip()
        wait_for_key()

# ----------- GAME 2: Tic-Tac-Toe -----------

class TicTacToe:
    def __init__(self):
        self.board = [[""]*3 for _ in range(3)]
        self.player = "X"
        self.winner = None
        self.game_over = False
        self.cell_size = 150
        self.margin_x = WIDTH//2 - self.cell_size * 3 // 2
        self.margin_y = HEIGHT//2 - self.cell_size * 3 // 2
        print("Opening Tic-Tac-Toe")

    def draw_board(self):
        SCREEN.fill(BLACK)
        # draw grid
        for i in range(4):
            pygame.draw.line(SCREEN, WHITE,
                             (self.margin_x, self.margin_y + i*self.cell_size),
                             (self.margin_x + 3*self.cell_size, self.margin_y + i*self.cell_size), 3)
            pygame.draw.line(SCREEN, WHITE,
                             (self.margin_x + i*self.cell_size, self.margin_y),
                             (self.margin_x + i*self.cell_size, self.margin_y + 3*self.cell_size), 3)

        # draw moves
        for r in range(3):
            for c in range(3):
                mark = self.board[r][c]
                if mark:
                    draw_text(mark, BIG_FONT, RED if mark == "X" else BLUE,
                              SCREEN,
                              self.margin_x + c*self.cell_size + self.cell_size//2 - BIG_FONT.size(mark)[0]//2,
                              self.margin_y + r*self.cell_size + self.cell_size//2 - BIG_FONT.size(mark)[1]//2)

        # status
        if self.winner:
            draw_text(f"{self.winner} wins!", FONT, GREEN, SCREEN, 10, 10)
        elif self.game_over:
            draw_text("Tie Game!", FONT, YELLOW, SCREEN, 10, 10)
        else:
            draw_text(f"{self.player}'s turn", FONT, WHITE, SCREEN, 10, 10)

        draw_text("ESC to return to menu", FONT, GRAY, SCREEN, 10, HEIGHT - 30)

        pygame.display.flip()

    def check_winner(self):
        lines = []
        # rows
        for r in range(3):
            lines.append(self.board[r])
        # cols
        for c in range(3):
            lines.append([self.board[r][c] for r in range(3)])
        # diagonals
        lines.append([self.board[i][i] for i in range(3)])
        lines.append([self.board[i][2-i] for i in range(3)])

        for line in lines:
            if line[0] and line[0] == line[1] == line[2]:
                return line[0]

        if all(self.board[r][c] != "" for r in range(3) for c in range(3)):
            return "Tie"
        return None

    def run(self):
        while True:
            self.draw_board()
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        return
                elif event.type == pygame.MOUSEBUTTONDOWN and not self.game_over:
                    mx, my = pygame.mouse.get_pos()
                    c = (mx - self.margin_x) // self.cell_size
                    r = (my - self.margin_y) // self.cell_size
                    if 0 <= r < 3 and 0 <= c < 3:
                        if self.board[r][c] == "":
                            self.board[r][c] = self.player
                            self.winner = self.check_winner()
                            if self.winner == "Tie":
                                self.game_over = True
                            elif self.winner:
                                self.game_over = True
                            else:
                                self.player = "O" if self.player == "X" else "X"

            CLOCK.tick(30)

# ----------- GAME 3: Hangman -----------

class Hangman:
    WORDS = ["PYTHON", "HANGMAN", "DEVELOPER", "PROGRAM", "COMPUTER", "PYGAME", "JADEN", "GAMES", "CODING","HACKER","JADEN"]

    def __init__(self):
        self.word = random.choice(self.WORDS)
        self.guessed = set()
        self.wrong_guesses = 0
        self.max_wrong = 6
        self.game_over = False
        self.won = False
        print("Opening Hangman")

    def draw_hangman(self):
        # Simple hangman drawing
        # base
        pygame.draw.line(SCREEN, WHITE, (150, 500), (350, 500), 6)
        # pole
        pygame.draw.line(SCREEN, WHITE, (250, 500), (250, 150), 6)
        # arm
        pygame.draw.line(SCREEN, WHITE, (250, 150), (400, 150), 6)
        # rope
        pygame.draw.line(SCREEN, WHITE, (400, 150), (400, 200), 4)

        if self.wrong_guesses > 0:  # head
            pygame.draw.circle(SCREEN, WHITE, (400, 230), 30, 4)
        if self.wrong_guesses > 1:  # body
            pygame.draw.line(SCREEN, WHITE, (400, 260), (400, 350), 4)
        if self.wrong_guesses > 2:  # left arm
            pygame.draw.line(SCREEN, WHITE, (400, 280), (350, 320), 4)
        if self.wrong_guesses > 3:  # right arm
            pygame.draw.line(SCREEN, WHITE, (400, 280), (450, 320), 4)
        if self.wrong_guesses > 4:  # left leg
            pygame.draw.line(SCREEN, WHITE, (400, 350), (350, 420), 4)
        if self.wrong_guesses > 5:  # right leg
            pygame.draw.line(SCREEN, WHITE, (400, 350), (450, 420), 4)

    def draw(self):
        SCREEN.fill(BLACK)
        draw_text("Hangman", BIG_FONT, WHITE, SCREEN, WIDTH//2 - 100, 20)

        # Draw guessed word
        display_word = ""
        for ch in self.word:
            display_word += ch + " " if ch in self.guessed else "_ "
        draw_text(display_word, BIG_FONT, GREEN, SCREEN, WIDTH//2 - 150, HEIGHT//2 - 40)

        # Draw guessed letters
        guessed_text = "Guessed: " + ", ".join(sorted(self.guessed))
        draw_text(guessed_text, FONT, WHITE, SCREEN, 10, HEIGHT - 80)

        # Draw hangman
        self.draw_hangman()

        # Status
        if self.game_over:
            if self.won:
                draw_text("You Won! Press any key to return", FONT, YELLOW, SCREEN, WIDTH//2 - 180, HEIGHT - 40)
            else:
                draw_text(f"You Lost! Word was: {self.word}", FONT, RED, SCREEN, WIDTH//2 - 160, HEIGHT - 40)
        else:
            draw_text("Type a letter, ESC to return", FONT, GRAY, SCREEN, 10, HEIGHT - 40)

        pygame.display.flip()

    def run(self):
        while True:
            self.draw()
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        return
                    if self.game_over:
                        return
                    if event.unicode.isalpha():
                        letter = event.unicode.upper()
                        if letter not in self.guessed:
                            self.guessed.add(letter)
                            if letter not in self.word:
                                self.wrong_guesses += 1
                                if self.wrong_guesses >= self.max_wrong:
                                    self.game_over = True
                                    self.won = False
                            else:
                                # Check if all letters guessed
                                if all(ch in self.guessed for ch in self.word):
                                    self.game_over = True
                                    self.won = True
            CLOCK.tick(30)

# ----------- GAME 4: Pong -----------

class Pong:
    def __init__(self):
        self.width, self.height = WIDTH, HEIGHT
        self.ball_radius = 10
        self.ball_pos = [self.width // 2, self.height // 2]
        self.ball_vel = [random.choice([-4, 4]), random.choice([-3, 3])]

        self.paddle_width, self.paddle_height = 10, 100
        self.paddle_speed = 7

        self.left_paddle_pos = [10, self.height // 2 - self.paddle_height // 2]
        self.right_paddle_pos = [self.width - 20, self.height // 2 - self.paddle_height // 2]

        self.left_score = 0
        self.right_score = 0
        self.max_score = 10

        self.running = True
        self.mode = None  # 'single' or 'two'
        self.difficulty = None  # 'Easy', 'Medium', 'Hard'

    def draw(self):
        SCREEN.fill(BLACK)
        # Draw ball
        pygame.draw.circle(SCREEN, WHITE, self.ball_pos, self.ball_radius)
        # Draw paddles
        pygame.draw.rect(SCREEN, WHITE, (self.left_paddle_pos[0], self.left_paddle_pos[1], self.paddle_width, self.paddle_height))
        pygame.draw.rect(SCREEN, WHITE, (self.right_paddle_pos[0], self.right_paddle_pos[1], self.paddle_width, self.paddle_height))
        # Draw scores
        draw_text(f"{self.left_score}", BIG_FONT, WHITE, SCREEN, self.width//4, 20)
        draw_text(f"{self.right_score}", BIG_FONT, WHITE, SCREEN, self.width*3//4, 20)
        # Draw mode and difficulty info
        if self.mode == 'single':
            draw_text(f"Mode: VS Computer ({self.difficulty})", FONT, GRAY, SCREEN, 10, self.height - 30)
        else:
            draw_text("Mode: Two Player", FONT, GRAY, SCREEN, 10, self.height - 30)
        draw_text("W/S for Left Paddle", FONT, GRAY, SCREEN, 10, self.height - 60)
        if self.mode == 'two':
            draw_text("Up/Down for Right Paddle", FONT, GRAY, SCREEN, 10, self.height - 90)
        draw_text("ESC to return to menu", FONT, GRAY, SCREEN, self.width - 230, self.height - 30)

        pygame.display.flip()

    def reset_ball(self):
        self.ball_pos = [self.width // 2, self.height // 2]
        self.ball_vel = [random.choice([-4, 4]), random.choice([-3, 3])]

    def choose_mode(self):
        choosing = True
        selected = 0
        options = ["VS Computer", "Two Player"]
        while choosing:
            SCREEN.fill(BLACK)
            draw_text("Choose Pong Mode", BIG_FONT, WHITE, SCREEN, self.width // 2 - 170, self.height // 3)
            for i, option in enumerate(options):
                color = GREEN if i == selected else WHITE
                draw_text(option, FONT, color, SCREEN, self.width // 2 - 80, self.height // 2 + i * 40)
            draw_text("Use UP/DOWN to choose, ENTER to select", FONT, GRAY, SCREEN, self.width // 2 - 160, self.height - 50)
            pygame.display.flip()

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_UP:
                        selected = (selected - 1) % len(options)
                    elif event.key == pygame.K_DOWN:
                        selected = (selected + 1) % len(options)
                    elif event.key == pygame.K_RETURN:
                        self.mode = 'single' if selected == 0 else 'two'
                        choosing = False
                    elif event.key == pygame.K_ESCAPE:
                        return False
            CLOCK.tick(30)
        return True

    def choose_difficulty(self):
        choosing = True
        selected = 0
        options = ["Easy", "Medium", "Hard"]
        while choosing:
            SCREEN.fill(BLACK)
            draw_text("Choose Difficulty", BIG_FONT, WHITE, SCREEN, self.width // 2 - 150, self.height // 3)
            for i, option in enumerate(options):
                color = GREEN if i == selected else WHITE
                draw_text(option, FONT, color, SCREEN, self.width // 2 - 50, self.height // 2 + i * 40)
            draw_text("Use UP/DOWN to choose, ENTER to select", FONT, GRAY, SCREEN, self.width // 2 - 160, self.height - 50)
            pygame.display.flip()

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_UP:
                        selected = (selected - 1) % len(options)
                    elif event.key == pygame.K_DOWN:
                        selected = (selected + 1) % len(options)
                    elif event.key == pygame.K_RETURN:
                        self.difficulty = options[selected]
                        choosing = False
                    elif event.key == pygame.K_ESCAPE:
                        return False
            CLOCK.tick(30)
        return True

    def run(self):
        if not self.choose_mode():
            return  # back to menu if escape pressed during mode choose
        if self.mode == 'single':
            if not self.choose_difficulty():
                return  # back to menu if escape pressed during difficulty choose

        while self.running:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        return

            keys = pygame.key.get_pressed()

            # Left paddle controls (W/S)
            if keys[pygame.K_w] and self.left_paddle_pos[1] > 0:
                self.left_paddle_pos[1] -= self.paddle_speed
            if keys[pygame.K_s] and self.left_paddle_pos[1] < self.height - self.paddle_height:
                self.left_paddle_pos[1] += self.paddle_speed

            # Right paddle controls
            if self.mode == 'two':
                if keys[pygame.K_UP] and self.right_paddle_pos[1] > 0:
                    self.right_paddle_pos[1] -= self.paddle_speed
                if keys[pygame.K_DOWN] and self.right_paddle_pos[1] < self.height - self.paddle_height:
                    self.right_paddle_pos[1] += self.paddle_speed
            else:  # VS Computer AI
                # Set AI paddle speed based on difficulty
                if self.difficulty == 'Easy':
                    ai_speed = 3
                elif self.difficulty == 'Medium':
                    ai_speed = 5
                else:  # Hard
                    ai_speed = 8

                # Simple AI: move paddle towards the ball (with limited speed)
                if self.right_paddle_pos[1] + self.paddle_height/2 < self.ball_pos[1]:
                    self.right_paddle_pos[1] += ai_speed
                elif self.right_paddle_pos[1] + self.paddle_height/2 > self.ball_pos[1]:
                    self.right_paddle_pos[1] -= ai_speed

                # Keep paddle on screen
                if self.right_paddle_pos[1] < 0:
                    self.right_paddle_pos[1] = 0
                if self.right_paddle_pos[1] > self.height - self.paddle_height:
                    self.right_paddle_pos[1] = self.height - self.paddle_height

            # Move ball
            self.ball_pos[0] += self.ball_vel[0]
            self.ball_pos[1] += self.ball_vel[1]

            # Ball collision with top/bottom walls
            if self.ball_pos[1] - self.ball_radius <= 0 or self.ball_pos[1] + self.ball_radius >= self.height:
                self.ball_vel[1] = -self.ball_vel[1]

            # Ball collision with paddles
            # Left paddle
            if (self.ball_pos[0] - self.ball_radius <= self.left_paddle_pos[0] + self.paddle_width and
                self.left_paddle_pos[1] <= self.ball_pos[1] <= self.left_paddle_pos[1] + self.paddle_height):
                self.ball_vel[0] = -self.ball_vel[0]
                self.ball_vel[1] += random.choice([-1, 0, 1])

            # Right paddle
            if (self.ball_pos[0] + self.ball_radius >= self.right_paddle_pos[0] and
                self.right_paddle_pos[1] <= self.ball_pos[1] <= self.right_paddle_pos[1] + self.paddle_height):
                self.ball_vel[0] = -self.ball_vel[0]
                self.ball_vel[1] += random.choice([-1, 0, 1])

            # Check if someone scored
            if self.ball_pos[0] < 0:
                self.right_score += 1
                self.reset_ball()
            elif self.ball_pos[0] > self.width:
                self.left_score += 1
                self.reset_ball()

            # Check if max score reached
            if self.left_score >= self.max_score or self.right_score >= self.max_score:
                winner = "Left Player" if self.left_score > self.right_score else "Right Player"
                if self.mode == 'single' and winner == "Right Player":
                    winner = "Computer"
                SCREEN.fill(BLACK)
                draw_text(f"{winner} Wins!", BIG_FONT, GREEN, SCREEN, self.width // 2 - 150, self.height // 2 - 50)
                draw_text("Press any key to return to menu", FONT, GRAY, SCREEN, self.width // 2 - 160, self.height // 2 + 50)
                pygame.display.flip()
                waiting = True
                while waiting:
                    for event in pygame.event.get():
                        if event.type == pygame.QUIT:
                            pygame.quit()
                            sys.exit()
                        elif event.type == pygame.KEYDOWN:
                            waiting = False
                return

            self.draw()
            CLOCK.tick(60)



# ----------- GAME 5: Breakout -----------

class Breakout:
    def __init__(self):
        self.paddle_width = 100
        self.paddle_height = 15
        self.ball_radius = 10
        self.paddle_x = WIDTH // 2 - self.paddle_width // 2
        self.paddle_y = HEIGHT - 50
        self.ball_x = WIDTH // 2
        self.ball_y = HEIGHT - 70
        self.ball_speed_x = 5 * random.choice([-1, 1])
        self.ball_speed_y = -5
        self.bricks = []
        self.rows = 6
        self.cols = 10
        self.brick_width = WIDTH // self.cols
        self.brick_height = 30
        self.score = 0
        self.lives = 3
        self.create_bricks()
        self.game_over = False

    def create_bricks(self):
        self.bricks.clear()
        for row in range(self.rows):
            for col in range(self.cols):
                rect = pygame.Rect(col*self.brick_width, row*self.brick_height + 60, self.brick_width-2, self.brick_height-2)
                self.bricks.append(rect)

    def draw(self):
        SCREEN.fill(BLACK)
        # Paddle
        pygame.draw.rect(SCREEN, BLUE, (self.paddle_x, self.paddle_y, self.paddle_width, self.paddle_height))
        # Ball
        pygame.draw.circle(SCREEN, WHITE, (int(self.ball_x), int(self.ball_y)), self.ball_radius)
        # Bricks
        for brick in self.bricks:
            pygame.draw.rect(SCREEN, ORANGE, brick)

        draw_text(f"Score: {self.score}", FONT, WHITE, SCREEN, 10, 10)
        draw_text(f"Lives: {self.lives}", FONT, WHITE, SCREEN, WIDTH - 120, 10)
        draw_text("ESC to return to menu", FONT, GRAY, SCREEN, 10, HEIGHT - 30)

        pygame.display.flip()

    def run(self):
        while not self.game_over:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        self.game_over = True

            keys = pygame.key.get_pressed()
            if keys[pygame.K_LEFT]:
                self.paddle_x -= 10
            if keys[pygame.K_RIGHT]:
                self.paddle_x += 10

            self.paddle_x = max(0, min(WIDTH - self.paddle_width, self.paddle_x))

            # Move ball
            self.ball_x += self.ball_speed_x
            self.ball_y += self.ball_speed_y

            # Wall collisions
            if self.ball_x <= self.ball_radius or self.ball_x >= WIDTH - self.ball_radius:
                self.ball_speed_x = -self.ball_speed_x
            if self.ball_y <= self.ball_radius:
                self.ball_speed_y = -self.ball_speed_y

            # Paddle collision
            paddle_rect = pygame.Rect(self.paddle_x, self.paddle_y, self.paddle_width, self.paddle_height)
            ball_rect = pygame.Rect(self.ball_x - self.ball_radius, self.ball_y - self.ball_radius,
                                    self.ball_radius*2, self.ball_radius*2)
            if paddle_rect.colliderect(ball_rect) and self.ball_speed_y > 0:
                self.ball_speed_y = -self.ball_speed_y

            # Brick collisions
            hit_index = None
            for i, brick in enumerate(self.bricks):
                if brick.colliderect(ball_rect):
                    hit_index = i
                    break
            if hit_index is not None:
                hit_brick = self.bricks.pop(hit_index)
                self.ball_speed_y = -self.ball_speed_y
                self.score += 10

            # Ball falls below paddle
            if self.ball_y > HEIGHT:
                self.lives -= 1
                if self.lives <= 0:
                    self.game_over = True
                else:
                    self.ball_x = WIDTH // 2
                    self.ball_y = HEIGHT - 70
                    self.ball_speed_x = 5 * random.choice([-1, 1])
                    self.ball_speed_y = -5
                    self.paddle_x = WIDTH // 2 - self.paddle_width // 2

            self.draw()
            CLOCK.tick(60)

        # Game over screen
        SCREEN.fill(BLACK)
        draw_text("Game Over!", BIG_FONT, RED, SCREEN, WIDTH//2 - 120, HEIGHT//2 - 60)
        draw_text(f"Score: {self.score}", BIG_FONT, WHITE, SCREEN, WIDTH//2 - 80, HEIGHT//2)
        draw_text("Press any key to return", FONT, GRAY, SCREEN, WIDTH//2 - 130, HEIGHT//2 + 80)
        pygame.display.flip()
        wait_for_key()

# ----------- GAME 6: Minesweeper -----------

class Minesweeper:
    def __init__(self):
        self.rows = 9
        self.cols = 9
        self.cell_size = 40
        self.mines_count = 10
        self.grid = [[0]*self.cols for _ in range(self.rows)]
        self.revealed = [[False]*self.cols for _ in range(self.rows)]
        self.flags = [[False]*self.cols for _ in range(self.rows)]
        self.game_over = False
        self.win = False
        self.generate_mines()
        self.calculate_numbers()

    def generate_mines(self):
        self.mines = set()
        while len(self.mines) < self.mines_count:
            r = random.randint(0, self.rows - 1)
            c = random.randint(0, self.cols - 1)
            self.mines.add((r, c))

    def calculate_numbers(self):
        for r in range(self.rows):
            for c in range(self.cols):
                if (r, c) in self.mines:
                    self.grid[r][c] = -1
                else:
                    count = 0
                    for dr in [-1, 0, 1]:
                        for dc in [-1, 0, 1]:
                            nr, nc = r + dr, c + dc
                            if 0 <= nr < self.rows and 0 <= nc < self.cols:
                                if (nr, nc) in self.mines:
                                    count += 1
                    self.grid[r][c] = count

    def reveal_cell(self, r, c):
        if self.revealed[r][c] or self.flags[r][c]:
            return
        self.revealed[r][c] = True
        if self.grid[r][c] == -1:
            self.game_over = True
            return
        elif self.grid[r][c] == 0:
            # Reveal neighbors recursively
            for dr in [-1, 0, 1]:
                for dc in [-1, 0, 1]:
                    nr, nc = r + dr, c + dc
                    if 0 <= nr < self.rows and 0 <= nc < self.cols:
                        if not self.revealed[nr][nc]:
                            self.reveal_cell(nr, nc)

    def check_win(self):
        for r in range(self.rows):
            for c in range(self.cols):
                if self.grid[r][c] != -1 and not self.revealed[r][c]:
                    return False
        return True

    def draw(self):
        SCREEN.fill(BLACK)
        # Draw grid
        for r in range(self.rows):
            for c in range(self.cols):
                rect = pygame.Rect(c*self.cell_size + (WIDTH - self.cols*self.cell_size)//2,
                                   r*self.cell_size + 60,
                                   self.cell_size, self.cell_size)
                if self.revealed[r][c]:
                    pygame.draw.rect(SCREEN, GRAY, rect)
                    if self.grid[r][c] > 0:
                        draw_text(str(self.grid[r][c]), FONT, BLUE, SCREEN,
                                  rect.x + self.cell_size//2 - FONT.size(str(self.grid[r][c]))[0]//2,
                                  rect.y + self.cell_size//2 - FONT.size(str(self.grid[r][c]))[1]//2)
                    elif self.grid[r][c] == -1:
                        pygame.draw.circle(SCREEN, RED, rect.center, self.cell_size//3)
                else:
                    pygame.draw.rect(SCREEN, WHITE, rect)
                    if self.flags[r][c]:
                        draw_text("F", FONT, RED, SCREEN,
                                  rect.x + self.cell_size//2 - FONT.size("F")[0]//2,
                                  rect.y + self.cell_size//2 - FONT.size("F")[1]//2)
                pygame.draw.rect(SCREEN, BLACK, rect, 2)

        if self.game_over:
            draw_text("Game Over! Press any key to return", FONT, RED, SCREEN, WIDTH//2 - 180, HEIGHT - 40)
        elif self.win:
            draw_text("You Win! Press any key to return", FONT, GREEN, SCREEN, WIDTH//2 - 160, HEIGHT - 40)
        else:
            draw_text("Left click: Reveal | Right click: Flag | ESC to menu", FONT, GRAY, SCREEN, 10, HEIGHT - 30)

        pygame.display.flip()

    def run(self):
        while True:
            self.draw()
            if self.game_over or self.win:
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        pygame.quit()
                        sys.exit()
                    elif event.type == pygame.KEYDOWN:
                        return
            else:
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        pygame.quit()
                        sys.exit()
                    elif event.type == pygame.KEYDOWN:
                        if event.key == pygame.K_ESCAPE:
                            return
                    elif event.type == pygame.MOUSEBUTTONDOWN:
                        mx, my = pygame.mouse.get_pos()
                        grid_x = (WIDTH - self.cols*self.cell_size)//2
                        grid_y = 60
                        c = (mx - grid_x) // self.cell_size
                        r = (my - grid_y) // self.cell_size
                        if 0 <= r < self.rows and 0 <= c < self.cols:
                            if event.button == 1:  # left click
                                self.reveal_cell(r, c)
                                if self.game_over:
                                    pass
                                elif self.check_win():
                                    self.win = True
                            elif event.button == 3:  # right click
                                if not self.revealed[r][c]:
                                    self.flags[r][c] = not self.flags[r][c]
            CLOCK.tick(30)

# ----------- GAME 7: Text Adventure RPG -----------

class TextAdventure:
    def __init__(self):
        self.state = "start"
        self.text = ""
        self.choices = []
        self.health = 10
        self.enemy_health = 0
        self.running = True
        self.story = {
            "start": {
                "text": "You are in a dark forest. There is a path leading north and a cave to the east.",
                "choices": [("Go North", "north_path"), ("Enter Cave", "cave")]
            },
            "north_path": {
                "text": "You meet a wild wolf! Fight or run?",
                "choices": [("Fight", "fight_wolf"), ("Run", "start")]
            },
            "cave": {
                "text": "The cave is dark and you find a treasure chest!",
                "choices": [("Open chest", "treasure"), ("Leave cave", "start")]
            },
            "fight_wolf": {
                "text": "You fight the wolf!",
                "choices": []
            },
            "treasure": {
                "text": "You find a healing potion and drink it.",
                "choices": [("Continue", "start")]
            },
            "end": {
                "text": "You survived the adventure! Thanks for playing.",
                "choices": []
            }
        }
        self.enemy_health = 6

    def draw(self):
        SCREEN.fill(BLACK)
        y = 40
        draw_text("Text Adventure RPG", BIG_FONT, WHITE, SCREEN, WIDTH//2 - 180, 10)
        lines = self.text.split("\n")
        for line in lines:
            draw_text(line, FONT, GREEN, SCREEN, 40, y)
            y += 30

        for i, (choice_text, _) in enumerate(self.choices):
            draw_text(f"{i+1}. {choice_text}", FONT, WHITE, SCREEN, 60, y)
            y += 30

        draw_text(f"Health: {self.health}", FONT, RED, SCREEN, WIDTH - 150, 10)
        pygame.display.flip()

    def run(self):
        while self.running:
            if self.state == "start":
                self.text = self.story["start"]["text"]
                self.choices = self.story["start"]["choices"]
            elif self.state == "north_path":
                self.text = self.story["north_path"]["text"]
                self.choices = self.story["north_path"]["choices"]
            elif self.state == "cave":
                self.text = self.story["cave"]["text"]
                self.choices = self.story["cave"]["choices"]
            elif self.state == "treasure":
                self.text = self.story["treasure"]["text"]
                self.choices = self.story["treasure"]["choices"]
                self.health = min(self.health + 5, 10)
                self.state = "start"
                continue
            elif self.state == "fight_wolf":
                self.text = "You fight the wolf! Press 1 to attack."
                self.choices = [("Attack", "attack")]
            elif self.state == "attack":
                self.enemy_health -= random.randint(1, 4)
                if self.enemy_health <= 0:
                    self.text = "You defeated the wolf!"
                    self.choices = [("Continue", "end")]
                else:
                    self.health -= random.randint(1, 3)
                    if self.health <= 0:
                        self.text = "You were defeated by the wolf... Game over."
                        self.choices = []
                        self.running = False
                    else:
                        self.text = f"The wolf has {self.enemy_health} health left.\nYour health is {self.health}.\nPress 1 to attack."
                        self.choices = [("Attack", "attack")]
            elif self.state == "end":
                self.text = self.story["end"]["text"]
                self.choices = []
                self.running = False

            self.draw()

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        return
                    elif event.unicode.isdigit():
                        choice_num = int(event.unicode) - 1
                        if 0 <= choice_num < len(self.choices):
                            self.state = self.choices[choice_num][1]
            CLOCK.tick(30)

# ----------- MAIN MENU AND APP STRUCTURE -----------

import pygame
import sys
import random

# Initialize pygame
pygame.init()
WIDTH, HEIGHT = 800, 600
SCREEN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Jaden's Python Games")
CLOCK = pygame.time.Clock()

# Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (120, 120, 120)
RED = (255, 0, 0)
GREEN = (0, 200, 0)
BLUE = (0, 0, 255)
ORANGE = (255, 165, 0)

# Fonts
FONT = pygame.font.SysFont("arial", 24)
BIG_FONT = pygame.font.SysFont("arial", 48)

def draw_text(text, font, color, surface, x, y):
    surface.blit(font.render(text, True, color), (x, y))

def wait_for_key():
    waiting = True
    while waiting:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                waiting = False

class Menu:
    def __init__(self):
        self.options = [
            "Snake",
            "Tic Tac Toe",
            "Pong",
            "Breakout",
            "Minesweeper",
            "Text Adventure RPG",
            "Quit"
        ]
        self.selected = 0

    def draw(self):
        SCREEN.fill(BLACK)
        draw_text("Jaden's Python Games", BIG_FONT, WHITE, SCREEN, WIDTH//2 - 200, 50)
        for i, option in enumerate(self.options):
            color = GREEN if i == self.selected else WHITE
            draw_text(option, FONT, color, SCREEN, WIDTH//2 - 100, 150 + i*40)
        draw_text("Use UP/DOWN to navigate, ENTER to select", FONT, GRAY, SCREEN, WIDTH//2 - 170, HEIGHT - 50)
        pygame.display.flip()

    def run(self):
        running = True
        while running:
            self.draw()
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_UP:
                        self.selected = (self.selected - 1) % len(self.options)
                    elif event.key == pygame.K_DOWN:
                        self.selected = (self.selected + 1) % len(self.options)
                    elif event.key == pygame.K_RETURN:
                        return self.options[self.selected]
            CLOCK.tick(30)

def main():
    menu = Menu()
    while True:
        choice = menu.run()
        if choice == "Quit":
            pygame.quit()
            sys.exit()
        elif choice == "Snake":
            Snake().run()
        elif choice == "Tic Tac Toe":
            TicTacToe().run()
        elif choice == "Pong":
            Pong().run()
        elif choice == "Breakout":
            Breakout().run()
        elif choice == "Minesweeper":
            Minesweeper().run()
        elif choice == "Text Adventure RPG":
            TextAdventure().run()

if __name__ == "__main__":
    main()












































































































































































































#Made by Jaden le Dieu DONT STEAL