kaggle-environments 1.22.6__py3-none-any.whl → 1.24.3__py3-none-any.whl

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.

Potentially problematic release.


This version of kaggle-environments might be problematic. Click here for more details.

Files changed (68) hide show
  1. kaggle_environments/envs/connectx/visualizer/default/index.html +13 -0
  2. kaggle_environments/envs/connectx/visualizer/default/package.json +22 -0
  3. kaggle_environments/envs/connectx/visualizer/default/replays/test-replay.json +1129 -0
  4. kaggle_environments/envs/connectx/visualizer/default/src/main.ts +12 -0
  5. kaggle_environments/envs/connectx/visualizer/default/src/renderer.ts +396 -0
  6. kaggle_environments/envs/connectx/visualizer/default/src/style.css +38 -0
  7. kaggle_environments/envs/connectx/visualizer/default/tsconfig.json +4 -0
  8. kaggle_environments/envs/connectx/visualizer/default/vite.config.ts +7 -0
  9. kaggle_environments/envs/open_spiel_env/games/repeated_poker/repeated_poker.js +163 -88
  10. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/index.html +13 -0
  11. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/package.json +23 -0
  12. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/replays/test-replay.json +1 -0
  13. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/scripts/print_first_steps.mjs +202 -0
  14. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/scripts/print_replay.mjs +215 -0
  15. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/scripts/print_steps_with_end_states.mjs +234 -0
  16. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/getRepeatedPokerStateForStep.js +260 -0
  17. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/utils.ts +61 -0
  18. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/debug_repeated_poker_renderer.ts +49 -0
  19. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_1.svg +22 -0
  20. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_10.svg +22 -0
  21. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_100.svg +48 -0
  22. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_25.svg +22 -0
  23. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_5.svg +22 -0
  24. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/main.ts +36 -0
  25. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/repeated_poker_renderer.ts +573 -0
  26. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/style.css +594 -0
  27. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/tsconfig.json +7 -0
  28. kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/vite.config.ts +6 -0
  29. kaggle_environments/envs/werewolf/README.md +190 -0
  30. kaggle_environments/envs/werewolf/harness/__init__.py +0 -0
  31. kaggle_environments/envs/werewolf/harness/base.py +773 -0
  32. kaggle_environments/envs/werewolf/harness/litellm_models.yaml +51 -0
  33. kaggle_environments/envs/werewolf/harness/main.py +54 -0
  34. kaggle_environments/envs/werewolf/harness/test_base.py +35 -0
  35. kaggle_environments/envs/werewolf/runner.py +146 -0
  36. kaggle_environments/envs/werewolf/scripts/__init__.py +0 -0
  37. kaggle_environments/envs/werewolf/scripts/add_audio.py +425 -0
  38. kaggle_environments/envs/werewolf/scripts/configs/audio/standard.yaml +24 -0
  39. kaggle_environments/envs/werewolf/scripts/configs/run/block_basic.yaml +102 -0
  40. kaggle_environments/envs/werewolf/scripts/configs/run/comprehensive.yaml +100 -0
  41. kaggle_environments/envs/werewolf/scripts/configs/run/roundrobin_discussion_DisableDoctorSelfSave_DisableDoctorConsecutiveSave_large.yaml +104 -0
  42. kaggle_environments/envs/werewolf/scripts/configs/run/roundrobin_discussion_large.yaml +103 -0
  43. kaggle_environments/envs/werewolf/scripts/configs/run/roundrobin_discussion_small.yaml +103 -0
  44. kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard.yaml +103 -0
  45. kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_DisableDoctorConsecutiveSave.yaml +104 -0
  46. kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_SeerRevealTeam.yaml +105 -0
  47. kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_SeerRevealTeam_NightEliminationNoReveal_DayExileNoReveal.yaml +105 -0
  48. kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_SeerRevealTeam_NightEliminationRevealTeam_DayExileRevealTeam.yaml +105 -0
  49. kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_disable_doctor_self_save.yaml +103 -0
  50. kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_parallel_voting.yaml +103 -0
  51. kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_parallel_voting_no_tie_exile.yaml +103 -0
  52. kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_parallel_voting_roundbiddiscussion.yaml +105 -0
  53. kaggle_environments/envs/werewolf/scripts/configs/run/run_config.yaml +58 -0
  54. kaggle_environments/envs/werewolf/scripts/configs/run/vertex_api_example_config.yaml +115 -0
  55. kaggle_environments/envs/werewolf/scripts/measure_cost.py +251 -0
  56. kaggle_environments/envs/werewolf/scripts/plot_existing_trajectories.py +135 -0
  57. kaggle_environments/envs/werewolf/scripts/rerender_html.py +87 -0
  58. kaggle_environments/envs/werewolf/scripts/run.py +93 -0
  59. kaggle_environments/envs/werewolf/scripts/run_block.py +237 -0
  60. kaggle_environments/envs/werewolf/scripts/run_pairwise_matrix.py +222 -0
  61. kaggle_environments/envs/werewolf/scripts/self_play.py +196 -0
  62. kaggle_environments/envs/werewolf/scripts/utils.py +47 -0
  63. kaggle_environments/envs/werewolf/werewolf.json +1 -1
  64. {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/METADATA +1 -1
  65. {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/RECORD +68 -7
  66. {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/WHEEL +0 -0
  67. {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/entry_points.txt +0 -0
  68. {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,202 @@
1
+ #!/usr/bin/env node
2
+
3
+ import path from "path";
4
+ import { fileURLToPath } from "url";
5
+ import { readFile } from "fs/promises";
6
+
7
+ function parseArgs(defaultReplayPath, defaultStepLimit) {
8
+ const args = process.argv.slice(2);
9
+ let replayPath = defaultReplayPath;
10
+ let stepLimit = defaultStepLimit;
11
+
12
+ const usage = `Usage: node ${path.basename(
13
+ process.argv[1]
14
+ )} [options]\n\nOptions:\n -r, --replay <path> Replay JSON to inspect (default: ${defaultReplayPath})\n -s, --steps <count> Number of steps to print (default: ${defaultStepLimit})\n -h, --help Show this help message\n`;
15
+
16
+ for (let i = 0; i < args.length; i += 1) {
17
+ const arg = args[i];
18
+ if (arg === "-h" || arg === "--help") {
19
+ console.log(usage);
20
+ process.exit(0);
21
+ } else if ((arg === "-r" || arg === "--replay") && args[i + 1]) {
22
+ replayPath = path.resolve(args[i + 1]);
23
+ i += 1;
24
+ } else if ((arg === "-s" || arg === "--steps") && args[i + 1]) {
25
+ const value = Number(args[i + 1]);
26
+ if (!Number.isInteger(value) || value <= 0) {
27
+ console.error("Steps limit must be a positive integer.");
28
+ console.log(usage);
29
+ process.exit(1);
30
+ }
31
+ stepLimit = value;
32
+ i += 1;
33
+ } else {
34
+ console.error(`Unknown argument: ${arg}`);
35
+ console.log(usage);
36
+ process.exit(1);
37
+ }
38
+ }
39
+
40
+ return { replayPath, stepLimit };
41
+ }
42
+
43
+ function truncate(text, maxLength = 120) {
44
+ if (typeof text !== "string") {
45
+ return text;
46
+ }
47
+ if (text.length <= maxLength) {
48
+ return text;
49
+ }
50
+ return `${text.slice(0, maxLength - 3)}...`;
51
+ }
52
+
53
+ function summarizeAction(action) {
54
+ if (action == null) {
55
+ return "-";
56
+ }
57
+
58
+ if (typeof action !== "object") {
59
+ return String(action);
60
+ }
61
+
62
+ const parts = [];
63
+ if (Object.prototype.hasOwnProperty.call(action, "actionString")) {
64
+ parts.push(`actionString=${action.actionString}`);
65
+ }
66
+ if (Object.prototype.hasOwnProperty.call(action, "submission")) {
67
+ parts.push(`submission=${action.submission}`);
68
+ }
69
+ if (Object.prototype.hasOwnProperty.call(action, "status") && action.status) {
70
+ parts.push(`status=${truncate(action.status, 60)}`);
71
+ }
72
+
73
+ if (parts.length > 0) {
74
+ return parts.join(" | ");
75
+ }
76
+
77
+ return truncate(JSON.stringify(action));
78
+ }
79
+
80
+ function summarizeObservation(observation) {
81
+ if (observation == null) {
82
+ return "-";
83
+ }
84
+
85
+ if (typeof observation !== "object") {
86
+ return String(observation);
87
+ }
88
+
89
+ const parts = [];
90
+ if (Object.prototype.hasOwnProperty.call(observation, "step")) {
91
+ parts.push(`step=${observation.step}`);
92
+ }
93
+ if (Object.prototype.hasOwnProperty.call(observation, "currentPlayer")) {
94
+ parts.push(`currentPlayer=${observation.currentPlayer}`);
95
+ }
96
+ if (Object.prototype.hasOwnProperty.call(observation, "isTerminal")) {
97
+ parts.push(`isTerminal=${observation.isTerminal}`);
98
+ }
99
+ if (
100
+ Object.prototype.hasOwnProperty.call(observation, "observationString") &&
101
+ observation.observationString
102
+ ) {
103
+ parts.push(
104
+ `observationString="${truncate(observation.observationString, 80)}"`
105
+ );
106
+ }
107
+ if (
108
+ Object.prototype.hasOwnProperty.call(
109
+ observation,
110
+ "serializedGameAndState"
111
+ ) &&
112
+ observation.serializedGameAndState
113
+ ) {
114
+ parts.push("serializedGameAndState=<omitted>");
115
+ }
116
+
117
+ if (parts.length > 0) {
118
+ return parts.join(" | ");
119
+ }
120
+
121
+ return truncate(JSON.stringify(observation));
122
+ }
123
+
124
+ async function main() {
125
+ const __filename = fileURLToPath(import.meta.url);
126
+ const __dirname = path.dirname(__filename);
127
+ const defaultReplayPath = path.resolve(
128
+ __dirname,
129
+ "../replays/test-replay.json"
130
+ );
131
+ const defaultStepLimit = 5;
132
+
133
+ const { replayPath, stepLimit } = parseArgs(
134
+ defaultReplayPath,
135
+ defaultStepLimit
136
+ );
137
+
138
+ let replayRaw;
139
+ try {
140
+ replayRaw = await readFile(replayPath, "utf-8");
141
+ } catch (error) {
142
+ console.error(`Failed to read replay at ${replayPath}: ${error.message}`);
143
+ process.exit(1);
144
+ }
145
+
146
+ let replay;
147
+ try {
148
+ replay = JSON.parse(replayRaw);
149
+ } catch (error) {
150
+ console.error(
151
+ `Replay file ${replayPath} is not valid JSON: ${error.message}`
152
+ );
153
+ process.exit(1);
154
+ }
155
+
156
+ const steps = Array.isArray(replay?.steps) ? replay.steps : [];
157
+ if (steps.length === 0) {
158
+ console.error("Replay does not contain any steps.");
159
+ process.exit(1);
160
+ }
161
+
162
+ const limit = Math.min(stepLimit, steps.length);
163
+ console.log(`Loaded replay: ${replayPath}`);
164
+ console.log(`Printing first ${limit} of ${steps.length} steps\n`);
165
+
166
+ for (let stepIndex = 0; stepIndex < limit; stepIndex += 1) {
167
+ const step = steps[stepIndex];
168
+ console.log(`Step ${stepIndex}`);
169
+
170
+ if (!Array.isArray(step)) {
171
+ console.log(" (step is not an array)\n");
172
+ continue;
173
+ }
174
+
175
+ step.forEach((playerStep, playerIndex) => {
176
+ if (!playerStep || typeof playerStep !== "object") {
177
+ console.log(` Player ${playerIndex}: <invalid step payload>`);
178
+ return;
179
+ }
180
+
181
+ const { action, observation, reward, status } = playerStep;
182
+ const actionSummary = summarizeAction(action);
183
+ const observationSummary = summarizeObservation(observation);
184
+ const rewardSummary =
185
+ reward == null ? "-" : JSON.stringify(reward, null, 0);
186
+ const statusSummary = status ?? "-";
187
+
188
+ console.log(
189
+ ` Player ${playerIndex}: status=${statusSummary} | reward=${rewardSummary}`
190
+ );
191
+ console.log(` action: ${actionSummary}`);
192
+ console.log(` observation: ${observationSummary}`);
193
+ });
194
+
195
+ console.log("");
196
+ }
197
+ }
198
+
199
+ main().catch((error) => {
200
+ console.error("Failed to print steps:", error);
201
+ process.exit(1);
202
+ });
@@ -0,0 +1,215 @@
1
+ #!/usr/bin/env node
2
+
3
+ import path from "path";
4
+ import { fileURLToPath, pathToFileURL } from "url";
5
+ import { readFile } from "fs/promises";
6
+ import { createRequire } from "module";
7
+
8
+ async function loadCoreModules(repoRoot) {
9
+ const require = createRequire(import.meta.url);
10
+ const corePath = path.resolve(repoRoot, "web/core/dist/index.umd.cjs");
11
+ const timelinePath = path.resolve(
12
+ repoRoot,
13
+ "web/core/dist/transformers/buildTimeline.js"
14
+ );
15
+
16
+ const { processEpisodeData } = require(corePath);
17
+ const { buildTimeline, getPokerStateForStep } = await import(
18
+ pathToFileURL(timelinePath).href
19
+ );
20
+
21
+ return { processEpisodeData, buildTimeline, getPokerStateForStep };
22
+ }
23
+
24
+ function parseArgs(defaultReplayPath, defaultStepLimit) {
25
+ const args = process.argv.slice(2);
26
+ let replayPath = defaultReplayPath;
27
+ let stepLimit = defaultStepLimit;
28
+
29
+ const usage = `Usage: node ${path.basename(
30
+ process.argv[1]
31
+ )} [options]\n\nOptions:\n -r, --replay <path> Replay JSON to inspect (default: ${defaultReplayPath})\n -s, --steps <count> Number of timeline steps to print (default: ${defaultStepLimit})\n -h, --help Show this help message\n`;
32
+
33
+ for (let i = 0; i < args.length; i += 1) {
34
+ const arg = args[i];
35
+ if (arg === "-h" || arg === "--help") {
36
+ console.log(usage);
37
+ process.exit(0);
38
+ } else if ((arg === "-r" || arg === "--replay") && args[i + 1]) {
39
+ replayPath = path.resolve(args[i + 1]);
40
+ i += 1;
41
+ } else if ((arg === "-s" || arg === "--steps") && args[i + 1]) {
42
+ const value = Number(args[i + 1]);
43
+ if (!Number.isInteger(value) || value <= 0) {
44
+ console.error("Steps limit must be a positive integer.");
45
+ console.log(usage);
46
+ process.exit(1);
47
+ }
48
+ stepLimit = value;
49
+ i += 1;
50
+ } else {
51
+ console.error(`Unknown argument: ${arg}`);
52
+ console.log(usage);
53
+ process.exit(1);
54
+ }
55
+ }
56
+
57
+ return { replayPath, stepLimit };
58
+ }
59
+
60
+ function extractStateHistory(replay) {
61
+ return (
62
+ replay?.info?.stateHistory ??
63
+ replay?.info?.state_history ??
64
+ replay?.stateHistory ??
65
+ replay?.state_history ??
66
+ []
67
+ );
68
+ }
69
+
70
+ function formatCommunityCards(cards) {
71
+ if (!Array.isArray(cards) || cards.length === 0) {
72
+ return "--";
73
+ }
74
+ return cards.join(" ");
75
+ }
76
+
77
+ function formatWinOdds(winOdds) {
78
+ if (!Array.isArray(winOdds) || winOdds.length === 0) {
79
+ return "--";
80
+ }
81
+ return winOdds.join(" vs ");
82
+ }
83
+
84
+ async function main() {
85
+ const __filename = fileURLToPath(import.meta.url);
86
+ const __dirname = path.dirname(__filename);
87
+ const repoRoot = path.resolve(__dirname, "../../../../../../../..");
88
+ const defaultReplayPath = path.resolve(
89
+ __dirname,
90
+ "../replays/test-replay.json"
91
+ );
92
+ const defaultStepLimit = 5;
93
+
94
+ const { replayPath, stepLimit } = parseArgs(
95
+ defaultReplayPath,
96
+ defaultStepLimit
97
+ );
98
+
99
+ const { processEpisodeData, buildTimeline, getPokerStateForStep } =
100
+ await loadCoreModules(repoRoot);
101
+
102
+ let replayRaw;
103
+ try {
104
+ replayRaw = await readFile(replayPath, "utf-8");
105
+ } catch (error) {
106
+ console.error(`Failed to read replay at ${replayPath}: ${error.message}`);
107
+ process.exit(1);
108
+ }
109
+
110
+ let replay;
111
+ try {
112
+ replay = JSON.parse(replayRaw);
113
+ } catch (error) {
114
+ console.error(
115
+ `Replay file ${replayPath} is not valid JSON: ${error.message}`
116
+ );
117
+ process.exit(1);
118
+ }
119
+
120
+ const stateHistory = extractStateHistory(replay);
121
+ if (!Array.isArray(stateHistory) || stateHistory.length === 0) {
122
+ console.error("Replay does not contain a state history.");
123
+ process.exit(1);
124
+ }
125
+
126
+ const processedSteps = processEpisodeData(
127
+ {
128
+ steps: replay.steps,
129
+ state_history: stateHistory,
130
+ info: replay.info,
131
+ configuration: replay.configuration,
132
+ },
133
+ "repeated_poker"
134
+ );
135
+
136
+ const environment = {
137
+ configuration: replay.configuration,
138
+ info: {
139
+ ...replay.info,
140
+ stateHistory,
141
+ },
142
+ steps: processedSteps,
143
+ __processedSteps: processedSteps,
144
+ __rawSteps: replay.steps,
145
+ };
146
+
147
+ const timeline = buildTimeline(environment, 2);
148
+ environment.__timeline = timeline;
149
+
150
+ console.log(`Loaded replay: ${replayPath}`);
151
+ console.log(
152
+ `Printing first ${Math.min(stepLimit, timeline.length)} of ${
153
+ timeline.length
154
+ } timeline steps\n`
155
+ );
156
+
157
+ for (let stepIndex = 0; stepIndex < timeline.length; stepIndex += 1) {
158
+ if (stepIndex >= stepLimit) {
159
+ break;
160
+ }
161
+
162
+ const event = timeline[stepIndex];
163
+ const uiState = getPokerStateForStep(environment, stepIndex);
164
+
165
+ const headerParts = [
166
+ `Step ${stepIndex}`,
167
+ `stateIndex=${event?.stateIndex ?? "N/A"}`,
168
+ `highlight=${event?.highlightPlayer ?? "-"}`,
169
+ `action='${event?.actionText ?? ""}'`,
170
+ ];
171
+ if (event?.hideHoleCards) {
172
+ headerParts.push("hideHoleCards");
173
+ }
174
+ if (event?.hideCommunity) {
175
+ headerParts.push("hideCommunity");
176
+ }
177
+
178
+ console.log(headerParts.join(" | "));
179
+
180
+ if (!uiState) {
181
+ console.log(" (UI state unavailable)\n");
182
+ continue;
183
+ }
184
+
185
+ console.log(
186
+ ` pot=${uiState.pot} | community=${formatCommunityCards(
187
+ uiState.communityCards
188
+ )} | winOdds=${formatWinOdds(uiState.winOdds)}`
189
+ );
190
+
191
+ uiState.players.forEach((player, seat) => {
192
+ const cards =
193
+ Array.isArray(player.cards) && player.cards.length > 0
194
+ ? player.cards.join(" ")
195
+ : "--";
196
+ const flags = [
197
+ player.isDealer ? "D" : "",
198
+ player.isTurn ? "T" : "",
199
+ player.isLastActor ? "LA" : "",
200
+ ]
201
+ .filter(Boolean)
202
+ .join(",") || "-";
203
+ console.log(
204
+ ` P${seat}: stack=${player.stack} bet=${player.currentBet} cards=${cards} flags=${flags} action='${player.actionDisplayText || ""}'`
205
+ );
206
+ });
207
+
208
+ console.log("");
209
+ }
210
+ }
211
+
212
+ main().catch((error) => {
213
+ console.error("Failed to print replay steps:", error);
214
+ process.exit(1);
215
+ });
@@ -0,0 +1,234 @@
1
+ #!/usr/bin/env node
2
+
3
+ import path from "path";
4
+ import { fileURLToPath, pathToFileURL } from "url";
5
+ import { readFile } from "fs/promises";
6
+ import { createRequire } from "module";
7
+
8
+ async function loadCoreModules(repoRoot) {
9
+ const require = createRequire(import.meta.url);
10
+ const corePath = path.resolve(repoRoot, "web/core/dist/index.umd.cjs");
11
+ const transformerPath = path.resolve(
12
+ repoRoot,
13
+ "web/core/dist/transformers/repeatedPokerTransformer.js"
14
+ );
15
+
16
+ const { processEpisodeData } = require(corePath);
17
+ const { getPokerStepsWithEndStates } = await import(
18
+ pathToFileURL(transformerPath).href
19
+ );
20
+
21
+ return { processEpisodeData, getPokerStepsWithEndStates };
22
+ }
23
+
24
+ function parseArgs(defaultReplayPath, defaultLimit, defaultJsonOutput) {
25
+ const args = process.argv.slice(2);
26
+ let replayPath = defaultReplayPath;
27
+ let limit = defaultLimit;
28
+ let asJson = defaultJsonOutput;
29
+
30
+ const usage = `Usage: node ${path.basename(
31
+ process.argv[1]
32
+ )} [options]\n\nOptions:\n -r, --replay <path> Replay JSON to inspect (default: ${defaultReplayPath})\n -l, --limit <count> Number of entries to print (0 = all) (default: ${defaultLimit})\n --json Print raw JSON instead of formatted text\n -h, --help Show this help message\n`;
33
+
34
+ for (let i = 0; i < args.length; i += 1) {
35
+ const arg = args[i];
36
+ if (arg === "-h" || arg === "--help") {
37
+ console.log(usage);
38
+ process.exit(0);
39
+ } else if ((arg === "-r" || arg === "--replay") && args[i + 1]) {
40
+ replayPath = path.resolve(args[i + 1]);
41
+ i += 1;
42
+ } else if ((arg === "-l" || arg === "--limit") && args[i + 1]) {
43
+ const value = Number(args[i + 1]);
44
+ if (!Number.isInteger(value) || value < 0) {
45
+ console.error("Limit must be a non-negative integer.");
46
+ console.log(usage);
47
+ process.exit(1);
48
+ }
49
+ limit = value;
50
+ i += 1;
51
+ } else if (arg === "--json") {
52
+ asJson = true;
53
+ } else {
54
+ console.error(`Unknown argument: ${arg}`);
55
+ console.log(usage);
56
+ process.exit(1);
57
+ }
58
+ }
59
+
60
+ return { replayPath, limit, asJson };
61
+ }
62
+
63
+ function extractStateHistory(replay) {
64
+ return (
65
+ replay?.info?.stateHistory ??
66
+ replay?.info?.state_history ??
67
+ replay?.stateHistory ??
68
+ replay?.state_history ??
69
+ []
70
+ );
71
+ }
72
+
73
+ function buildEnvironment(
74
+ replay,
75
+ processedSteps,
76
+ processedInfo,
77
+ processedConfig,
78
+ stateHistory
79
+ ) {
80
+ return {
81
+ configuration: processedConfig ?? replay.configuration ?? null,
82
+ info: {
83
+ ...(processedInfo || replay.info || {}),
84
+ stateHistory,
85
+ },
86
+ steps: processedSteps,
87
+ __processedSteps: processedSteps,
88
+ __rawSteps: replay.steps,
89
+ };
90
+ }
91
+
92
+ function describeStep(step, index) {
93
+ const baseParts = [
94
+ `Index ${index}`,
95
+ `hand=${step.hand}`,
96
+ `stateHistoryIndex=${step.stateHistoryIndex ?? "?"}`,
97
+ `isEndState=${step.isEndState}`,
98
+ ];
99
+
100
+ if (step.postActionOf != null) {
101
+ baseParts.push(`postActionOf=${step.postActionOf}`);
102
+ }
103
+
104
+ if (step.actingPlayer != null) {
105
+ const label =
106
+ step.actingPlayerName && step.actingPlayerName.length > 0
107
+ ? `${step.actingPlayer}(${step.actingPlayerName})`
108
+ : `${step.actingPlayer}`;
109
+ baseParts.push(`actingPlayer=${label}`);
110
+ }
111
+
112
+ if (step.currentPlayer != null) {
113
+ const label =
114
+ step.currentPlayerName && step.currentPlayerName.length > 0
115
+ ? `${step.currentPlayer}(${step.currentPlayerName})`
116
+ : `${step.currentPlayer}`;
117
+ baseParts.push(`currentPlayer=${label}`);
118
+ }
119
+
120
+ if (step.isEndState) {
121
+ baseParts.push(`conclusion=${step.handConclusion ?? "-"}`);
122
+ baseParts.push(`winner=${step.winner ?? "-"}`);
123
+ } else if (step.step?.action?.actionString) {
124
+ baseParts.push(`action=${step.step.action.actionString}`);
125
+ } else if (step.actionText) {
126
+ baseParts.push(`actionText=${step.actionText}`);
127
+ }
128
+
129
+ return baseParts.join(" | ");
130
+ }
131
+
132
+ async function main() {
133
+ const __filename = fileURLToPath(import.meta.url);
134
+ const __dirname = path.dirname(__filename);
135
+ const repoRoot = path.resolve(__dirname, "../../../../../../../..");
136
+ const defaultReplayPath = path.resolve(
137
+ __dirname,
138
+ "../replays/test-replay.json"
139
+ );
140
+ const defaultLimit = 10;
141
+ const defaultJsonOutput = false;
142
+
143
+ const { replayPath, limit, asJson } = parseArgs(
144
+ defaultReplayPath,
145
+ defaultLimit,
146
+ defaultJsonOutput
147
+ );
148
+
149
+ const { processEpisodeData, getPokerStepsWithEndStates } =
150
+ await loadCoreModules(repoRoot);
151
+
152
+ let replayRaw;
153
+ try {
154
+ replayRaw = await readFile(replayPath, "utf-8");
155
+ } catch (error) {
156
+ console.error(`Failed to read replay at ${replayPath}: ${error.message}`);
157
+ process.exit(1);
158
+ }
159
+
160
+ let replay;
161
+ try {
162
+ replay = JSON.parse(replayRaw);
163
+ } catch (error) {
164
+ console.error(
165
+ `Replay file ${replayPath} is not valid JSON: ${error.message}`
166
+ );
167
+ process.exit(1);
168
+ }
169
+
170
+ const stateHistory = extractStateHistory(replay);
171
+ if (!Array.isArray(stateHistory) || stateHistory.length === 0) {
172
+ console.error("Replay does not contain a state history.");
173
+ process.exit(1);
174
+ }
175
+
176
+ const processedResult = processEpisodeData(
177
+ {
178
+ steps: replay.steps,
179
+ state_history: stateHistory,
180
+ info: replay.info,
181
+ configuration: replay.configuration,
182
+ },
183
+ "repeated_poker"
184
+ );
185
+
186
+ const processedSteps = Array.isArray(processedResult?.steps)
187
+ ? processedResult.steps
188
+ : [];
189
+
190
+ if (processedSteps.length === 0) {
191
+ console.error("Processed episode contains no steps.");
192
+ process.exit(1);
193
+ }
194
+
195
+ const environment = buildEnvironment(
196
+ replay,
197
+ processedSteps,
198
+ processedResult?.info,
199
+ processedResult?.configuration,
200
+ stateHistory
201
+ );
202
+
203
+ const stepsWithEndStates = getPokerStepsWithEndStates(environment);
204
+
205
+ console.log(`Loaded replay: ${replayPath}`);
206
+ console.log(
207
+ `Derived ${stepsWithEndStates.length} entries via getPokerStepsWithEndStates`
208
+ );
209
+
210
+ if (asJson) {
211
+ const subset =
212
+ limit === 0 ? stepsWithEndStates : stepsWithEndStates.slice(0, limit);
213
+ console.log(JSON.stringify(subset, null, 2));
214
+ return;
215
+ }
216
+
217
+ const entriesToPrint =
218
+ limit === 0 ? stepsWithEndStates : stepsWithEndStates.slice(0, limit);
219
+
220
+ entriesToPrint.forEach((entry, index) => {
221
+ console.log(describeStep(entry, index));
222
+ });
223
+
224
+ if (limit > 0 && stepsWithEndStates.length > limit) {
225
+ console.log(
226
+ `\n(${stepsWithEndStates.length - limit} additional entries not shown; rerun with -l 0 to display all or --json for raw output.)`
227
+ );
228
+ }
229
+ }
230
+
231
+ main().catch((error) => {
232
+ console.error("Failed to print steps:", error);
233
+ process.exit(1);
234
+ });