<commit_before>// A few polynomial-time primitives for the AI.

var terrain = require('terrain-gen');

// Given a tile position and something to build, find the nearest tile where it
// can be built, or null.
function findConstructionLocation(humanity, tile, b) {
  var dependencies = terrain.buildingDependencies[b];
  dependencies = dependencies || [];
  var sameTileDependency = terrain.buildingTileDependency[b];
  // Aggregate all terrain-based requirements.
  // That includes terrain and things which cannot be built.
  if (isGenerated(sameTileDependency)) {
    var sameTileTerrainDependency = sameTileDependency;
  }
  // List of [number, building type].
  var terrainDependencies = dependencies.filter(function(dep) {
    return isGenerated(dep[1]);
  });
  return humanity.findNearest(tile, function(tile) {
    // This tile must not hold water.
    var terrainTile = terrain(tile);
    if (terrainTile.type === terrain.tileTypes.water) { return false; }
    // Current tile requirement.
    if (sameTileTerrainDependency) {
      var humanityTile = humanity(tile);
      if (!isOneOf(terrainTile.type, sameTileTerrainDependency)) {
        if (humanityTile == null) { return false; }
        if (!isOneOf(humanityTile.b, sameTileTerrainDependency)) {
          return false;
        }
      }
    }
    // For each surrounding dependency, count the surroundings.
    for (var i = 0; i < terrainDependencies.length; i++) {
      var dependencyCount = terrainDependencies[i][0];
      var dependencyType = terrainDependencies[i][1];
      var count = 0;
      for (var j = 0; j < 6; j++) {
        var neighbor = terrain.neighborFromTile(tile, j);
        var humanityNeighbor = humanity(neighbor);
        if (terrain(neighbor).type === dependencyType
          || (humanityNeighbor && humanityNeighbor.b === dependencyType)) {
          count++;
        }
      }
      if (count < dependencyCount) {
        return false;
      }
    }
    // Check that the build order succeeds.
    if (dependencyBuilds(humanity, b, tile) != null) {
      return true;
    } else { return false; }
  });
}

// Given a building type (number), returns true if it can be built.
function isBuilding(b) {
  return terrain.buildingTypes.indexOf(b) >= 0;
}

// Given a dependency item (building, terrain, resource), returns true if that
// dependency was generated by the world.
function isGenerated(b) {
  // b can be negative if it is a resource.
  return  b >= 0 && !isBuilding(b);
}

// buildings: list of building types (as numbers).
// b: building.
// Returns true if b is either one of the buildings in the list.
function isOneOf(b, buildings) {
  return buildings.indexOf(b) >= 0;
}

// tile: {q,r}
// tiles: [{q,r}]
// Returns true if `tile` is one of the tiles in `tiles`.
function tileIsOneOf(tile, tiles) {
  for (var i = 0; i < tiles.length; i++) {
    if (sameTile(tile, tiles[i])) { return true; }
  }
  return false;
}

