Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import os
- import time
- import random
- import threading
- import sys
- from colorama import init, Fore, Back, Style
- # Initialize colorama
- init()
- # Game settings
- WIDTH = 40
- HEIGHT = 20
- #PLAYER_PADDLE_WIDTH = 1
- #OPPONENT_PADDLE_WIDTH = 1
- PLAYER_PADDLE_HEIGHT = 5
- OPPONENT_PADDLE_HEIGHT = 1
- BALL_CHAR = "O"
- PLAYER_PADDLE_CHAR = "█"
- OPPONENT_PADDLE_CHAR = "█"
- REFLECTING_PADDLE_CHAR = "|"
- PREDICTION_CHAR = "+"
- FRAME_RATE = 14 # Frames per second
- NUM_REFLECTING_PADDLES = 4
- MAX_PENALTY_POINTS = 100
- INITIAL_LIVES = 5 # New: Initial number of lives
- # Border characters
- HORIZONTAL_BORDER = "═"
- VERTICAL_BORDER = "║"
- TOP_LEFT_CORNER = "╔"
- TOP_RIGHT_CORNER = "╗"
- BOTTOM_LEFT_CORNER = "╚"
- BOTTOM_RIGHT_CORNER = "╝"
- # Initialize game state
- player_paddle_height = PLAYER_PADDLE_HEIGHT
- opponent_paddle_height = OPPONENT_PADDLE_HEIGHT
- player_pos = HEIGHT // 2 - player_paddle_height // 2
- opponent_pos = HEIGHT // 2 - opponent_paddle_height // 2
- ball_x, ball_y = WIDTH // 2, HEIGHT // 2
- ball_dx, ball_dy = 1, random.choice([-1, 1])
- player_penalty = opponent_penalty = 0
- player_lives = opponent_lives = INITIAL_LIVES # New: Initialize lives
- predicted_y = None
- last_touch = "player" # To track who last touched the ball
- paused = False
- # Initialize reflecting paddles
- class ReflectingPaddle:
- def __init__(self, x):
- self.x = x
- self.y = random.randint(0, HEIGHT - 1)
- self.height = random.randint(3, 8)
- self.direction = random.choice([-1, 1]) # -1 for up, 1 for down
- def move(self):
- self.y += self.direction
- if self.y <= 0 or self.y + self.height >= HEIGHT:
- self.direction *= -1 # Reverse direction when hitting top or bottom
- self.y = max(0, min(self.y, HEIGHT - self.height))
- # Evenly space out the reflecting paddles from the center
- paddle_spacing = WIDTH // (NUM_REFLECTING_PADDLES + 1)
- reflecting_paddles = [ReflectingPaddle(x=(i+1) * paddle_spacing) for i in range(NUM_REFLECTING_PADDLES)]
- # User input variables
- user_input = None
- input_lock = threading.Lock()
- def draw_board():
- board = [[" " for _ in range(WIDTH + 2)] for _ in range(HEIGHT + 2)]
- # Draw borders
- for i in range(WIDTH + 2):
- board[0][i] = Fore.YELLOW + HORIZONTAL_BORDER + Style.RESET_ALL
- board[HEIGHT + 1][i] = Fore.YELLOW + HORIZONTAL_BORDER + Style.RESET_ALL
- for i in range(HEIGHT + 2):
- board[i][0] = Fore.YELLOW + VERTICAL_BORDER + Style.RESET_ALL
- board[i][WIDTH + 1] = Fore.YELLOW + VERTICAL_BORDER + Style.RESET_ALL
- # Draw corners
- board[0][0] = Fore.YELLOW + TOP_LEFT_CORNER + Style.RESET_ALL
- board[0][WIDTH + 1] = Fore.YELLOW + TOP_RIGHT_CORNER + Style.RESET_ALL
- board[HEIGHT + 1][0] = Fore.YELLOW + BOTTOM_LEFT_CORNER + Style.RESET_ALL
- board[HEIGHT + 1][WIDTH + 1] = Fore.YELLOW + BOTTOM_RIGHT_CORNER + Style.RESET_ALL
- # Draw player paddle
- for i in range(player_paddle_height):
- board[player_pos + i + 1][1] = Fore.BLUE + PLAYER_PADDLE_CHAR + Style.RESET_ALL
- # Draw opponent paddle
- for i in range(opponent_paddle_height):
- board[opponent_pos + i + 1][WIDTH] = Fore.RED + OPPONENT_PADDLE_CHAR + Style.RESET_ALL
- # Draw reflecting paddles
- for paddle in reflecting_paddles:
- for i in range(paddle.height):
- if 0 <= paddle.y + i < HEIGHT:
- board[paddle.y + i + 1][paddle.x + 1] = Fore.GREEN + REFLECTING_PADDLE_CHAR + Style.RESET_ALL
- # Draw ball
- ball_x_int, ball_y_int = int(ball_x), int(ball_y)
- if 0 <= ball_x_int < WIDTH and 0 <= ball_y_int < HEIGHT:
- board[ball_y_int + 1][ball_x_int + 1] = Fore.RED + Back.BLACK + BALL_CHAR + Style.RESET_ALL
- # Draw prediction
- if predicted_y is not None and 0 <= predicted_y < HEIGHT:
- board[predicted_y + 1][WIDTH+1] = Fore.MAGENTA + PREDICTION_CHAR + Style.RESET_ALL
- # Draw scores and lives
- score_text = f"P:{player_penalty}({player_lives}❤️) - O:{opponent_penalty}({opponent_lives}❤️)"
- score_pos = WIDTH // 2 - len(score_text) // 2
- for i, char in enumerate(score_text):
- board[0][score_pos + i + 1] = Fore.CYAN + char + Style.RESET_ALL
- return "\n".join("".join(row) for row in board)
- def predict_ball_position(ball_x, ball_y, ball_dx, ball_dy):
- time_to_reach = (WIDTH - 1 - ball_x) / ball_dx
- predicted_y = ball_y + ball_dy * time_to_reach
- while predicted_y < 0 or predicted_y >= HEIGHT:
- if predicted_y < 0:
- predicted_y = -predicted_y
- elif predicted_y >= HEIGHT:
- predicted_y = 2 * (HEIGHT - 1) - predicted_y
- return int(predicted_y)
- def move_opponent_paddle(current_pos, target_y):
- # Check if moving towards target_y would result in hitting a reflecting paddle
- for paddle in reflecting_paddles:
- if WIDTH - 2 <= paddle.x <= WIDTH and paddle.y <= target_y < paddle.y + paddle.height:
- # Avoid the paddle by moving in the opposite direction
- if current_pos < target_y:
- return max(current_pos - 1, 0)
- elif current_pos > target_y:
- return min(current_pos + 1, HEIGHT - opponent_paddle_height)
- return current_pos
- # If no paddle interference, move towards the target
- if current_pos < target_y:
- return min(current_pos + 1, HEIGHT - opponent_paddle_height)
- elif current_pos > target_y:
- return max(current_pos - 1, 0)
- return current_pos
- def move_ball():
- global ball_x, ball_y, ball_dx, ball_dy, player_penalty, opponent_penalty, last_touch, player_lives, opponent_lives
- ball_x += ball_dx
- ball_y += ball_dy
- # Bounce off top and bottom
- if ball_y <= 0 or ball_y >= HEIGHT - 1:
- ball_dy = -ball_dy
- # Bounce off player paddle
- if ball_x <= 1 and player_pos <= ball_y < player_pos + player_paddle_height:
- ball_x = 1
- ball_dx = abs(ball_dx)
- paddle_center = player_pos + player_paddle_height / 2
- ball_dy += (ball_y - paddle_center) / (player_paddle_height / 2) * 0.5
- ball_dy = max(min(ball_dy, 1.5), -1.5)
- last_touch = "player"
- # Bounce off opponent paddle
- elif ball_x >= WIDTH - 2 and opponent_pos <= ball_y < opponent_pos + opponent_paddle_height:
- ball_x = WIDTH - 2
- ball_dx = -abs(ball_dx)
- paddle_center = opponent_pos + opponent_paddle_height / 2
- ball_dy += (ball_y - paddle_center) / (opponent_paddle_height / 2) * 0.5
- ball_dy = max(min(ball_dy, 1.5), -1.5)
- last_touch = "opponent"
- # Bounce off reflecting paddles
- for paddle in reflecting_paddles:
- if (paddle.x - 1 <= ball_x <= paddle.x + 1) and (paddle.y <= ball_y < paddle.y + paddle.height):
- ball_dx = -ball_dx
- if ball_x < paddle.x:
- ball_x = paddle.x - 1
- else:
- ball_x = paddle.x + 1
- paddle_center = paddle.y + paddle.height / 2
- ball_dy += (ball_y - paddle_center) / (paddle.height / 2) * 0.5
- ball_dy = max(min(ball_dy, 1.5), -1.5)
- # Apply penalty to the last player who touched the ball
- if last_touch == "player":
- player_penalty += 1
- else:
- opponent_penalty += 1
- break
- # Score penalty points and reduce lives
- if ball_x < 0:
- player_penalty += 10
- player_lives -= 1 # New: Reduce player lives
- ball_x, ball_y = WIDTH // 2, HEIGHT // 2
- ball_dx, ball_dy = 1, random.choice([-1, 1])
- last_touch = "player"
- elif ball_x >= WIDTH:
- opponent_penalty += 10
- opponent_lives -= 1 # New: Reduce opponent lives
- ball_x, ball_y = WIDTH // 2, HEIGHT // 2
- ball_dx, ball_dy = -1, random.choice([-1, 1])
- last_touch = "opponent"
- def get_user_input():
- global user_input
- while True:
- key = sys.stdin.read(1)
- with input_lock:
- user_input = key
- if key == 'q':
- break
- def has_line_of_sight(ball_x, ball_y):
- for paddle in reflecting_paddles:
- if paddle.x > ball_x and paddle.y <= ball_y < paddle.y + paddle.height:
- return False
- return True
- def main():
- global player_pos, opponent_pos, user_input, predicted_y, paused
- input_thread = threading.Thread(target=get_user_input, daemon=True)
- input_thread.start()
- last_seen_ball_y = HEIGHT // 2
- last_seen_ball_dy = 0
- last_draw = ""
- while player_lives > 0 and opponent_lives > 0 and player_penalty < MAX_PENALTY_POINTS and opponent_penalty < MAX_PENALTY_POINTS:
- current_draw = draw_board()
- if not paused or current_draw != last_draw:
- os.system('cls' if os.name == 'nt' else 'clear')
- print(current_draw)
- print(f"\n{Fore.CYAN}Use 'w' to move up, 's' to move down, 'p' to pause/unpause, 'q' to quit{Style.RESET_ALL}")
- print(f"{Fore.YELLOW}Player paddle height: {player_paddle_height}, Opponent paddle height: {opponent_paddle_height}{Style.RESET_ALL}")
- print(f"{Fore.MAGENTA}Game will end when a player reaches {MAX_PENALTY_POINTS} penalty points or loses all lives.{Style.RESET_ALL}")
- if paused:
- print(f"{Fore.RED}Game is paused. Press 'p' to unpause.{Style.RESET_ALL}")
- last_draw = current_draw
- if not paused:
- move_ball()
- # Move reflecting paddles
- for paddle in reflecting_paddles:
- paddle.move()
- # Handle user input for player paddle
- with input_lock:
- if user_input == 'w' and player_pos > 0:
- player_pos = max(player_pos - 3, 0) # Move up 3, but not above the top
- elif user_input == 's' and player_pos < HEIGHT - player_paddle_height:
- player_pos = min(player_pos + 3, HEIGHT - player_paddle_height) # Move down 3, but not below the bottom
- elif user_input == 'p':
- paused = not paused # Toggle pause state
- elif user_input == 'q':
- break
- user_input = None
- if not paused:
- # AI for opponent paddle
- if ball_dx > 0 and has_line_of_sight(ball_x, ball_y):
- predicted_y = predict_ball_position(ball_x, ball_y, ball_dx, ball_dy)
- last_seen_ball_y = ball_y
- last_seen_ball_dy = ball_dy
- else:
- predicted_y = None
- # If no line of sight, move towards the last seen ball position
- last_seen_ball_y += last_seen_ball_dy
- if last_seen_ball_y <= 0 or last_seen_ball_y >= HEIGHT - 1:
- last_seen_ball_dy = -last_seen_ball_dy
- last_seen_ball_y = max(0, min(last_seen_ball_y, HEIGHT - 1))
- target_y = predicted_y - opponent_paddle_height // 2 if predicted_y is not None else last_seen_ball_y - opponent_paddle_height // 2
- opponent_pos = move_opponent_paddle(opponent_pos, target_y)
- time.sleep(1 / FRAME_RATE)
- os.system('cls' if os.name == 'nt' else 'clear')
- print(draw_board())
- if player_lives <= 0:
- winner = "Opponent"
- elif opponent_lives <= 0:
- winner = "Player"
- elif player_penalty >= MAX_PENALTY_POINTS:
- winner = "Opponent"
- else:
- winner = "Player"
- print(f"\n{Fore.GREEN}Game Over! {winner} wins!{Style.RESET_ALL}")
- if __name__ == "__main__":
- import tty, termios
- old_settings = termios.tcgetattr(sys.stdin)
- try:
- tty.setcbreak(sys.stdin.fileno())
- main()
- finally:
- termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement