<commit_before>const _ = require('lodash');
const Entity = require('./entity');
const simulateWorld = require('./simulator');

function fitness (expectedPosition, entity) {
  var distance = {
    x: Math.abs(expectedPosition.x - entity.x),
    y: Math.abs(expectedPosition.y - entity.y)
  };

  return 1000 - (distance.x + distance.y);
}

function limitTo (limit, number) {
  return _.max([limit, number]);
}

function weightedAverage (scoresPerScenario) {
  return Math.sqrt(_.sum(scoresPerScenario.map(score => Math.pow(limitTo(0, score), 2))) / scoresPerScenario.length);
}

function boilDownIndividualScore (individual, participant, fitnesses) {
  return weightedAverage(
    _.values(fitnesses[participant][individual])
      .map(scoresForScenario => weightedAverage(scoresForScenario))
  );
}

function scoreScenario (scenario, fitnesses, individuals) {
  scenario.participants.forEach(participant => {
    scoreParticipantOnScenario(scenario, participant, fitnesses, individuals[participant]);
  });
}

function scoreParticipantOnScenario (scenario, participant, fitnesses, individuals) {
  individuals.forEach(individual => {
    scoreIndividualOnScenario(scenario, participant, individual, fitnesses);
  });
}

function scoreIndividualOnScenario (scenario, participant, individual, fitnesses) {
  // This is where we call up a variant on the original simulation code
  // Note that exactly one participant is allowed to vary at each point
  var currentFrame = 0;

  if (fitnesses[participant][individual] === undefined) {
    fitnesses[participant][individual] = {};
  };

  fitnesses[participant][individual][scenario.id] = [];

  var entities = scenario.participants.map(participantForEntity => {
    var initial = scenario.initialPositions[participantForEntity];
    var expectedPositions = scenario.expectedPositions[participantForEntity] || [];

    if (participantForEntity === participant) {
      return new Entity(individual, initial, expectedPositions, true);
    } else {
      return new Entity([], initial, expectedPositions, false);
    }
  });

  var activeEntity = _.find(entities, 'active');

  scenario.expectedPositions[participant].forEach(expectedPosition => {
    var frameCount = expectedPosition.frame - currentFrame;

    simulateWorld(entities, frameCount, scenario.input, currentFrame);

    currentFrame = expectedPosition.frame;
    var evaluatedFitness = fitness(expectedPosition, activeEntity);

    fitnesses[participant][individual][scenario.id].push(evaluatedFitness);
  });
}

module.exports = {scoreScenario, boilDownIndividualScore};
<commit_msg>Use pythag's theory for fitness distance calculation<commit_after>const _ = require('lodash');
const Entity = require('./entity');
const simulateWorld = require('./simulator');

function fitness (expectedPosition, entity) {
  var distance = {
    x: Math.abs(expectedPosition.x - entity.x),
    y: Math.abs(expectedPosition.y - entity.y)
  };

  return 1000 - Math.sqrt(Math.pow(distance.x, 2) + Math.pow(distance.y, 2));
}

function limitTo (limit, number) {
  return _.max([limit, number]);
}

function weightedAverage (scoresPerScenario) {
  return Math.sqrt(_.sum(scoresPerScenario.map(score => Math.pow(limitTo(0, score), 2))) / scoresPerScenario.length);
}

function boilDownIndividualScore (individual, participant, fitnesses) {
  return weightedAverage(
    _.values(fitnesses[participant][individual])
      .map(scoresForScenario => weightedAverage(scoresForScenario))
  );
}

function scoreScenario (scenario, fitnesses, individuals) {
  scenario.participants.forEach(participant => {
    scoreParticipantOnScenario(scenario, participant, fitnesses, individuals[participant]);
  });
}

function scoreParticipantOnScenario (scenario, participant, fitnesses, individuals) {
  individuals.forEach(individual => {
    scoreIndividualOnScenario(scenario, participant, individual, fitnesses);
  });
}

function scoreIndividualOnScenario (scenario, participant, individual, fitnesses) {
  // This is where we call up a variant on the original simulation code
  // Note that exactly one participant is allowed to vary at each point
  var currentFrame = 0;

  if (fitnesses[participant][individual] === undefined) {
    fitnesses[participant][individual] = {};
  };

  fitnesses[participant][individual][scenario.id] = [];

  var entities = scenario.participants.map(participantForEntity => {
    var initial = scenario.initialPositions[participantForEntity];
    var expectedPositions = scenario.expectedPositions[participantForEntity] || [];

    if (participantForEntity === participant) {
      return new Entity(individual, initial, expectedPositions, true);
    } else {
      return new Entity([], initial, expectedPositions, false);
    }
  });

  var activeEntity = _.find(entities, 'active');

  scenario.expectedPositions[participant].forEach(expectedPosition => {
    var frameCount = expectedPosition.frame - currentFrame;

    simulateWorld(entities, frameCount, scenario.input, currentFrame);

    currentFrame = expectedPosition.frame;
    var evaluatedFitness = fitness(expectedPosition, activeEntity);

    fitnesses[participant][individual][scenario.id].push(evaluatedFitness);
  });
}

module.exports = {scoreScenario, boilDownIndividualScore};

{'fraction_non_alphanumeric': 0.11825095057034221, 'fraction_numerical': 0.003041825095057034, 'mean_word_length': 5.248218527315914, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7353520', 'n_tokens_mistral': 1563, 'n_tokens_neox': 1435, 'n_words': 324}