Skip to content

argos-analytics.js #3

@natefrog808

Description

@natefrog808

/**

  • ArgOS Analytics Module
  • Collects and analyzes simulation data to measure agent performance
  • and environmental dynamics
    */

import {
Actions,
SensoryData,
Memory,
Goals,
CognitiveState,
Learning,
Social,
RealityFlux,
Environmental,
Position
} from './argos-framework.js';

export class ArgOSAnalytics {
/**

  • Initialize analytics for an ArgOS simulation

  • @param {Object} world - The BitECS world object
    */
    constructor(world) {
    this.world = world;
    this.data = {
    time: 0,

    // Agent metrics
    agentCount: 0,
    successRates: [], // Success rate history
    avgSuccessRate: 0,
    avgReward: 0,
    avgAdaptability: 0,
    avgEmotionalState: 0,

    // Environmental metrics
    resourceCount: 0,
    obstacleCount: 0,
    hazardCount: 0,

    // Social metrics
    cooperationCount: 0,
    avgTrustLevel: 0,
    alliances: 0,
    rivalries: 0,

    // Reality metrics
    realityShifts: 0,
    activeFluxEffects: 0,
    teleports: 0,
    phases: 0,
    transforms: 0,

    // Historical data (for charting)
    successHistory: [],
    rewardHistory: [],
    cooperationHistory: [],
    resourceHistory: [],
    fluxHistory: []
    };

// Sampling rate (how often to record history)
this.samplingRate = 10; // Every 10 ticks

}

/**

  • Update analytics data based on current world state
  • Should be called every simulation tick
    */
    update() {
    const time = this.world.time;
    this.data.time = time;
// Count entities by type
let agentCount = 0;
let resourceCount = 0;
let obstacleCount = 0;
let hazardCount = 0;

// Agent metrics
let totalSuccessRate = 0;
let totalReward = 0;
let totalAdaptability = 0;
let totalEmotionalState = 0;

// Social metrics
let totalTrustLevel = 0;
let totalCooperationCount = 0;
let totalAlliances = 0;
let totalRivalries = 0;

// Reality metrics
let activeFluxEffects = 0;
let teleports = 0;
let phases = 0;
let transforms = 0;

// Analyze all entities
for (let i = 0; i < this.world.entities.length; i++) {
  const entity = i;
  
  // Count agent types
  if (SensoryData[entity] && Memory[entity] && Goals[entity]) {
    agentCount++;
    
    // Track action success rate
    if (Actions[entity]) {
      totalSuccessRate += Actions.successRate[entity];
    }
    
    // Track learning rewards
    if (Learning[entity]) {
      totalReward += Learning.rewardAccumulator[entity];
    }
    
    // Track cognitive metrics
    if (CognitiveState[entity]) {
      totalAdaptability += CognitiveState.adaptability[entity];
      totalEmotionalState += CognitiveState.emotionalState[entity];
    }
    
    // Track social metrics
    if (Social[entity]) {
      totalTrustLevel += Social.trustLevel[entity];
      totalCooperationCount += Social.cooperationCount[entity];
      
      // Count alliances
      for (let j = 0; j < 5; j++) {
        if (Social.allies[entity * 5 + j] !== 0) {
          totalAlliances++;
        }
        if (Social.rivals[entity * 5 + j] !== 0) {
          totalRivalries++;
        }
      }
    }
  }
  
  // Count environmental entities
  if (Environmental[entity]) {
    switch (Environmental.type[entity]) {
      case 0: resourceCount++; break;
      case 1: obstacleCount++; break;
      case 2: hazardCount++; break;
    }
  }
  
  // Count reality flux effects
  if (RealityFlux[entity] && RealityFlux.effectType[entity] > 0) {
    activeFluxEffects++;
    switch (RealityFlux.effectType[entity]) {
      case 1: teleports++; break;
      case 2: phases++; break;
      case 3: transforms++; break;
    }
  }
}

// Calculate averages
this.data.agentCount = agentCount;
this.data.avgSuccessRate = agentCount > 0 ? totalSuccessRate / agentCount : 0;
this.data.avgReward = agentCount > 0 ? totalReward / agentCount : 0;
this.data.avgAdaptability = agentCount > 0 ? totalAdaptability / agentCount : 0;
this.data.avgEmotionalState = agentCount > 0 ? totalEmotionalState / agentCount : 0;

this.data.resourceCount = resourceCount;
this.data.obstacleCount = obstacleCount;
this.data.hazardCount = hazardCount;

this.data.cooperationCount = totalCooperationCount;
this.data.avgTrustLevel = agentCount > 0 ? totalTrustLevel / agentCount : 0;
this.data.alliances = totalAlliances;
this.data.rivalries = totalRivalries;

this.data.activeFluxEffects = activeFluxEffects;
this.data.teleports = teleports;
this.data.phases = phases;
this.data.transforms = transforms;

// Count reality shifts based on time
if (time % 150 === 0 && time > 0) {
  this.data.realityShifts++;
}

// Record historical data (at sampling rate)
if (time % this.samplingRate === 0) {
  this.data.successHistory.push({
    time: time,
    value: this.data.avgSuccessRate
  });
  
  this.data.rewardHistory.push({
    time: time,
    value: this.data.avgReward
  });
  
  this.data.cooperationHistory.push({
    time: time,
    value: this.data.cooperationCount
  });
  
  this.data.resourceHistory.push({
    time: time,
    value: this.data.resourceCount
  });
  
  this.data.fluxHistory.push({
    time: time,
    value: this.data.activeFluxEffects
  });
  
  // Limit history size to prevent memory issues
  const maxHistoryLength = 100;
  if (this.data.successHistory.length > maxHistoryLength) {
    this.data.successHistory.shift();
    this.data.rewardHistory.shift();
    this.data.cooperationHistory.shift();
    this.data.resourceHistory.shift();
    this.data.fluxHistory.shift();
  }
}

return this.data;

}

/**

  • Render analytics to HTML container
  • @param {HTMLElement} container - The HTML element to render analytics into
    */
    render(container) {
    if (!container) return;
// Format data for display
const data = this.data;
const html = `
  <h3>ArgOS Analytics</h3>
  
  <div class="metrics-grid">
    <div class="metric-card">
      <h4>Simulation</h4>
      <p>Time: <span class="value">${data.time}</span></p>
      <p>Reality Shifts: <span class="value">${data.realityShifts}</span></p>
    </div>
    
    <div class="metric-card">
      <h4>Agents</h4>
      <p>Count: <span class="value">${data.agentCount}</span></p>
      <p>Success Rate: <span class="value">${data.avgSuccessRate.toFixed(1)}%</span></p>
      <p>Avg Reward: <span class="value">${data.avgReward.toFixed(1)}</span></p>
    </div>
    
    <div class="metric-card">
      <h4>Cognitive</h4>
      <p>Adaptability: <span class="value">${data.avgAdaptability.toFixed(1)}</span></p>
      <p>Emotional: <span class="value">${data.avgEmotionalState.toFixed(1)}</span></p>
    </div>
    
    <div class="metric-card">
      <h4>Social</h4>
      <p>Cooperation: <span class="value">${data.cooperationCount}</span></p>
      <p>Trust Level: <span class="value">${data.avgTrustLevel.toFixed(1)}</span></p>
      <p>Alliances: <span class="value">${data.alliances}</span></p>
    </div>
    
    <div class="metric-card">
      <h4>Environment</h4>
      <p>Resources: <span class="value">${data.resourceCount}</span></p>
      <p>Obstacles: <span class="value">${data.obstacleCount}</span></p>
      <p>Hazards: <span class="value">${data.hazardCount}</span></p>
    </div>
    
    <div class="metric-card">
      <h4>Reality Flux</h4>
      <p>Active Effects: <span class="value">${data.activeFluxEffects}</span></p>
      <p>Teleports: <span class="value">${data.teleports}</span></p>
      <p>Phases/Transforms: <span class="value">${data.phases}/${data.transforms}</span></p>
    </div>
  </div>
  
  <canvas id="analytics-chart" width="300" height="150"></canvas>
`;

container.innerHTML = html;

// Render chart if canvas and chart library available
this.renderChart();

}

/**

  • Render analytics chart using Chart.js if available
    */
    renderChart() {
    const canvas = document.getElementById('analytics-chart');
    if (!canvas) return;
// Check if Chart is available (we're assuming Chart.js is loaded)
if (typeof Chart !== 'undefined') {
  // Destroy previous chart if it exists
  if (this.chart) {
    this.chart.destroy();
  }
  
  const ctx = canvas.getContext('2d');
  
  // Create chart with history data
  this.chart = new Chart(ctx, {
    type: 'line',
    data: {
      datasets: [
        {
          label: 'Success Rate',
          data: this.data.successHistory.map(item => ({ x: item.time, y: item.value })),
          borderColor: 'rgba(52, 152, 219, 1)',
          backgroundColor: 'rgba(52, 152, 219, 0.2)',
          tension: 0.3
        },
        {
          label: 'Avg Reward',
          data: this.data.rewardHistory.map(item => ({ x: item.time, y: item.value })),
          borderColor: 'rgba(46, 204, 113, 1)',
          backgroundColor: 'rgba(46, 204, 113, 0.2)',
          tension: 0.3
        },
        {
          label: 'Cooperation',
          data: this.data.cooperationHistory.map(item => ({ x: item.time, y: item.value })),
          borderColor: 'rgba(155, 89, 182, 1)',
          backgroundColor: 'rgba(155, 89, 182, 0.2)',
          tension: 0.3
        }
      ]
    },
    options: {
      responsive: true,
      maintainAspectRatio: false,
      scales: {
        x: {
          type: 'linear',
          title: {
            display: true,
            text: 'Simulation Time'
          }
        },
        y: {
          beginAtZero: true
        }
      }
    }
  });
} else {
  // Fallback to simple text if Chart.js is not available
  canvas.style.display = 'none';
}

}

/**

  • Get a simplified data summary for export
  • @returns {Object} Data summary
    */
    getDataSummary() {
    return {
    simulationTime: this.data.time,
    realityShifts: this.data.realityShifts,
    agentMetrics: {
    count: this.data.agentCount,
    avgSuccessRate: this.data.avgSuccessRate,
    avgReward: this.data.avgReward,
    avgAdaptability: this.data.avgAdaptability
    },
    socialMetrics: {
    cooperationCount: this.data.cooperationCount,
    avgTrustLevel: this.data.avgTrustLevel,
    alliances: this.data.alliances
    },
    environmentMetrics: {
    resources: this.data.resourceCount,
    hazards: this.data.hazardCount
    },
    realityMetrics: {
    activeFluxEffects: this.data.activeFluxEffects
    }
    };
    }

/**

  • Export analytics data as CSV
  • @returns {string} CSV data
    */
    exportAsCSV() {
    const headers = [
    'Time',
    'AgentCount',
    'AvgSuccessRate',
    'AvgReward',
    'ResourceCount',
    'CooperationCount',
    'ActiveFluxEffects'
    ].join(',');
// Combine history data
const rows = [];
for (let i = 0; i < this.data.successHistory.length; i++) {
  const time = this.data.successHistory[i].time;
  const row = [
    time,
    this.data.agentCount,
    this.data.successHistory[i].value.toFixed(2),
    this.data.rewardHistory[i].value.toFixed(2),
    this.data.resourceHistory[i].value,
    this.data.cooperationHistory[i].value,
    this.data.fluxHistory[i].value
  ].join(',');
  
  rows.push(row);
}

return `${headers}\n${rows.join('\n')}`;

}

/**

  • Download analytics data as CSV file
    */
    downloadCSV() {
    const csvContent = this.exportAsCSV();
    const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
    const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.setAttribute('href', url);
link.setAttribute('download', `argos-analytics-${Date.now()}.csv`);
link.style.visibility = 'hidden';

document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);

}

