feat(gamecli): wire stdio read-line loop to physics + reward + observation
This commit is contained in:
@@ -1,2 +1,98 @@
|
||||
// Placeholder. Rewritten in Task 8.
|
||||
System.Console.Error.WriteLine("GameCli placeholder");
|
||||
using System.Text.Json;
|
||||
using GameCli;
|
||||
|
||||
// Deterministic PRNG for start-pose randomization on reset.
|
||||
// Seeded fresh on each reset if the caller supplies a seed.
|
||||
var rng = new Random();
|
||||
|
||||
// Current world state and step counter. Reset on {"cmd":"reset"}.
|
||||
var ship = ShipState.AtCenter();
|
||||
int stepCount = 0;
|
||||
int lastAction = 0;
|
||||
|
||||
// --- Startup handshake ---------------------------------------------------
|
||||
var init = new InitMessage
|
||||
{
|
||||
Init = new InitPayload
|
||||
{
|
||||
World = new[] { 1f, 1f },
|
||||
Dt = Physics.Dt,
|
||||
ObsDim = Observation.Dim,
|
||||
NActions = 4,
|
||||
},
|
||||
};
|
||||
Console.WriteLine(JsonSerializer.Serialize(init, ProtocolJsonContext.Default.InitMessage));
|
||||
Console.Out.Flush();
|
||||
|
||||
// --- Read-line loop ------------------------------------------------------
|
||||
string? line;
|
||||
while ((line = Console.In.ReadLine()) is not null)
|
||||
{
|
||||
if (line.Length == 0) continue;
|
||||
|
||||
StepInput? input;
|
||||
try
|
||||
{
|
||||
input = JsonSerializer.Deserialize(line, ProtocolJsonContext.Default.StepInput);
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
Console.Error.WriteLine($"invalid json: {ex.Message}");
|
||||
continue;
|
||||
}
|
||||
if (input is null) continue;
|
||||
|
||||
// Reset command.
|
||||
if (input.Cmd == "reset")
|
||||
{
|
||||
if (input.Seed is int seed) rng = new Random(seed);
|
||||
ship = RandomStartPose(rng);
|
||||
stepCount = 0;
|
||||
lastAction = 0;
|
||||
WriteObservation((0.5f, 0.5f), reward: 0f, done: false);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Step command.
|
||||
int action = input.Action ?? 0;
|
||||
var target = (input.Target is { Length: >= 2 })
|
||||
? (input.Target[0], input.Target[1])
|
||||
: (0.5f, 0.5f);
|
||||
|
||||
ship = Physics.Step(ship, action);
|
||||
lastAction = action;
|
||||
stepCount++;
|
||||
|
||||
float reward = Reward.Compute(ship, target, action);
|
||||
WriteObservation(target, reward, done: false);
|
||||
}
|
||||
|
||||
// --- Helpers -------------------------------------------------------------
|
||||
void WriteObservation((float X, float Y) target, float reward, bool done)
|
||||
{
|
||||
var output = new StepOutput
|
||||
{
|
||||
Obs = Observation.Build(ship, target),
|
||||
State = new ShipStateDto
|
||||
{
|
||||
X = ship.X,
|
||||
Y = ship.Y,
|
||||
Angle = ship.Angle,
|
||||
Engine = lastAction,
|
||||
},
|
||||
Reward = reward,
|
||||
Done = done,
|
||||
Step = stepCount,
|
||||
};
|
||||
Console.WriteLine(JsonSerializer.Serialize(output, ProtocolJsonContext.Default.StepOutput));
|
||||
Console.Out.Flush();
|
||||
}
|
||||
|
||||
static ShipState RandomStartPose(Random rng)
|
||||
{
|
||||
// Random position in a comfortable box; zero velocity, near-upright.
|
||||
float x = 0.2f + (float)rng.NextDouble() * 0.6f;
|
||||
float y = 0.2f + (float)rng.NextDouble() * 0.4f;
|
||||
float angle = ((float)rng.NextDouble() - 0.5f) * 0.4f; // ±0.2 rad
|
||||
return new ShipState(x, y, 0f, 0f, angle, 0f);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user