// Compute the set of buildings to build, in order, to be able to build
// something specific, on a tile.
// b: terrain.tileTypes
// tile: {q,r}
// forbiddenTiles: [{q,r}]
// Returns a list of {tile: {q,r}, building: type} that needs to be
// constructed, in the correct order (see terrain.tileTypes).
// FIXME: keep track of what gets destroyed and created while building.
// FIXME: don't destroy buildings which cost resources.
function dependencyBuilds(humanity, b, tile, forbiddenTiles) {
  forbiddenTiles = forbiddenTiles || [];
  // List of {tile: {q,r}, building: type}.
  var buildings = [];
  var dependencies = terrain.buildingDependencies[b];
  dependencies = dependencies || [];
  for (var i = 0; i < dependencies.length; i++) {
    var number = dependencies[i][0];
    var buildingType = dependencies[i][1];
    // Ignore resource requirements…
    if (buildingType < 0) { continue; }
    // Ignore terrain requirements…
    if (!isBuilding(buildingType)) { continue; }
    var dependencySatisfied = false;

    // Is what we are looking for already built there?
    for (var j = 0; j < 6; j++) {
      var neighbor = terrain.neighborFromTile(tile, j);
      var neighborHumanity = humanity(neighbor);
      var neighborTerrain = terrain(neighbor);
      if (neighborHumanity
        && (neighborHumanity.b === buildingType
         || neighborTerrain.type === buildingType)) {
        forbiddenTiles = forbiddenTiles.concat(neighbor);
        number -= 1;
        if (number <= 0) {
          // We have built everything of this type of building.
          dependencySatisfied = true;
          break;
        }
      }
    }
    if (number <= 0) { continue; }

    // Choose a random starting neighbor, check all neighbors.
    var startingNeighbor = (Math.random() * 6)|0;
    for (var j = 0; j < 6; j++) {
      var n = (j + startingNeighbor) % 6;
      var neighbor = terrain.neighborFromTile(tile, n);
      // Is this neighbor constructible?
      var neighborTerrain = terrain(neighbor);
      if (neighborTerrain.type === terrain.tileTypes.water) { continue; }
      // Is this neighbor authorized?
      if (tileIsOneOf(neighbor, forbiddenTiles)) { continue; }
      var neighborBuildings =
        dependencyBuilds(humanity, buildingType, neighbor, forbiddenTiles);
      if (neighborBuildings != null) {
        // We can build that.
        buildings = buildings.concat(neighborBuildings);
        var lastNeighborBuilding =
          neighborBuildings[neighborBuildings.length - 1];
        // We mustn't destroy this tile, it is needed to build `b`.
        forbiddenTiles = forbiddenTiles.concat(lastNeighborBuilding.tile);
        number -= 1;
        if (number <= 0) {
          // We have built everything of this type of building.
          dependencySatisfied = true;
          break;
        }
      }
    }
    if (!dependencySatisfied) { return null; }
  }
  // We have built all the dependencies, now we can build the final piece.
  buildings.push({ tile: tile, building: b });
  return buildings;
}