/**

  • Generate a detailed analytics report
  • @returns {Object} Detailed report with analysis
    */
    generateReport() {
    const data = this.data;
// Calculate trends
let successTrend = 'stable';
let rewardTrend = 'stable';

if (this.data.successHistory.length > 5) {
  const recentSuccess = this.data.successHistory.slice(-5);
  const firstValue = recentSuccess[0].value;
  const lastValue = recentSuccess[4].value;
  
  if (lastValue > firstValue * 1.1) {
    successTrend = 'improving';
  } else if (lastValue < firstValue * 0.9) {
    successTrend = 'declining';
  }
  
  const recentReward = this.data.rewardHistory.slice(-5);
  const firstReward = recentReward[0].value;
  const lastReward = recentReward[4].value;
  
  if (lastReward > firstReward * 1.1) {
    rewardTrend = 'improving';
  } else if (lastReward < firstReward * 0.9) {
    rewardTrend = 'declining';
  }
}

// Generate insights
const insights = [];

if (data.avgSuccessRate > 80) {
  insights.push('Agents are performing exceptionally well with high success rates.');
} else if (data.avgSuccessRate < 40) {
  insights.push('Agents are struggling to achieve their goals.');
}

if (data.cooperationCount > data.agentCount * 3) {
  insights.push('High levels of cooperation observed among agents.');
} else if (data.rivalries > data.alliances) {
  insights.push('Competitive behavior dominates over cooperation.');
}

if (data.activeFluxEffects > data.agentCount * 0.5) {
  insights.push('Significant reality distortion affecting agent behavior.');
}

if (successTrend === 'improving' && rewardTrend === 'improving') {
  insights.push('Agents show clear learning and adaptation over time.');
}

return {
  summary: {
    time: data.time,
    agentCount: data.agentCount,
    resourceCount: data.resourceCount,
    realityShifts: data.realityShifts
  },
  performance: {
    avgSuccessRate: data.avgSuccessRate.toFixed(1),
    avgReward: data.avgReward.toFixed(1),
    successTrend,
    rewardTrend
  },
  social: {
    cooperationCount: data.cooperationCount,
    alliances: data.alliances,
    rivalries: data.rivalries
  },
  reality: {
    activeEffects: data.activeFluxEffects,
    totalShifts: data.realityShifts
  },
  insights
};

}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions