| | import pygame
|
| | import math
|
| | import random
|
| | import numpy as np
|
| | import time
|
| |
|
| |
|
| | WIDTH, HEIGHT = 800, 600
|
| | WHITE = (255, 255, 255)
|
| | RED = (255, 0, 0)
|
| | BROWN = (139, 69, 19)
|
| |
|
| |
|
| | terrain_height = 50
|
| | terrain_points = [terrain_height + random.randint(5, 15) for _ in range(WIDTH // 50)]
|
| | terrain = np.interp(range(WIDTH), np.linspace(0, WIDTH, len(terrain_points)), terrain_points)
|
| |
|
| |
|
| | class Rocket:
|
| | def __init__(self):
|
| |
|
| | self.width = 40
|
| | self.height = 80
|
| | self.x = WIDTH // 2
|
| | self.y = HEIGHT // 2
|
| | self.angle = 0
|
| | self.velocity_x = 0
|
| | self.velocity_y = 0
|
| | self.gravity = 10
|
| | self.thrust_power = 30
|
| | self.angular_velocity = 0
|
| | self.thrusting = False
|
| | self.rotation_speed = 1
|
| |
|
| | def update(self, thrusting, rotate_left, rotate_right, time_step=0.1):
|
| | """Update the rocket state based on user inputs."""
|
| | self.thrusting = thrusting
|
| |
|
| |
|
| | self.velocity_y -= self.gravity * time_step
|
| |
|
| |
|
| | if self.thrusting:
|
| |
|
| | self.velocity_y += self.thrust_power * math.cos(math.radians(self.angle)) * time_step
|
| | self.velocity_x += self.thrust_power * math.sin(math.radians(self.angle)) * time_step
|
| |
|
| |
|
| | self.x += self.velocity_x * time_step
|
| | self.y += self.velocity_y * time_step
|
| |
|
| |
|
| |
|
| |
|
| | if rotate_left:
|
| | self.angle += self.rotation_speed * time_step
|
| | if rotate_right:
|
| | self.angle -= self.rotation_speed * time_step
|
| |
|
| | def draw(self, screen):
|
| | """Draw the rocket on the screen."""
|
| | rocket_surface = pygame.Surface((self.width, self.height), pygame.SRCALPHA)
|
| | pygame.draw.polygon(rocket_surface, RED, [
|
| | (self.width // 2, 0),
|
| | (0, self.height - 20),
|
| | (self.width, self.height - 20)
|
| | ])
|
| | pygame.draw.rect(rocket_surface, (0, 0, 0), (self.width // 4, self.height - 20, self.width // 2, 20))
|
| |
|
| |
|
| | if self.thrusting:
|
| | pygame.draw.polygon(rocket_surface, (255, 165, 0), [
|
| | (self.width // 4, self.height - 20),
|
| | (self.width // 2, self.height),
|
| | (3 * self.width // 4, self.height - 20)
|
| | ])
|
| |
|
| | rotated_rocket = pygame.transform.rotate(rocket_surface, self.angle)
|
| | rect = rotated_rocket.get_rect(center=(self.x, HEIGHT - self.y))
|
| | screen.blit(rotated_rocket, rect.topleft)
|
| | def state(self):
|
| | return [self.x, self.y, self.angle, self.velocity_x, self.velocity_y]
|
| |
|
| | class RocketLandingGame:
|
| | def __init__(self,render):
|
| | self.render=render
|
| | if render:
|
| | pygame.init()
|
| | self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
|
| | pygame.display.set_caption("Rocket Landing Simulation")
|
| | self.clock = pygame.time.Clock()
|
| | self.running = True
|
| | self.game_over = False
|
| | self.win = False
|
| | self.rocket = Rocket()
|
| | self.action_log = []
|
| |
|
| |
|
| | def draw_terrain(self):
|
| | """Draw the terrain at the bottom of the screen."""
|
| | for i in range(len(terrain) - 1):
|
| | pygame.draw.line(self.screen, BROWN, (i, HEIGHT - terrain[i]), (i + 1, HEIGHT - terrain[i + 1]), 3)
|
| | def returnState(self):
|
| | return self.rocket.state()
|
| |
|
| | def game_step(self, thrusting, rotate_left, rotate_right, time_step=0.5):
|
| | """Perform one step in the game (update physics, game state)."""
|
| | if not self.game_over:
|
| | reward = 0
|
| | self.rocket.update(thrusting, rotate_left, rotate_right, time_step)
|
| |
|
| |
|
| | rocket_bottom_y = self.rocket.y - self.rocket.height // 2
|
| | x_index = int(self.rocket.x)
|
| | terrain_y_at_x = terrain[x_index] if 0 <= x_index < WIDTH else float('inf')
|
| |
|
| | if rocket_bottom_y <= terrain_y_at_x:
|
| | self.rocket.y = terrain_y_at_x + self.rocket.height // 2
|
| |
|
| | if abs(self.rocket.velocity_y) <= 5.0 and abs(self.rocket.velocity_x) <= 5 and abs(self.rocket.angle) <= 10:
|
| | self.game_over = True
|
| | self.win = True
|
| |
|
| | reward = 5
|
| | else:
|
| | self.game_over = True
|
| | reward = -2
|
| | else:
|
| | if thrusting:
|
| | reward -= 0.002
|
| | else:
|
| | reward=0
|
| | reward += (5 - abs(self.rocket.velocity_y)) * 0.01
|
| | reward += (5 - abs(self.rocket.velocity_x)) * 0.01
|
| | reward+=1/(self.rocket.y-99)
|
| | if abs(self.rocket.angle) <= 5:
|
| | reward += 0.02
|
| | else:
|
| | reward -= 0.02
|
| | if self.rocket.y>400:
|
| | self.game_over = True
|
| | reward = -2
|
| | if self.rocket.x>500 or self.rocket.x<300:
|
| | self.game_over = True
|
| | reward = -2
|
| |
|
| | return reward, self.game_over, self.win
|
| |
|
| | def draw_info(self):
|
| | """Draw the game info (coordinates, angle, velocity) on the screen."""
|
| | font = pygame.font.SysFont('Arial', 18)
|
| | info_text = [
|
| | f"X: {self.rocket.x:.2f} Y: {self.rocket.y:.2f}",
|
| | f"Angle: {self.rocket.angle:.2f}",
|
| | f"Velocity X: {self.rocket.velocity_x:.2f} Velocity Y: {self.rocket.velocity_y:.2f}",
|
| | f"Thrusting: {'Yes' if self.rocket.thrusting else 'No'}",
|
| | ]
|
| | for i, text in enumerate(info_text):
|
| | label = font.render(text, True, (0, 0, 0))
|
| | self.screen.blit(label, (10, 10 + i * 20))
|
| |
|
| | def draw_restart_button(self):
|
| | """Draw the restart button if the game is over."""
|
| | font = pygame.font.SysFont('Arial', 30)
|
| | restart_text = font.render("Restart", True, (255, 255, 255))
|
| | button_rect = pygame.Rect(WIDTH // 2 - 75, HEIGHT // 2 - 50, 150, 50)
|
| | pygame.draw.rect(self.screen, (0, 128, 0), button_rect)
|
| | self.screen.blit(restart_text, button_rect.move(25, 10))
|
| |
|
| | return button_rect
|
| |
|
| | def add_to_action_log(self, action):
|
| | """Add actions to the action log."""
|
| | timestamp = time.strftime("%H:%M:%S", time.gmtime(time.time()))
|
| | self.action_log.append(f"{action}")
|
| |
|
| |
|
| |
|