Better scoring and map selection + Map delta

This commit is contained in:
2026-10-23 17:54:13 +02:00
parent ce720a92b2
commit f56b8c1e9c
16 changed files with 233 additions and 39 deletions
+57 -10
View File
@@ -22,7 +22,7 @@ any map when no such map exists.
The score is from 0 to 100:
`40 * coin_progress + 40 * distance_progress + 20 * won`
`50 * coin_progress + 10 * distance_progress + 40 * won`
where `coin_progress` is collected coins divided by the map's total coins,
`distance_progress` is progress from the spawn point to the finish, and `won`
@@ -37,21 +37,29 @@ are requested separately on every turn.
```
Every model gets a separate `Game` instance and can run in parallel. Valid
requests. Valid moves are `left_down`, `left`, `left_up`, `up`, `right_up`,
moves are `left_down`, `left`, `left_up`, `up`, `right_up`,
`right`, and `right_down`. Send `null` for a model when it has no more moves;
that model is stopped for the current generation.
The response identifies the selected map and returns the initial state:
The initial response is a `move_request`. It contains the selected map and the
initial state of every model. The map is sent only in this initial response;
clients should cache it for the rest of the simulation.
```json
{
"ok":true,
"type":"move_request",
"map":{"name":"default","difficulty":30.0,"layout":[["stone", "stone"]]},
"results":{"model-a":{"won":false,"coins":0,"moves":0,"position":[1,4],"finished":false},"model-b":{"won":false,"coins":0,"moves":0,"position":[1,4],"finished":false}}
"results":{"model-a":{"won":false,"coins":0,"moves":0,"position":[1,4],"finished":false,"changes":[]},"model-b":{"won":false,"coins":0,"moves":0,"position":[1,4],"finished":false,"changes":[]}}
}
```
After receiving this response, send one move for every model:
```json
{"type":"step","moves":{"model-a":"right","model-b":"right_up"}}
```
## Advance one turn
The client must send exactly one move for every model on each turn. The server
@@ -62,10 +70,49 @@ predict the next moves.
{"type":"step","moves":{"model-a":"right","model-b":null}}
```
The response is `move_request` with the selected map and updated per-model states, asking the
client for the next move of every model. When every model has finished, the
response type becomes `simulation_result` and includes the best model's
server-computed `score`, which is used to choose the next training map.
The response is another `move_request` containing the updated state and score
for every model. Each model also receives `changes`, a cumulative list of
blocks that differ from the base map. For example, a collected coin is sent as
`{"position":[4,7],"type":null}`. Unchanged turns return an empty list. It
asks the client for the next move of every unfinished model. A model that has
no more moves can send `null`:
The result score is `1000` for a win, plus `10` per coin, minus the number of
moves. Malformed requests receive `{"ok":false,"error":"..."}`.
```json
{"type":"step","moves":{"model-a":"right","model-b":null}}
```
When every model has finished, the response type becomes `simulation_result`.
It contains the final state and score for every model, plus the best score used
to choose the next training map:
```json
{
"ok":true,
"type":"simulation_result",
"results":{
"model-a":{
"won":true,
"coins":3,
"moves":18,
"position":[23,1],
"finished":true,
"changes":[{"position":[4,7],"type":null}],
"score":92
},
"model-b":{
"won":false,
"coins":1,
"moves":7,
"position":[8,4],
"finished":true,
"changes":[],
"score":24
}
},
"score":92
}
```
The score is calculated by the server using the weights described above. The
top-level `score` is the best model score for the completed generation.
Malformed requests receive `{"ok":false,"type":"error","error":"..."}`.