create-eigen-game 0.14.3 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -6
- package/templates/app-overlay/lib/game/v1/local_rules.dart.template +115 -0
- package/templates/app-overlay/lib/game/v1/rules.dart.template +6 -0
- package/templates/app-overlay/web/README.md +11 -0
- package/templates/app-overlay/web/drift_worker.js +13453 -0
- package/templates/app-overlay/web/eigen_offline_sw.js +82 -0
- package/templates/app-overlay/web/flutter_bootstrap.js.template +11 -0
- package/templates/app-overlay/web/sqlite3.wasm +0 -0
- package/templates/worker/game-contract.json +242 -0
- package/templates/worker/src/module/fixtures/v1/counter.json +179 -0
- package/templates/worker/src/module/fixtures/v1/rng.json +26 -0
- package/templates/worker/src/module/v1.ts +11 -4
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// The app shell's cache, so a game can be opened with no network.
|
|
2
|
+
//
|
|
3
|
+
// Flutter stopped generating a service worker in 2025, and the browser cache it
|
|
4
|
+
// left behind is not a promise: it is evicted on its own terms and never
|
|
5
|
+
// answers a cold start offline. Offline play needs the opposite guarantee, so
|
|
6
|
+
// this worker is the app's own, small and readable rather than generated.
|
|
7
|
+
//
|
|
8
|
+
// Runtime caching, not a precache manifest. Flutter's build emits hashed file
|
|
9
|
+
// names that a checked-in manifest would have to track release by release; what
|
|
10
|
+
// this does instead is remember what the app actually asked for, which after one
|
|
11
|
+
// online visit is exactly the shell.
|
|
12
|
+
|
|
13
|
+
const CACHE = "eigen-shell-v1";
|
|
14
|
+
|
|
15
|
+
// Never cached: the engine's own API and socket. They are the live truth, and a
|
|
16
|
+
// stale answer from here would be worse than an honest failure the app already
|
|
17
|
+
// knows how to render.
|
|
18
|
+
const isApi = (url) => url.pathname.startsWith("/api/");
|
|
19
|
+
|
|
20
|
+
self.addEventListener("install", (event) => {
|
|
21
|
+
// Take over as soon as this version is ready; there is no migration to stage.
|
|
22
|
+
event.waitUntil(self.skipWaiting());
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
self.addEventListener("activate", (event) => {
|
|
26
|
+
event.waitUntil(
|
|
27
|
+
(async () => {
|
|
28
|
+
const names = await caches.keys();
|
|
29
|
+
await Promise.all(names.filter((name) => name !== CACHE).map((name) => caches.delete(name)));
|
|
30
|
+
await self.clients.claim();
|
|
31
|
+
})(),
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
self.addEventListener("fetch", (event) => {
|
|
36
|
+
const request = event.request;
|
|
37
|
+
if (request.method !== "GET") return;
|
|
38
|
+
const url = new URL(request.url);
|
|
39
|
+
if (url.origin !== self.location.origin || isApi(url)) return;
|
|
40
|
+
|
|
41
|
+
// A navigation is the app opening. Prefer the network so a deploy is picked
|
|
42
|
+
// up, and fall back to whatever shell was cached, which is what makes a cold
|
|
43
|
+
// start offline work at all.
|
|
44
|
+
if (request.mode === "navigate") {
|
|
45
|
+
event.respondWith(
|
|
46
|
+
(async () => {
|
|
47
|
+
try {
|
|
48
|
+
const response = await fetch(request);
|
|
49
|
+
const cache = await caches.open(CACHE);
|
|
50
|
+
cache.put(request, response.clone());
|
|
51
|
+
return response;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
const cached = (await caches.match(request)) || (await caches.match("/"));
|
|
54
|
+
if (cached) return cached;
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
})(),
|
|
58
|
+
);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Everything else the shell is built from: answer from the cache instantly and
|
|
63
|
+
// refresh it in the background, so a release lands on the next load.
|
|
64
|
+
event.respondWith(
|
|
65
|
+
(async () => {
|
|
66
|
+
const cached = await caches.match(request);
|
|
67
|
+
const network = fetch(request)
|
|
68
|
+
.then(async (response) => {
|
|
69
|
+
if (response.ok) {
|
|
70
|
+
const cache = await caches.open(CACHE);
|
|
71
|
+
cache.put(request, response.clone());
|
|
72
|
+
}
|
|
73
|
+
return response;
|
|
74
|
+
})
|
|
75
|
+
.catch((error) => {
|
|
76
|
+
if (cached) return cached;
|
|
77
|
+
throw error;
|
|
78
|
+
});
|
|
79
|
+
return cached || network;
|
|
80
|
+
})(),
|
|
81
|
+
);
|
|
82
|
+
});
|
|
@@ -15,5 +15,16 @@
|
|
|
15
15
|
});
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
if ("serviceWorker" in navigator) {
|
|
19
|
+
// The app shell's own cache, registered at the root scope so it can answer
|
|
20
|
+
// a cold start with no network. Separate from the messaging worker above,
|
|
21
|
+
// which owns only its push scope.
|
|
22
|
+
await navigator.serviceWorker
|
|
23
|
+
.register("eigen_offline_sw.js", { scope: "/" })
|
|
24
|
+
.catch((error) => {
|
|
25
|
+
console.warn("Offline shell service worker registration failed", error);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
18
29
|
_flutter.loader.load();
|
|
19
30
|
})();
|
|
Binary file
|
|
@@ -112,6 +112,248 @@
|
|
|
112
112
|
},
|
|
113
113
|
"kind": "playerLimits",
|
|
114
114
|
"name": "two seats, because applyAction passes the turn with 1 - playerIndex"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"config": {
|
|
118
|
+
"target": 10
|
|
119
|
+
},
|
|
120
|
+
"expected": {
|
|
121
|
+
"outcome": null,
|
|
122
|
+
"pending": [
|
|
123
|
+
0
|
|
124
|
+
],
|
|
125
|
+
"state": {
|
|
126
|
+
"count": 0
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
"kind": "initialState",
|
|
130
|
+
"name": "opens at zero with seat 0 to move",
|
|
131
|
+
"playerCount": 2
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"config": {
|
|
135
|
+
"target": 10
|
|
136
|
+
},
|
|
137
|
+
"expected": {
|
|
138
|
+
"outcome": [
|
|
139
|
+
{
|
|
140
|
+
"placement": 1,
|
|
141
|
+
"playerIndex": 0,
|
|
142
|
+
"result": "win",
|
|
143
|
+
"teamIndex": 0
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"placement": 2,
|
|
147
|
+
"playerIndex": 1,
|
|
148
|
+
"result": "loss",
|
|
149
|
+
"teamIndex": 1
|
|
150
|
+
}
|
|
151
|
+
],
|
|
152
|
+
"pending": [],
|
|
153
|
+
"state": {
|
|
154
|
+
"count": 4
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
"kind": "lifecycle",
|
|
158
|
+
"name": "the seat that ran out of time loses",
|
|
159
|
+
"pending": [
|
|
160
|
+
1
|
|
161
|
+
],
|
|
162
|
+
"state": {
|
|
163
|
+
"count": 4
|
|
164
|
+
},
|
|
165
|
+
"type": "timeout"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"config": {
|
|
169
|
+
"target": 10
|
|
170
|
+
},
|
|
171
|
+
"expected": {
|
|
172
|
+
"outcome": [
|
|
173
|
+
{
|
|
174
|
+
"placement": 1,
|
|
175
|
+
"playerIndex": 1,
|
|
176
|
+
"result": "win",
|
|
177
|
+
"teamIndex": 1
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"placement": 2,
|
|
181
|
+
"playerIndex": 0,
|
|
182
|
+
"result": "loss",
|
|
183
|
+
"teamIndex": 0
|
|
184
|
+
}
|
|
185
|
+
],
|
|
186
|
+
"pending": [],
|
|
187
|
+
"state": {
|
|
188
|
+
"count": 4
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
"kind": "lifecycle",
|
|
192
|
+
"name": "a resign hands the game to the other seat",
|
|
193
|
+
"pending": [
|
|
194
|
+
0
|
|
195
|
+
],
|
|
196
|
+
"playerIndex": 0,
|
|
197
|
+
"state": {
|
|
198
|
+
"count": 4
|
|
199
|
+
},
|
|
200
|
+
"type": "forfeit"
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
"config": {
|
|
204
|
+
"target": 3
|
|
205
|
+
},
|
|
206
|
+
"expected": {
|
|
207
|
+
"outcome": [
|
|
208
|
+
{
|
|
209
|
+
"placement": 1,
|
|
210
|
+
"playerIndex": 0,
|
|
211
|
+
"result": "win",
|
|
212
|
+
"teamIndex": 0
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"placement": 2,
|
|
216
|
+
"playerIndex": 1,
|
|
217
|
+
"result": "loss",
|
|
218
|
+
"teamIndex": 1
|
|
219
|
+
}
|
|
220
|
+
],
|
|
221
|
+
"pending": [],
|
|
222
|
+
"state": {
|
|
223
|
+
"count": 3
|
|
224
|
+
},
|
|
225
|
+
"status": "finished",
|
|
226
|
+
"version": 3
|
|
227
|
+
},
|
|
228
|
+
"kind": "transcript",
|
|
229
|
+
"name": "three turns reach the target and end the game",
|
|
230
|
+
"playerCount": 2,
|
|
231
|
+
"seed": "counter-twin-transcript",
|
|
232
|
+
"transitions": [
|
|
233
|
+
{
|
|
234
|
+
"data": {
|
|
235
|
+
"amount": 1
|
|
236
|
+
},
|
|
237
|
+
"kind": "game",
|
|
238
|
+
"playerIndex": 0
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"data": {
|
|
242
|
+
"amount": 1
|
|
243
|
+
},
|
|
244
|
+
"kind": "game",
|
|
245
|
+
"playerIndex": 1
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"data": {
|
|
249
|
+
"amount": 1
|
|
250
|
+
},
|
|
251
|
+
"kind": "game",
|
|
252
|
+
"playerIndex": 0
|
|
253
|
+
}
|
|
254
|
+
]
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
"config": {
|
|
258
|
+
"target": 10
|
|
259
|
+
},
|
|
260
|
+
"expected": {
|
|
261
|
+
"outcome": [
|
|
262
|
+
{
|
|
263
|
+
"placement": 1,
|
|
264
|
+
"playerIndex": 0,
|
|
265
|
+
"result": "win",
|
|
266
|
+
"teamIndex": 0
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
"placement": 2,
|
|
270
|
+
"playerIndex": 1,
|
|
271
|
+
"result": "loss",
|
|
272
|
+
"teamIndex": 1
|
|
273
|
+
}
|
|
274
|
+
],
|
|
275
|
+
"pending": [],
|
|
276
|
+
"state": {
|
|
277
|
+
"count": 2
|
|
278
|
+
},
|
|
279
|
+
"status": "finished",
|
|
280
|
+
"version": 2
|
|
281
|
+
},
|
|
282
|
+
"kind": "transcript",
|
|
283
|
+
"name": "a resign ends the game before the target",
|
|
284
|
+
"playerCount": 2,
|
|
285
|
+
"seed": "counter-twin-transcript",
|
|
286
|
+
"transitions": [
|
|
287
|
+
{
|
|
288
|
+
"data": {
|
|
289
|
+
"amount": 2
|
|
290
|
+
},
|
|
291
|
+
"kind": "game",
|
|
292
|
+
"playerIndex": 0
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
"kind": "lifecycle",
|
|
296
|
+
"playerIndex": 1,
|
|
297
|
+
"type": "forfeit"
|
|
298
|
+
}
|
|
299
|
+
]
|
|
300
|
+
}
|
|
301
|
+
],
|
|
302
|
+
"schemaVersion": 1
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
"path": "v1/rng.json",
|
|
307
|
+
"document": {
|
|
308
|
+
"cases": [
|
|
309
|
+
{
|
|
310
|
+
"draws": [
|
|
311
|
+
0.918312304187566,
|
|
312
|
+
0.4001447563059628,
|
|
313
|
+
0.7442655747290701,
|
|
314
|
+
0.2554785134270787,
|
|
315
|
+
0.5585219208151102,
|
|
316
|
+
0.07595188519917428,
|
|
317
|
+
0.24315627454780042,
|
|
318
|
+
0.9577318748924881,
|
|
319
|
+
0.9142457258421928,
|
|
320
|
+
0.6567775409203023,
|
|
321
|
+
0.6638973171357065,
|
|
322
|
+
0.18344326340593398,
|
|
323
|
+
0.20923550752922893,
|
|
324
|
+
0.3633683763910085,
|
|
325
|
+
0.48092103423550725,
|
|
326
|
+
0.5577720713336021
|
|
327
|
+
],
|
|
328
|
+
"kind": "rng",
|
|
329
|
+
"name": "version 0: the stream initialState draws from",
|
|
330
|
+
"seed": "twin-fixtures",
|
|
331
|
+
"version": 0
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
"draws": [
|
|
335
|
+
0.9881007166113704,
|
|
336
|
+
0.19638481689617038,
|
|
337
|
+
0.36466718139126897,
|
|
338
|
+
0.012999370228499174,
|
|
339
|
+
0.07939737639389932,
|
|
340
|
+
0.6601194732356817,
|
|
341
|
+
0.4466901211999357,
|
|
342
|
+
0.44865574641153216,
|
|
343
|
+
0.9610719594638795,
|
|
344
|
+
0.2350573013536632,
|
|
345
|
+
0.1399781135842204,
|
|
346
|
+
0.2336114849895239,
|
|
347
|
+
0.8675420160870999,
|
|
348
|
+
0.8760754023678601,
|
|
349
|
+
0.3999718655832112,
|
|
350
|
+
0.5116847101598978
|
|
351
|
+
],
|
|
352
|
+
"kind": "rng",
|
|
353
|
+
"name": "seat 1's bot stream at version 1",
|
|
354
|
+
"seat": 1,
|
|
355
|
+
"seed": "counter-twin-transcript",
|
|
356
|
+
"version": 1
|
|
115
357
|
}
|
|
116
358
|
],
|
|
117
359
|
"schemaVersion": 1
|
|
@@ -37,6 +37,185 @@
|
|
|
37
37
|
"minPlayers": 2,
|
|
38
38
|
"maxPlayers": 2
|
|
39
39
|
}
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"kind": "initialState",
|
|
43
|
+
"name": "opens at zero with seat 0 to move",
|
|
44
|
+
"config": {
|
|
45
|
+
"target": 10
|
|
46
|
+
},
|
|
47
|
+
"playerCount": 2,
|
|
48
|
+
"expected": {
|
|
49
|
+
"state": {
|
|
50
|
+
"count": 0
|
|
51
|
+
},
|
|
52
|
+
"pending": [0],
|
|
53
|
+
"outcome": null
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"kind": "lifecycle",
|
|
58
|
+
"name": "the seat that ran out of time loses",
|
|
59
|
+
"config": {
|
|
60
|
+
"target": 10
|
|
61
|
+
},
|
|
62
|
+
"state": {
|
|
63
|
+
"count": 4
|
|
64
|
+
},
|
|
65
|
+
"pending": [1],
|
|
66
|
+
"type": "timeout",
|
|
67
|
+
"expected": {
|
|
68
|
+
"state": {
|
|
69
|
+
"count": 4
|
|
70
|
+
},
|
|
71
|
+
"pending": [],
|
|
72
|
+
"outcome": [
|
|
73
|
+
{
|
|
74
|
+
"playerIndex": 0,
|
|
75
|
+
"result": "win",
|
|
76
|
+
"placement": 1,
|
|
77
|
+
"teamIndex": 0
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"playerIndex": 1,
|
|
81
|
+
"result": "loss",
|
|
82
|
+
"placement": 2,
|
|
83
|
+
"teamIndex": 1
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"kind": "lifecycle",
|
|
90
|
+
"name": "a resign hands the game to the other seat",
|
|
91
|
+
"config": {
|
|
92
|
+
"target": 10
|
|
93
|
+
},
|
|
94
|
+
"state": {
|
|
95
|
+
"count": 4
|
|
96
|
+
},
|
|
97
|
+
"pending": [0],
|
|
98
|
+
"type": "forfeit",
|
|
99
|
+
"playerIndex": 0,
|
|
100
|
+
"expected": {
|
|
101
|
+
"state": {
|
|
102
|
+
"count": 4
|
|
103
|
+
},
|
|
104
|
+
"pending": [],
|
|
105
|
+
"outcome": [
|
|
106
|
+
{
|
|
107
|
+
"playerIndex": 1,
|
|
108
|
+
"result": "win",
|
|
109
|
+
"placement": 1,
|
|
110
|
+
"teamIndex": 1
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"playerIndex": 0,
|
|
114
|
+
"result": "loss",
|
|
115
|
+
"placement": 2,
|
|
116
|
+
"teamIndex": 0
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"kind": "transcript",
|
|
123
|
+
"name": "three turns reach the target and end the game",
|
|
124
|
+
"config": {
|
|
125
|
+
"target": 3
|
|
126
|
+
},
|
|
127
|
+
"playerCount": 2,
|
|
128
|
+
"seed": "counter-twin-transcript",
|
|
129
|
+
"transitions": [
|
|
130
|
+
{
|
|
131
|
+
"kind": "game",
|
|
132
|
+
"playerIndex": 0,
|
|
133
|
+
"data": {
|
|
134
|
+
"amount": 1
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"kind": "game",
|
|
139
|
+
"playerIndex": 1,
|
|
140
|
+
"data": {
|
|
141
|
+
"amount": 1
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"kind": "game",
|
|
146
|
+
"playerIndex": 0,
|
|
147
|
+
"data": {
|
|
148
|
+
"amount": 1
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
],
|
|
152
|
+
"expected": {
|
|
153
|
+
"version": 3,
|
|
154
|
+
"status": "finished",
|
|
155
|
+
"state": {
|
|
156
|
+
"count": 3
|
|
157
|
+
},
|
|
158
|
+
"pending": [],
|
|
159
|
+
"outcome": [
|
|
160
|
+
{
|
|
161
|
+
"playerIndex": 0,
|
|
162
|
+
"result": "win",
|
|
163
|
+
"placement": 1,
|
|
164
|
+
"teamIndex": 0
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"playerIndex": 1,
|
|
168
|
+
"result": "loss",
|
|
169
|
+
"placement": 2,
|
|
170
|
+
"teamIndex": 1
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"kind": "transcript",
|
|
177
|
+
"name": "a resign ends the game before the target",
|
|
178
|
+
"config": {
|
|
179
|
+
"target": 10
|
|
180
|
+
},
|
|
181
|
+
"playerCount": 2,
|
|
182
|
+
"seed": "counter-twin-transcript",
|
|
183
|
+
"transitions": [
|
|
184
|
+
{
|
|
185
|
+
"kind": "game",
|
|
186
|
+
"playerIndex": 0,
|
|
187
|
+
"data": {
|
|
188
|
+
"amount": 2
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"kind": "lifecycle",
|
|
193
|
+
"type": "forfeit",
|
|
194
|
+
"playerIndex": 1
|
|
195
|
+
}
|
|
196
|
+
],
|
|
197
|
+
"expected": {
|
|
198
|
+
"version": 2,
|
|
199
|
+
"status": "finished",
|
|
200
|
+
"state": {
|
|
201
|
+
"count": 2
|
|
202
|
+
},
|
|
203
|
+
"pending": [],
|
|
204
|
+
"outcome": [
|
|
205
|
+
{
|
|
206
|
+
"playerIndex": 0,
|
|
207
|
+
"result": "win",
|
|
208
|
+
"placement": 1,
|
|
209
|
+
"teamIndex": 0
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"playerIndex": 1,
|
|
213
|
+
"result": "loss",
|
|
214
|
+
"placement": 2,
|
|
215
|
+
"teamIndex": 1
|
|
216
|
+
}
|
|
217
|
+
]
|
|
218
|
+
}
|
|
40
219
|
}
|
|
41
220
|
]
|
|
42
221
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"cases": [
|
|
4
|
+
{
|
|
5
|
+
"kind": "rng",
|
|
6
|
+
"name": "version 0: the stream initialState draws from",
|
|
7
|
+
"seed": "twin-fixtures",
|
|
8
|
+
"version": 0,
|
|
9
|
+
"draws": [
|
|
10
|
+
0.918312304187566, 0.4001447563059628, 0.7442655747290701, 0.2554785134270787, 0.5585219208151102, 0.07595188519917428, 0.24315627454780042, 0.9577318748924881, 0.9142457258421928, 0.6567775409203023, 0.6638973171357065, 0.18344326340593398, 0.20923550752922893, 0.3633683763910085, 0.48092103423550725,
|
|
11
|
+
0.5577720713336021
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"kind": "rng",
|
|
16
|
+
"name": "seat 1's bot stream at version 1",
|
|
17
|
+
"seed": "counter-twin-transcript",
|
|
18
|
+
"version": 1,
|
|
19
|
+
"seat": 1,
|
|
20
|
+
"draws": [
|
|
21
|
+
0.9881007166113704, 0.19638481689617038, 0.36466718139126897, 0.012999370228499174, 0.07939737639389932, 0.6601194732356817, 0.4466901211999357, 0.44865574641153216, 0.9610719594638795, 0.2350573013536632, 0.1399781135842204, 0.2336114849895239, 0.8675420160870999, 0.8760754023678601, 0.3999718655832112,
|
|
22
|
+
0.5116847101598978
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { GameRules } from "@eigeninteractive/rules";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
|
-
const stateSchema = z.object({ count: z.int().min(0) })
|
|
5
|
-
const observationSchema = z.object({ count: z.int().min(0) })
|
|
6
|
-
const actionSchema = z.object({ amount: z.int().min(1) })
|
|
7
|
-
const configSchema = z.object({ target: z.int().min(1) })
|
|
4
|
+
const stateSchema = z.object({ count: z.int().min(0) });
|
|
5
|
+
const observationSchema = z.object({ count: z.int().min(0) });
|
|
6
|
+
const actionSchema = z.object({ amount: z.int().min(1) });
|
|
7
|
+
const configSchema = z.object({ target: z.int().min(1) });
|
|
8
8
|
|
|
9
9
|
type State = z.infer<typeof stateSchema>;
|
|
10
10
|
type Observation = z.infer<typeof observationSchema>;
|
|
@@ -61,4 +61,11 @@ export const rulesV1: GameRules<State, Observation, Action, Config> = {
|
|
|
61
61
|
|
|
62
62
|
ratingPool: () => null,
|
|
63
63
|
botSeatable: () => true,
|
|
64
|
+
|
|
65
|
+
// The in-engine bot brain, keyed by the bot registry's `username`. The Dart
|
|
66
|
+
// twin in `app/lib/game/v1/local_rules.dart` ships a brain under the same
|
|
67
|
+
// name, so one registered bot is playable on the server and on the device.
|
|
68
|
+
botActions: {
|
|
69
|
+
"example-bot": () => ({ amount: 1 }),
|
|
70
|
+
},
|
|
64
71
|
};
|