Advertisement
Guest User

ASCII Pong by Claude Sonnet 3.5

a guest
Jun 26th, 2024
347
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.66 KB | Software | 0 0
  1. import os
  2. import time
  3. import random
  4. import threading
  5. import sys
  6. from colorama import init, Fore, Back, Style
  7.  
  8. # Initialize colorama
  9. init()
  10.  
  11. # Game settings
  12. WIDTH = 40
  13. HEIGHT = 20
  14. #PLAYER_PADDLE_WIDTH = 1
  15. #OPPONENT_PADDLE_WIDTH = 1
  16. PLAYER_PADDLE_HEIGHT = 5
  17. OPPONENT_PADDLE_HEIGHT = 1
  18. BALL_CHAR = "O"
  19. PLAYER_PADDLE_CHAR = "█"
  20. OPPONENT_PADDLE_CHAR = "█"
  21. REFLECTING_PADDLE_CHAR = "|"
  22. PREDICTION_CHAR = "+"
  23. FRAME_RATE = 14  # Frames per second
  24. NUM_REFLECTING_PADDLES = 4
  25. MAX_PENALTY_POINTS = 100
  26. INITIAL_LIVES = 5  # New: Initial number of lives
  27.  
  28. # Border characters
  29. HORIZONTAL_BORDER = "═"
  30. VERTICAL_BORDER = "║"
  31. TOP_LEFT_CORNER = "╔"
  32. TOP_RIGHT_CORNER = "╗"
  33. BOTTOM_LEFT_CORNER = "╚"
  34. BOTTOM_RIGHT_CORNER = "╝"
  35.  
  36. # Initialize game state
  37. player_paddle_height = PLAYER_PADDLE_HEIGHT
  38. opponent_paddle_height = OPPONENT_PADDLE_HEIGHT
  39. player_pos = HEIGHT // 2 - player_paddle_height // 2
  40. opponent_pos = HEIGHT // 2 - opponent_paddle_height // 2
  41. ball_x, ball_y = WIDTH // 2, HEIGHT // 2
  42. ball_dx, ball_dy = 1, random.choice([-1, 1])
  43. player_penalty = opponent_penalty = 0
  44. player_lives = opponent_lives = INITIAL_LIVES  # New: Initialize lives
  45. predicted_y = None
  46. last_touch = "player"  # To track who last touched the ball
  47. paused = False
  48.  
  49. # Initialize reflecting paddles
  50. class ReflectingPaddle:
  51.     def __init__(self, x):
  52.         self.x = x
  53.         self.y = random.randint(0, HEIGHT - 1)
  54.         self.height = random.randint(3, 8)
  55.         self.direction = random.choice([-1, 1])  # -1 for up, 1 for down
  56.  
  57.     def move(self):
  58.         self.y += self.direction
  59.         if self.y <= 0 or self.y + self.height >= HEIGHT:
  60.             self.direction *= -1  # Reverse direction when hitting top or bottom
  61.         self.y = max(0, min(self.y, HEIGHT - self.height))
  62.  
  63. # Evenly space out the reflecting paddles from the center
  64. paddle_spacing = WIDTH // (NUM_REFLECTING_PADDLES + 1)
  65. reflecting_paddles = [ReflectingPaddle(x=(i+1) * paddle_spacing) for i in range(NUM_REFLECTING_PADDLES)]
  66.  
  67. # User input variables
  68. user_input = None
  69. input_lock = threading.Lock()
  70.  
  71. def draw_board():
  72.     board = [[" " for _ in range(WIDTH + 2)] for _ in range(HEIGHT + 2)]
  73.  
  74.     # Draw borders
  75.     for i in range(WIDTH + 2):
  76.         board[0][i] = Fore.YELLOW + HORIZONTAL_BORDER + Style.RESET_ALL
  77.         board[HEIGHT + 1][i] = Fore.YELLOW + HORIZONTAL_BORDER + Style.RESET_ALL
  78.     for i in range(HEIGHT + 2):
  79.         board[i][0] = Fore.YELLOW + VERTICAL_BORDER + Style.RESET_ALL
  80.         board[i][WIDTH + 1] = Fore.YELLOW + VERTICAL_BORDER + Style.RESET_ALL
  81.  
  82.     # Draw corners
  83.     board[0][0] = Fore.YELLOW + TOP_LEFT_CORNER + Style.RESET_ALL
  84.     board[0][WIDTH + 1] = Fore.YELLOW + TOP_RIGHT_CORNER + Style.RESET_ALL
  85.     board[HEIGHT + 1][0] = Fore.YELLOW + BOTTOM_LEFT_CORNER + Style.RESET_ALL
  86.     board[HEIGHT + 1][WIDTH + 1] = Fore.YELLOW + BOTTOM_RIGHT_CORNER + Style.RESET_ALL
  87.  
  88.     # Draw player paddle
  89.     for i in range(player_paddle_height):
  90.         board[player_pos + i + 1][1] = Fore.BLUE + PLAYER_PADDLE_CHAR + Style.RESET_ALL
  91.  
  92.     # Draw opponent paddle
  93.     for i in range(opponent_paddle_height):
  94.         board[opponent_pos + i + 1][WIDTH] = Fore.RED + OPPONENT_PADDLE_CHAR + Style.RESET_ALL
  95.  
  96.     # Draw reflecting paddles
  97.     for paddle in reflecting_paddles:
  98.         for i in range(paddle.height):
  99.             if 0 <= paddle.y + i < HEIGHT:
  100.                 board[paddle.y + i + 1][paddle.x + 1] = Fore.GREEN + REFLECTING_PADDLE_CHAR + Style.RESET_ALL
  101.  
  102.     # Draw ball
  103.     ball_x_int, ball_y_int = int(ball_x), int(ball_y)
  104.     if 0 <= ball_x_int < WIDTH and 0 <= ball_y_int < HEIGHT:
  105.         board[ball_y_int + 1][ball_x_int + 1] = Fore.RED + Back.BLACK + BALL_CHAR + Style.RESET_ALL
  106.  
  107.     # Draw prediction
  108.     if predicted_y is not None and 0 <= predicted_y < HEIGHT:
  109.         board[predicted_y + 1][WIDTH+1] = Fore.MAGENTA + PREDICTION_CHAR + Style.RESET_ALL
  110.  
  111.     # Draw scores and lives
  112.     score_text = f"P:{player_penalty}({player_lives}❤️) - O:{opponent_penalty}({opponent_lives}❤️)"
  113.     score_pos = WIDTH // 2 - len(score_text) // 2
  114.     for i, char in enumerate(score_text):
  115.         board[0][score_pos + i + 1] = Fore.CYAN + char + Style.RESET_ALL
  116.  
  117.     return "\n".join("".join(row) for row in board)
  118.  
  119. def predict_ball_position(ball_x, ball_y, ball_dx, ball_dy):
  120.     time_to_reach = (WIDTH - 1 - ball_x) / ball_dx
  121.     predicted_y = ball_y + ball_dy * time_to_reach
  122.  
  123.     while predicted_y < 0 or predicted_y >= HEIGHT:
  124.         if predicted_y < 0:
  125.             predicted_y = -predicted_y
  126.         elif predicted_y >= HEIGHT:
  127.             predicted_y = 2 * (HEIGHT - 1) - predicted_y
  128.  
  129.     return int(predicted_y)
  130.  
  131. def move_opponent_paddle(current_pos, target_y):
  132.     # Check if moving towards target_y would result in hitting a reflecting paddle
  133.     for paddle in reflecting_paddles:
  134.         if WIDTH - 2 <= paddle.x <= WIDTH and paddle.y <= target_y < paddle.y + paddle.height:
  135.             # Avoid the paddle by moving in the opposite direction
  136.             if current_pos < target_y:
  137.                 return max(current_pos - 1, 0)
  138.             elif current_pos > target_y:
  139.                 return min(current_pos + 1, HEIGHT - opponent_paddle_height)
  140.             return current_pos
  141.  
  142.     # If no paddle interference, move towards the target
  143.     if current_pos < target_y:
  144.         return min(current_pos + 1, HEIGHT - opponent_paddle_height)
  145.     elif current_pos > target_y:
  146.         return max(current_pos - 1, 0)
  147.     return current_pos
  148.  
  149. def move_ball():
  150.     global ball_x, ball_y, ball_dx, ball_dy, player_penalty, opponent_penalty, last_touch, player_lives, opponent_lives
  151.  
  152.     ball_x += ball_dx
  153.     ball_y += ball_dy
  154.  
  155.     # Bounce off top and bottom
  156.     if ball_y <= 0 or ball_y >= HEIGHT - 1:
  157.         ball_dy = -ball_dy
  158.  
  159.     # Bounce off player paddle
  160.     if ball_x <= 1 and player_pos <= ball_y < player_pos + player_paddle_height:
  161.         ball_x = 1
  162.         ball_dx = abs(ball_dx)
  163.         paddle_center = player_pos + player_paddle_height / 2
  164.         ball_dy += (ball_y - paddle_center) / (player_paddle_height / 2) * 0.5
  165.         ball_dy = max(min(ball_dy, 1.5), -1.5)
  166.         last_touch = "player"
  167.  
  168.     # Bounce off opponent paddle
  169.     elif ball_x >= WIDTH - 2 and opponent_pos <= ball_y < opponent_pos + opponent_paddle_height:
  170.         ball_x = WIDTH - 2
  171.         ball_dx = -abs(ball_dx)
  172.         paddle_center = opponent_pos + opponent_paddle_height / 2
  173.         ball_dy += (ball_y - paddle_center) / (opponent_paddle_height / 2) * 0.5
  174.         ball_dy = max(min(ball_dy, 1.5), -1.5)
  175.         last_touch = "opponent"
  176.  
  177.     # Bounce off reflecting paddles
  178.     for paddle in reflecting_paddles:
  179.         if (paddle.x - 1 <= ball_x <= paddle.x + 1) and (paddle.y <= ball_y < paddle.y + paddle.height):
  180.             ball_dx = -ball_dx
  181.             if ball_x < paddle.x:
  182.                 ball_x = paddle.x - 1
  183.             else:
  184.                 ball_x = paddle.x + 1
  185.             paddle_center = paddle.y + paddle.height / 2
  186.             ball_dy += (ball_y - paddle_center) / (paddle.height / 2) * 0.5
  187.             ball_dy = max(min(ball_dy, 1.5), -1.5)
  188.  
  189.             # Apply penalty to the last player who touched the ball
  190.             if last_touch == "player":
  191.                 player_penalty += 1
  192.             else:
  193.                 opponent_penalty += 1
  194.             break
  195.  
  196.     # Score penalty points and reduce lives
  197.     if ball_x < 0:
  198.         player_penalty += 10
  199.         player_lives -= 1  # New: Reduce player lives
  200.         ball_x, ball_y = WIDTH // 2, HEIGHT // 2
  201.         ball_dx, ball_dy = 1, random.choice([-1, 1])
  202.         last_touch = "player"
  203.     elif ball_x >= WIDTH:
  204.         opponent_penalty += 10
  205.         opponent_lives -= 1  # New: Reduce opponent lives
  206.         ball_x, ball_y = WIDTH // 2, HEIGHT // 2
  207.         ball_dx, ball_dy = -1, random.choice([-1, 1])
  208.         last_touch = "opponent"
  209.  
  210. def get_user_input():
  211.     global user_input
  212.     while True:
  213.         key = sys.stdin.read(1)
  214.         with input_lock:
  215.             user_input = key
  216.         if key == 'q':
  217.             break
  218.  
  219. def has_line_of_sight(ball_x, ball_y):
  220.     for paddle in reflecting_paddles:
  221.         if paddle.x > ball_x and paddle.y <= ball_y < paddle.y + paddle.height:
  222.             return False
  223.     return True
  224.  
  225. def main():
  226.     global player_pos, opponent_pos, user_input, predicted_y, paused
  227.  
  228.     input_thread = threading.Thread(target=get_user_input, daemon=True)
  229.     input_thread.start()
  230.  
  231.     last_seen_ball_y = HEIGHT // 2
  232.     last_seen_ball_dy = 0
  233.     last_draw = ""
  234.  
  235.     while player_lives > 0 and opponent_lives > 0 and player_penalty < MAX_PENALTY_POINTS and opponent_penalty < MAX_PENALTY_POINTS:
  236.         current_draw = draw_board()
  237.         if not paused or current_draw != last_draw:
  238.             os.system('cls' if os.name == 'nt' else 'clear')
  239.             print(current_draw)
  240.             print(f"\n{Fore.CYAN}Use 'w' to move up, 's' to move down, 'p' to pause/unpause, 'q' to quit{Style.RESET_ALL}")
  241.             print(f"{Fore.YELLOW}Player paddle height: {player_paddle_height}, Opponent paddle height: {opponent_paddle_height}{Style.RESET_ALL}")
  242.             print(f"{Fore.MAGENTA}Game will end when a player reaches {MAX_PENALTY_POINTS} penalty points or loses all lives.{Style.RESET_ALL}")
  243.             if paused:
  244.                 print(f"{Fore.RED}Game is paused. Press 'p' to unpause.{Style.RESET_ALL}")
  245.             last_draw = current_draw
  246.  
  247.         if not paused:
  248.             move_ball()
  249.  
  250.             # Move reflecting paddles
  251.             for paddle in reflecting_paddles:
  252.                 paddle.move()
  253.  
  254.         # Handle user input for player paddle
  255.         with input_lock:
  256.             if user_input == 'w' and player_pos > 0:
  257.                 player_pos = max(player_pos - 3, 0)  # Move up 3, but not above the top
  258.             elif user_input == 's' and player_pos < HEIGHT - player_paddle_height:
  259.                 player_pos = min(player_pos + 3, HEIGHT - player_paddle_height)  # Move down 3, but not below the bottom
  260.             elif user_input == 'p':
  261.                 paused = not paused  # Toggle pause state
  262.             elif user_input == 'q':
  263.                 break
  264.             user_input = None
  265.  
  266.         if not paused:
  267.             # AI for opponent paddle
  268.             if ball_dx > 0 and has_line_of_sight(ball_x, ball_y):
  269.                 predicted_y = predict_ball_position(ball_x, ball_y, ball_dx, ball_dy)
  270.                 last_seen_ball_y = ball_y
  271.                 last_seen_ball_dy = ball_dy
  272.             else:
  273.                 predicted_y = None
  274.                 # If no line of sight, move towards the last seen ball position
  275.                 last_seen_ball_y += last_seen_ball_dy
  276.                 if last_seen_ball_y <= 0 or last_seen_ball_y >= HEIGHT - 1:
  277.                     last_seen_ball_dy = -last_seen_ball_dy
  278.                 last_seen_ball_y = max(0, min(last_seen_ball_y, HEIGHT - 1))
  279.  
  280.             target_y = predicted_y - opponent_paddle_height // 2 if predicted_y is not None else last_seen_ball_y - opponent_paddle_height // 2
  281.             opponent_pos = move_opponent_paddle(opponent_pos, target_y)
  282.  
  283.         time.sleep(1 / FRAME_RATE)
  284.  
  285.     os.system('cls' if os.name == 'nt' else 'clear')
  286.     print(draw_board())
  287.     if player_lives <= 0:
  288.         winner = "Opponent"
  289.     elif opponent_lives <= 0:
  290.         winner = "Player"
  291.     elif player_penalty >= MAX_PENALTY_POINTS:
  292.         winner = "Opponent"
  293.     else:
  294.         winner = "Player"
  295.     print(f"\n{Fore.GREEN}Game Over! {winner} wins!{Style.RESET_ALL}")
  296.  
  297. if __name__ == "__main__":
  298.     import tty, termios
  299.     old_settings = termios.tcgetattr(sys.stdin)
  300.     try:
  301.         tty.setcbreak(sys.stdin.fileno())
  302.         main()
  303.     finally:
  304.         termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement