## actions.nim — map raw network output (4 tanh values) to bot intent fields. ## ## Note on acceleration vs targetSpeed: ## TankRoyale uses setTargetSpeed(), not setAcceleration(). ## The mapped `acceleration` field is a delta; callers must compute: ## newTargetSpeed = clamp(currentSpeed + acceleration, -8.0, 8.0) ## and call setTargetSpeed(newTargetSpeed). import arraymancer const ACTION_DIM* = 4 type MappedActions* = object turnRate*: float ## degrees/tick, speed-aware; [-10, 10] at speed 0 acceleration*: float ## delta speed in [-2, +1]; caller adds to currentSpeed gunTurnRate*: float ## degrees/tick in [-20, 20] firePower*: float ## 0 = don't fire; (0.1, 3.0] = fire with this power proc mapActions*(networkOutput: Tensor[float32], currentSpeed: float, gunHeat: float): MappedActions = ## networkOutput: [4] tensor of tanh values in [-1, 1]. let a0 = networkOutput[0].float let a1 = networkOutput[1].float let a2 = networkOutput[2].float let a3 = networkOutput[3].float result.turnRate = a0 * (10.0 - 0.75 * abs(currentSpeed)) # asymmetric accel: [-1,1] -> [-2, +1] via (value * 1.5 - 0.5) result.acceleration = a1 * 1.5 - 0.5 result.gunTurnRate = a2 * 20.0 if a3 > 0.0 and gunHeat <= 0.0: result.firePower = a3 * 2.9 + 0.1 else: result.firePower = 0.0