AI_Diplomacy/diplomacy/animation/utils/converter.js
2025-03-04 11:35:02 -08:00

166 lines
No EOL
5.6 KiB
JavaScript

/**
* Utility functions for converting between different diplomacy game file formats
*/
/**
* Convert AI Diplomacy results format to animation format
* @param {Object} resultsData - Results data from AI Diplomacy
* @returns {Object} Formatted game data compatible with the animation system
*/
export function convertResultsToAnimationFormat(resultsData) {
// Create a base game data structure
const gameData = {
map_name: "standard",
game_id: resultsData.game_id || "ai-diplomacy-game",
phases: []
};
// Extract phases from the results data
if (resultsData.rounds && Array.isArray(resultsData.rounds)) {
console.log(`Processing ${resultsData.rounds.length} rounds from results file`);
// Convert each round to a phase
gameData.phases = resultsData.rounds.map((round, index) => {
// Extract phase info
const phase = {
name: round.name || `Round ${index + 1}`,
year: round.year || 1900 + Math.floor(index / 3),
season: round.season || (index % 3 === 0 ? "SPRING" : (index % 3 === 1 ? "FALL" : "WINTER")),
type: round.type || (index % 3 === 2 ? "ADJUSTMENT" : "MOVEMENT"),
units: [],
orders: [],
results: [],
messages: round.messages || [],
index: index
};
// Extract unit positions
if (round.state && round.state.units) {
// Convert units to expected format
for (const [power, units] of Object.entries(round.state.units)) {
if (Array.isArray(units)) {
units.forEach(unit => {
// Parse unit info (e.g., "A PAR" or "F BRE")
const match = unit.match(/^([AF])\s+(.+)$/);
if (match) {
const unitType = match[1]; // 'A' or 'F'
const location = match[2];
// Create a unique ID for the unit
const unitId = `${power.toUpperCase()}_${unitType}_${location}_${index}`;
phase.units.push({
id: unitId,
type: unitType,
power: power.toUpperCase(),
location: location
});
}
});
}
}
}
// Extract orders
if (round.orders) {
for (const [power, orders] of Object.entries(round.orders)) {
if (Array.isArray(orders)) {
orders.forEach(order => {
// Extract the region from the order (e.g., "A PAR-BUR" -> "PAR")
const regionMatch = order.match(/^[AF]\s+([A-Za-z_/]+)/);
const region = regionMatch ? regionMatch[1] : "";
// Standardize the order format
let standardizedOrder = order;
standardizedOrder = standardizedOrder
.replace(/([A-Z]{3})\s*-\s*([A-Z]{3})/g, '$1-$2')
.replace(/([A-Z]{3})\s*H/g, '$1 H')
.replace(/([A-Z]{3})\s*S\s*([AF])\s*([A-Z]{3})/g, '$1 S $2 $3');
phase.orders.push({
text: standardizedOrder,
power: power.toUpperCase(),
region: region,
success: true // Default to true unless specified otherwise
});
});
}
}
}
return phase;
});
}
return gameData;
}
/**
* Detect the format of a game file and convert it if needed
* @param {Object} data - The loaded game data
* @returns {Object} Game data in the correct format for animation
*/
export function processGameFile(data) {
// Detect if this is a results file or a standard game file
if (data.rounds && Array.isArray(data.rounds)) {
// This appears to be a results file, convert it
console.log('Detected results file format, converting...');
return convertResultsToAnimationFormat(data);
}
// Standard game file format with phases array
if (data.phases && Array.isArray(data.phases)) {
console.log('Standard game format detected');
return data;
}
// Legacy format with state_history
if (data.state_history) {
console.log('Legacy format detected (state_history)');
// Convert to standard format
const convertedData = {
map_name: data.map_name || 'standard',
game_id: data.game_id || 'legacy-game',
phases: []
};
// Extract phases from state_history
const stateHistory = data.state_history;
const orderHistory = data.order_history || {};
const resultHistory = data.result_history || {};
const phases = [];
Object.entries(stateHistory).forEach(([phaseName, state], index) => {
phases.push({
name: phaseName,
year: state.year || '?',
season: state.season || '?',
type: state.type || '?',
units: state.units || [],
centers: state.centers || {},
orders: orderHistory[phaseName] ? Object.values(orderHistory[phaseName]) : [],
results: resultHistory[phaseName] ? Object.values(resultHistory[phaseName]) : [],
index: index
});
});
// Sort phases by year, season, and type
phases.sort((a, b) => {
if (a.year !== b.year) return a.year - b.year;
if (a.season !== b.season) {
const seasons = ['SPRING', 'SUMMER', 'FALL', 'AUTUMN', 'WINTER'];
return seasons.indexOf(a.season) - seasons.indexOf(b.season);
}
const types = ['MOVEMENT', 'RETREAT', 'ADJUSTMENT', 'BUILD'];
return types.indexOf(a.type) - types.indexOf(b.type);
});
convertedData.phases = phases;
return convertedData;
}
// Unknown format
console.warn('Unknown game file format');
return data;
}