last changes

This commit is contained in:
2026-02-21 10:58:05 +01:00
parent 841bc7c805
commit 0902732f60
136 changed files with 10387 additions and 2015 deletions

View File

@@ -1,6 +1,7 @@
import math
import numpy as np
import logging
import pygame
import Box2D
from Box2D import (b2FixtureDef, b2PolygonShape, b2ContactListener)
@@ -20,8 +21,6 @@ except Exception:
from gymnasium.envs.box2d.car_dynamics import Car
import pygame
DEBUG_DRAWING = False
LOOK_AHEAD = 10
@@ -98,9 +97,9 @@ class MyState:
class FrictionDetector(b2ContactListener):
def __init__(self, env):
def __init__(self, car_env):
super().__init__()
self.env = env
self.env = car_env
def BeginContact(self, contact):
self._contact(contact, True)
@@ -142,6 +141,17 @@ class FrictionDetector(b2ContactListener):
self.env.on_road = len(obj.tiles) > 0
def _world_to_screen(x, y, zoom, angle, scroll_x, scroll_y):
ca, sa = math.cos(angle), math.sin(angle)
rx = (x - scroll_x) * ca + (y - scroll_y) * sa
ry = -(x - scroll_x) * sa + (y - scroll_y) * ca
sx = int(WINDOW_W / 2 + rx * zoom)
sy = int(WINDOW_H / 4 + ry * zoom)
return sx, sy
class CarRacing:
metadata = {
"render_modes": ["human", "rgb_array", None],
@@ -150,6 +160,7 @@ class CarRacing:
def __init__(self, seed_value: int = 5, render_mode: str | None = "human"):
self.road_poly = None
self.offroad_frames = None
if seeding is not None:
self.np_random, _ = seeding.np_random(seed_value)
@@ -216,9 +227,9 @@ class CarRacing:
if self._pg is None:
self._pg = self._PygameCtx()
if not self._pg.initialized:
import pygame
if not pygame.get_init():
pygame.init()
flags = 0
if self.render_mode == "human":
self._pg.screen = pygame.display.set_mode((WINDOW_W, WINDOW_H))
else:
@@ -232,23 +243,13 @@ class CarRacing:
self._pg.font = None
self._pg.initialized = True
def _world_to_screen(self, x, y, zoom, angle, scroll_x, scroll_y):
ca, sa = math.cos(angle), math.sin(angle)
rx = (x - scroll_x) * ca + (y - scroll_y) * sa
ry = -(x - scroll_x) * sa + (y - scroll_y) * ca
sx = int(WINDOW_W / 2 + rx * zoom)
sy = int(WINDOW_H / 4 + ry * zoom)
return sx, sy
def get_feature_vector(self, lookahead: int = LOOK_AHEAD) -> list[float]:
my_s: MyState = self.my_state
vec = my_s.as_feature_vector(lookahead).tolist()
return vec
def _draw_polygon_world(self, poly, color, zoom, angle, scroll_x, scroll_y):
pts = [self._world_to_screen(px, py, zoom, angle, scroll_x, scroll_y) for (px, py) in poly]
pts = [_world_to_screen(px, py, zoom, angle, scroll_x, scroll_y) for (px, py) in poly]
pygame.draw.polygon(self._pg.screen, f2c(color), pts)
def _draw_body(self, body, color=(0.7, 0.7, 0.7), zoom=1.0, angle=0.0, scroll_x=0.0, scroll_y=0.0):
@@ -258,7 +259,7 @@ class CarRacing:
shape = fixture.shape
if isinstance(shape, b2PolygonShape):
verts = [body.transform * v for v in shape.vertices]
pts = [self._world_to_screen(v[0], v[1], zoom, angle, scroll_x, scroll_y) for v in verts]
pts = [_world_to_screen(v[0], v[1], zoom, angle, scroll_x, scroll_y) for v in verts]
pygame.draw.polygon(self._pg.screen, col, pts, width=0)
def _destroy(self):
@@ -432,8 +433,8 @@ class CarRacing:
self.track = track
self.original_road_poly = [((list(poly)), list(color)) for (poly, color) in self.road_poly]
self.ctrl_pts = np.array(list(map(lambda x: x[2:], self.track)))
self.angles = np.array(list(map(lambda x: x[1], self.track)))
self.ctrl_pts = np.array(list(map(lambda x_coord: x_coord[2:], self.track)))
self.angles = np.array(list(map(lambda x_coord: x_coord[1], self.track)))
self.outward_vectors = [np.array([np.cos(theta), np.sin(theta)]) for theta in self.angles]
angle_deltas = self.angles - np.roll(self.angles, 1)
self.angle_deltas = np.array(list(map(standardize_angle, angle_deltas)))
@@ -468,7 +469,7 @@ class CarRacing:
self._no_progress_steps = 0
self._stall_steps = 0
def reset(self, *, seed: int | None = None, options: dict | None = None):
def reset(self, *, seed: int | None = None):
if seed is not None:
if seeding is not None:
@@ -476,8 +477,9 @@ class CarRacing:
else:
self.np_random = np.random.RandomState(seed)
self._build_new_episode()
obs = self._get_observation()
info = {}
obs, _, _, _, info = self.step(
np.array([0.0, 0.0, 0.0], dtype=np.float32)
)
return obs, info
def fast_reset(self):
@@ -509,12 +511,12 @@ class CarRacing:
return self.step(np.array([0.0, 0.0, 0.0], dtype=np.float32))
def step(self, action):
def step(self, env_action):
if action is not None:
self.car.steer(-float(action[0]))
self.car.gas(float(action[1]))
self.car.brake(float(action[2]))
if env_action is not None:
self.car.steer(-float(env_action[0]))
self.car.gas(float(env_action[1]))
self.car.brake(float(env_action[2]))
self.car.step(1.0 / FPS)
self.world.Step(1.0 / FPS, 6 * 30, 2 * 30)
@@ -522,27 +524,27 @@ class CarRacing:
self.steps += 1
terminated = False
truncated = False
env_terminated = False
env_truncated = False
if action is not None:
if env_action is not None:
self.reward -= 5.0 / FPS
if self.tile_visited_count == len(self.track):
terminated = True
env_terminated = True
x, y = self.car.hull.position
if abs(x) > PLAYFIELD or abs(y) > PLAYFIELD:
self.reward -= 100.0
terminated = True
env_terminated = True
if not self.on_road:
self.offroad_frames += 1
self.reward -= self.offroad_penalty_per_frame / FPS
if self.offroad_frames > self.offroad_grace_frames:
self.reward -= 20.0
terminated = True
env_terminated = True
else:
self.offroad_frames = 0
@@ -552,7 +554,7 @@ class CarRacing:
else:
self._no_progress_steps += 1
if self._no_progress_steps >= NO_PROGRESS_STEPS:
truncated = True
env_truncated = True
step_reward = self.reward - self.prev_reward
self.prev_reward = self.reward
@@ -605,11 +607,10 @@ class CarRacing:
obs = self._get_observation()
info = {"features": self.my_state}
return obs, step_reward, terminated, truncated, info
return obs, step_reward, env_terminated, env_truncated, info
def _get_observation(self):
return None
return np.array(self.get_feature_vector(), dtype=np.float32)
def render(self):
self._ensure_pygame()
@@ -636,10 +637,10 @@ class CarRacing:
for y in range(-20, 20, 2):
x0, y0 = k * x + 0, k * y + 0
x1, y1 = k * x + k, k * y + k
p0 = self._world_to_screen(x0, y0, zoom, angle, scroll_x, scroll_y)
p1 = self._world_to_screen(x1, y0, zoom, angle, scroll_x, scroll_y)
p2 = self._world_to_screen(x1, y1, zoom, angle, scroll_x, scroll_y)
p3 = self._world_to_screen(x0, y1, zoom, angle, scroll_x, scroll_y)
p0 = _world_to_screen(x0, y0, zoom, angle, scroll_x, scroll_y)
p1 = _world_to_screen(x1, y0, zoom, angle, scroll_x, scroll_y)
p2 = _world_to_screen(x1, y1, zoom, angle, scroll_x, scroll_y)
p3 = _world_to_screen(x0, y1, zoom, angle, scroll_x, scroll_y)
pygame.draw.polygon(self._pg.screen, grid_color, [p0, p1, p2, p3])
for poly, color in self.road_poly: