trigo / trigo-web /tools /tgnToMoveSequence.ts
k-l-lambda's picture
Update trigo-web with VS People multiplayer mode
15f353f
#!/usr/bin/env node
/**
* Convert TGN files to move sequences (JSON format)
*
* Output format for C++ consumption:
* {
* "boardShape": { "x": 5, "y": 5, "z": 1 },
* "moves": [
* { "x": 1, "y": 2, "z": 0, "player": 1 }, // BLACK = 1
* { "x": 2, "y": 2, "z": 0, "player": 2 }, // WHITE = 2
* null, // pass move
* ...
* ]
* }
*/
import { TrigoGame, StoneType, StepType } from "@inc/trigo/game.js";
import { calculateTerritory } from "@inc/trigo/gameUtils.js";
import { initializeParsers } from "@inc/trigo/parserInit.js";
import * as fs from "fs";
import * as path from "path";
interface MoveSequenceOutput {
tgnFile: string;
boardShape: { x: number; y: number; z: number };
moves: Array<{ x: number; y: number; z: number; player: number } | null>;
finalBoard: number[][][];
territory: {
black: number;
white: number;
neutral: number;
};
error?: string;
}
function convertTgnToMoveSequence(tgnFilePath: string): MoveSequenceOutput {
try {
const tgnContent = fs.readFileSync(tgnFilePath, "utf-8");
// Parse TGN
const game = TrigoGame.fromTGN(tgnContent);
const shape = game.getShape();
const history = game.getHistory();
// Convert steps to simple move format
const moveSequence = history
.filter(step => step.type === StepType.DROP || step.type === StepType.PASS)
.map(step => {
if (step.type === StepType.PASS) {
return null; // Pass move
}
if (step.type === StepType.DROP && step.position) {
return {
x: step.position.x,
y: step.position.y,
z: step.position.z,
player: step.player === StoneType.BLACK ? 1 : 2 // BLACK = 1, WHITE = 2
};
}
return null;
});
// Get final board state and territory
const board = game.getBoard();
const territory = calculateTerritory(board, shape);
return {
tgnFile: path.basename(tgnFilePath),
boardShape: shape,
moves: moveSequence,
finalBoard: board,
territory: {
black: territory.black,
white: territory.white,
neutral: territory.neutral
}
};
} catch (error) {
return {
tgnFile: path.basename(tgnFilePath),
boardShape: { x: 0, y: 0, z: 0 },
moves: [],
finalBoard: [],
territory: { black: 0, white: 0, neutral: 0 },
error: error instanceof Error ? error.message : String(error)
};
}
}
function main() {
const args = process.argv.slice(2);
if (args.length === 0) {
console.error("Usage: tgnToMoveSequence.ts <tgn_file> [<tgn_file> ...]");
console.error("");
console.error("Converts TGN files to move sequences for C++ validation.");
console.error("Outputs JSON to stdout.");
process.exit(1);
}
// Initialize parsers first
initializeParsers().then(() => {
const results: MoveSequenceOutput[] = [];
for (const tgnFile of args) {
if (!fs.existsSync(tgnFile)) {
console.error(`File not found: ${tgnFile}`);
results.push({
tgnFile: path.basename(tgnFile),
boardShape: { x: 0, y: 0, z: 0 },
moves: [],
finalBoard: [],
territory: { black: 0, white: 0, neutral: 0 },
error: "File not found"
});
continue;
}
const result = convertTgnToMoveSequence(tgnFile);
results.push(result);
}
// Output as JSON
console.log(JSON.stringify(results, null, 2));
}).catch(error => {
console.error("Error initializing parsers:", error);
process.exit(1);
});
}
main();