import pyxel
import random
import math
scale=1
width,height = 160*scale,120*scale

class App:
    def __init__(self):
        pyxel.init(width, height, title="Gravity Trajectory")
        self.px, self.py = 0.0, 0.0
        self.vx, self.vy = 0.0, 0.0
        self.accel = 0.1
        self.friction = 1
        self.G = 0.01
        self.cell_size = 400
        self.zoom = 1.0
        self.particles = []
        self.stars = [(random.randint(0, width-1), random.randint(0, height-1), random.random()) for _ in range(50)]
        pyxel.run(self.update, self.draw)

    def get_planets(self, px, py):
        planets = []
        cx_b, cy_b = int(px // self.cell_size), int(py // self.cell_size)
        for cx in range(cx_b - 1, cx_b + 2):
            for cy in range(cy_b - 1, cy_b + 2): # Note: cy_base is cy_b
                random.seed(hash((cx, cy)))
                if random.random() < 0.5:
                    x = cx * self.cell_size + random.randint(40, self.cell_size - 40)
                    y = cy * self.cell_size + random.randint(40, self.cell_size - 40)
                    rad = random.randint(10, 30)
                    planets.append({'x': x, 'y': y, 'rad': rad, 'col': random.randint(1, 15), 'm': rad**3})
        return planets

    def update(self):
        # Zoom Controls
        if pyxel.btn(pyxel.KEY_Z): self.zoom = min(self.zoom + 0.02, 2.0)
        if pyxel.btn(pyxel.KEY_X): self.zoom = max(self.zoom - 0.02, 0.2)

        # Thrust
        tx, ty = 0, 0
        if pyxel.btn(pyxel.KEY_UP):    self.vy -= self.accel; ty = 1
        if pyxel.btn(pyxel.KEY_DOWN):  self.vy += self.accel; ty = -1
        if pyxel.btn(pyxel.KEY_LEFT):  self.vx -= self.accel; tx = 1
        if pyxel.btn(pyxel.KEY_RIGHT): self.vx += self.accel; tx = -1

        if tx != 0 or ty != 0:
            for _ in range(2):
                self.particles.append([80, 60, tx*random.uniform(0.2, 1.5), ty*random.uniform(0.2, 1.5), 10])

        # Physics
        self.px += self.vx
        self.py += self.vy
        nearby = self.get_planets(self.px, self.py)
        for p in nearby:
            dx, dy = p['x'] - self.px, p['y'] - self.py
            dist_sq = max(dx**2 + dy**2, 150)
            dist = math.sqrt(dist_sq)
            if dist < 300:
                force = (self.G * p['m']) / dist_sq
                self.vx += force * (dx / dist)
                self.vy += force * (dy / dist)
            if dist < p['rad'] + 2:
                nx, ny = dx/dist, dy/dist
                self.px -= nx * (p['rad'] + 2 - dist)
                dot = self.vx*nx + self.vy*ny
                if dot > 0: self.vx -= 1.3*dot*nx; self.vy -= 1.3*dot*ny

        # Particles
        for p in self.particles[:]:
            p[0] += (p[2] - self.vx)
            p[1] += (p[3] - self.vy)
            p[4] -= 1
            if p[4] <= 0: self.particles.remove(p)
    def draw(self):
        pyxel.cls(0)
        cx, cy = self.px, self.py
        z = self.zoom

        # Stars (Static background)
        for sx, sy, d in self.stars:
            pyxel.pset((sx - self.px*0.05*d)%width, (sy - self.py*0.05*d)%height, 5 if d < 0.5 else 7)

        # Planets & Trajectory
        nearby = self.get_planets(cx, cy)
        
        # Draw Trajectory Projection (Next 1000 steps)
        t_px, t_py = cx, cy
        t_vx, t_vy = self.vx, self.vy
        for i in range(1000):
            t_px += t_vx
            t_py += t_vy
            for p in nearby:
                tdx, tdy = p['x'] - t_px, p['y'] - t_py
                tdist_sq = max(tdx**2 + tdy**2, 150)
                if tdist_sq < 90000: # 300^2
                    t_f = (self.G * p['m']) / tdist_sq
                    t_dist = math.sqrt(tdist_sq)
                    t_vx += t_f * (tdx / t_dist)
                    t_vy += t_f * (tdy / t_dist)
            if i % 4 == 0: # Draw dotted path
                screen_x = 80 + (t_px - cx) * z
                screen_y = 60 + (t_py - cy) * z
                pyxel.pset(screen_x, screen_y, 6)

        # Draw Planets
        for p in nearby:
            sx = 80 + (p['x'] - cx) * z
            sy = 60 + (p['y'] - cy) * z
            pyxel.circ(sx, sy, p['rad'] * z, p['col'])

        # Player & Particles
        for p in self.particles: pyxel.pset(p[0], p[1], 10 if p[4] > 5 else 9)
        pyxel.rect(width/2-1, height/2-2, 3, 5, 12)
        pyxel.circ(width/2, height/2-2, 1, 7)

        # HUD
        pyxel.text(4, 4, f"ZOOM: {z:.1f}  Z/X to adjust", 7)
        # Minimap (Remains fixed size/position)
        mx, my = width-35, height-35
        pyxel.rect(mx-1, my-1, 32, 32, 0)
        pyxel.rectb(mx-1, my-1, 32, 32, 5)
        pyxel.pset(mx+15, my+15, 7)
        for p in nearby:
            mdx, mdy = (p['x']-cx)/100, (p['y']-cy)/25
            if -15 < mdx < 15 and -15 < mdy < 15: pyxel.pset(mx+15+mdx, my+15+mdy, p['col'])
App()