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.
- kaggle_environments/envs/connectx/visualizer/default/index.html +13 -0
- kaggle_environments/envs/connectx/visualizer/default/package.json +22 -0
- kaggle_environments/envs/connectx/visualizer/default/replays/test-replay.json +1129 -0
- kaggle_environments/envs/connectx/visualizer/default/src/main.ts +12 -0
- kaggle_environments/envs/connectx/visualizer/default/src/renderer.ts +396 -0
- kaggle_environments/envs/connectx/visualizer/default/src/style.css +38 -0
- kaggle_environments/envs/connectx/visualizer/default/tsconfig.json +4 -0
- kaggle_environments/envs/connectx/visualizer/default/vite.config.ts +7 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/repeated_poker.js +163 -88
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/index.html +13 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/package.json +23 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/replays/test-replay.json +1 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/scripts/print_first_steps.mjs +202 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/scripts/print_replay.mjs +215 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/scripts/print_steps_with_end_states.mjs +234 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/getRepeatedPokerStateForStep.js +260 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/utils.ts +61 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/debug_repeated_poker_renderer.ts +49 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_1.svg +22 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_10.svg +22 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_100.svg +48 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_25.svg +22 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_5.svg +22 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/main.ts +36 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/repeated_poker_renderer.ts +573 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/style.css +594 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/tsconfig.json +7 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/vite.config.ts +6 -0
- kaggle_environments/envs/werewolf/README.md +190 -0
- kaggle_environments/envs/werewolf/harness/__init__.py +0 -0
- kaggle_environments/envs/werewolf/harness/base.py +773 -0
- kaggle_environments/envs/werewolf/harness/litellm_models.yaml +51 -0
- kaggle_environments/envs/werewolf/harness/main.py +54 -0
- kaggle_environments/envs/werewolf/harness/test_base.py +35 -0
- kaggle_environments/envs/werewolf/runner.py +146 -0
- kaggle_environments/envs/werewolf/scripts/__init__.py +0 -0
- kaggle_environments/envs/werewolf/scripts/add_audio.py +425 -0
- kaggle_environments/envs/werewolf/scripts/configs/audio/standard.yaml +24 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/block_basic.yaml +102 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/comprehensive.yaml +100 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/roundrobin_discussion_DisableDoctorSelfSave_DisableDoctorConsecutiveSave_large.yaml +104 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/roundrobin_discussion_large.yaml +103 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/roundrobin_discussion_small.yaml +103 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard.yaml +103 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_DisableDoctorConsecutiveSave.yaml +104 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_SeerRevealTeam.yaml +105 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_SeerRevealTeam_NightEliminationNoReveal_DayExileNoReveal.yaml +105 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_SeerRevealTeam_NightEliminationRevealTeam_DayExileRevealTeam.yaml +105 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_disable_doctor_self_save.yaml +103 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_parallel_voting.yaml +103 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_parallel_voting_no_tie_exile.yaml +103 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_parallel_voting_roundbiddiscussion.yaml +105 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/run_config.yaml +58 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/vertex_api_example_config.yaml +115 -0
- kaggle_environments/envs/werewolf/scripts/measure_cost.py +251 -0
- kaggle_environments/envs/werewolf/scripts/plot_existing_trajectories.py +135 -0
- kaggle_environments/envs/werewolf/scripts/rerender_html.py +87 -0
- kaggle_environments/envs/werewolf/scripts/run.py +93 -0
- kaggle_environments/envs/werewolf/scripts/run_block.py +237 -0
- kaggle_environments/envs/werewolf/scripts/run_pairwise_matrix.py +222 -0
- kaggle_environments/envs/werewolf/scripts/self_play.py +196 -0
- kaggle_environments/envs/werewolf/scripts/utils.py +47 -0
- kaggle_environments/envs/werewolf/werewolf.json +1 -1
- {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/METADATA +1 -1
- {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/RECORD +68 -7
- {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/WHEEL +0 -0
- {kaggle_environments-1.22.6.dist-info → kaggle_environments-1.24.3.dist-info}/entry_points.txt +0 -0
- {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
|
+
});
|