// Find nearest terrain where nothing is built.
// size: number of layers that must be empty around the tile.
function findNearestEmpty(humanity, tile, size) {<commit_msg>AI: Keep track of what gets destroyed / created while building.<commit_after>// A few polynomial-time primitives for the AI.

var terrain = require('terrain-gen');

// Given a tile position and something to build, find the nearest tile where it
// can be built, or null.
function findConstructionLocation(humanity, tile, b) {
  var dependencies = terrain.buildingDependencies[b];
  dependencies = dependencies || [];
  var sameTileDependency = terrain.buildingTileDependency[b];
  // Aggregate all terrain-based requirements.
  // That includes terrain and things which cannot be built.
  if (isGenerated(sameTileDependency)) {
    var sameTileTerrainDependency = sameTileDependency;
  }
  // List of [number, building type].
  var terrainDependencies = dependencies.filter(function(dep) {
    return isGenerated(dep[1]);
  });
  return humanity.findNearest(tile, function(tile) {
    // This tile must not hold water.
    var terrainTile = terrain(tile);
    if (terrainTile.type === terrain.tileTypes.water) { return false; }
    // Current tile requirement.
    if (sameTileTerrainDependency) {
      var humanityTile = humanity(tile);
      if (!isOneOf(terrainTile.type, sameTileTerrainDependency)) {
        if (humanityTile == null) { return false; }
        if (!isOneOf(humanityTile.b, sameTileTerrainDependency)) {
          return false;
        }
      }
    }
    // For each surrounding dependency, count the surroundings.
    for (var i = 0; i < terrainDependencies.length; i++) {
      var dependencyCount = terrainDependencies[i][0];
      var dependencyType = terrainDependencies[i][1];
      var count = 0;
      for (var j = 0; j < 6; j++) {
        var neighbor = terrain.neighborFromTile(tile, j);
        var humanityNeighbor = humanity(neighbor);
        if (terrain(neighbor).type === dependencyType
          || (humanityNeighbor && humanityNeighbor.b === dependencyType)) {
          count++;
        }
      }
      if (count < dependencyCount) {
        return false;
      }
    }
    // Check that the build order succeeds.
    if (dependencyBuilds(humanity, b, tile) != null) {
      return true;
    } else { return false; }
  });
}

// Given a building type (number), returns true if it can be built.
function isBuilding(b) {
  return terrain.buildingTypes.indexOf(b) >= 0;
}

// Given a dependency item (building, terrain, resource), returns true if that
// dependency was generated by the world.
function isGenerated(b) {
  // b can be negative if it is a resource.
  return  b >= 0 && !isBuilding(b);
}

// buildings: list of building types (as numbers).
// b: building.
// Returns true if b is either one of the buildings in the list.
function isOneOf(b, buildings) {
  return buildings.indexOf(b) >= 0;
}

// tile: {q,r}
// tiles: [{q,r}]
// Returns true if `tile` is one of the tiles in `tiles`.
function tileIsOneOf(tile, tiles) {
  for (var i = 0; i < tiles.length; i++) {
    if (sameTile(tile, tiles[i])) { return true; }
  }
  return false;
}

// Compute the set of buildings to build, in order, to be able to build
// something specific, on a tile.
// b: terrain.tileTypes
// tile: {q,r}
// forbiddenTiles: [{q,r}]
// override: map from "q:r" to building type, showing buildings that
//   will be built during the construction.
// Returns a list of {tile: {q,r}, building: type} that needs to be
// constructed, in the correct order (see terrain.tileTypes).
// FIXME: don't destroy buildings which cost resources.
// FIXME: don't destroy buildings of the type we're creating.
function dependencyBuilds(humanity, b, tile, forbiddenTiles, override) {
  forbiddenTiles = forbiddenTiles || [];

  // Keep track of what gets destroyed and created while building.
  override = override || Object.create(null);
  var buildingOnTile = function(tile) {
    var tileKey = terrain.keyFromTile(tile);
    if (override[tileKey] != null) {
      return override[tileKey];
    }
    var humanityTile = humanity(tile);
    if (humanityTile == null) { return null; }
    return humanityTile.b;
  };

  // List of {tile: {q,r}, building: type}.
  var buildings = [];
  var dependencies = terrain.buildingDependencies[b];
  dependencies = dependencies || [];
  for (var i = 0; i < dependencies.length; i++) {
    var number = dependencies[i][0];
    var buildingType = dependencies[i][1];
    // Ignore resource requirements…
    if (buildingType < 0) { continue; }
    // Ignore terrain requirements…
    if (!isBuilding(buildingType)) { continue; }
    var dependencySatisfied = false;

    // Is what we are looking for already built there?
    for (var j = 0; j < 6; j++) {
      var neighbor = terrain.neighborFromTile(tile, j);
      var neighborTerrain = terrain(neighbor);
      if (buildingOnTile(neighbor) === buildingType
        || neighborTerrain.type === buildingType) {
        forbiddenTiles = forbiddenTiles.concat(neighbor);
        number -= 1;
        if (number <= 0) {
          // We have built everything of this type of building.
          dependencySatisfied = true;
          break;
        }
      }
    }
    if (number <= 0) { continue; }

    // Choose a random starting neighbor, check all neighbors.
    var startingNeighbor = (Math.random() * 6)|0;
    for (var j = 0; j < 6; j++) {
      var n = (j + startingNeighbor) % 6;
      var neighbor = terrain.neighborFromTile(tile, n);
      // Is this neighbor constructible?
      var neighborTerrain = terrain(neighbor);
      if (neighborTerrain.type === terrain.tileTypes.water) { continue; }
      // Is this neighbor authorized?
      if (tileIsOneOf(neighbor, forbiddenTiles)) { continue; }
      var neighborBuildings =
        dependencyBuilds(humanity, buildingType, neighbor,
            forbiddenTiles, override);
      if (neighborBuildings != null) {
        // We can build that.
        buildings = buildings.concat(neighborBuildings);
        var lastNeighborBuilding =
          neighborBuildings[neighborBuildings.length - 1];
        // We mustn't destroy this tile, it is needed to build `b`.
        forbiddenTiles = forbiddenTiles.concat(lastNeighborBuilding.tile);
        number -= 1;
        if (number <= 0) {
          // We have built everything of this type of building.
          dependencySatisfied = true;
          break;
        }
      }
    }
    if (!dependencySatisfied) { return null; }
  }
  // We have built all the dependencies, now we can build the final piece.
  buildings.push({ tile: tile, building: b });
  override[terrain.keyFromTile(tile)] = b;
  return buildings;
}

// Find nearest terrain where nothing is built.
// size: number of layers that must be empty around the tile.
function findNearestEmpty(humanity, tile, size) {
{'fraction_non_alphanumeric': 0.11557357872572721, 'fraction_numerical': 0.004367152772362162, 'mean_word_length': 2.9145299145299144, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 9, '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': '458022', 'n_tokens_mistral': 3727, 'n_tokens_neox': 3604, 'n_words': 1239}