mirror of
https://github.com/GoodStartLabs/AI_Diplomacy.git
synced 2026-04-23 16:59:10 +00:00
166 lines
No EOL
5.6 KiB
JavaScript
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;
|
|
} |