Skip to content

Instantly share code, notes, and snippets.

@Andersgee
Created July 7, 2022 11:08
Show Gist options
  • Save Andersgee/52cf13f54638bd78d143f94c79bcae1f to your computer and use it in GitHub Desktop.
Save Andersgee/52cf13f54638bd78d143f94c79bcae1f to your computer and use it in GitHub Desktop.
var CODE_VERSION = '6a5c8d06';/* The contents of this file will be copied unmodified to the top of your build. */
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./src/ability/jump.ts":
/*!*****************************!*\
!*** ./src/ability/jump.ts ***!
\*****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "jumpCost": () => (/* binding */ jumpCost),
/* harmony export */ "maxJumpDistance": () => (/* binding */ maxJumpDistance),
/* harmony export */ "canJump": () => (/* binding */ canJump),
/* harmony export */ "jumpPoint": () => (/* binding */ jumpPoint)
/* harmony export */ });
/* harmony import */ var _vec__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../vec */ "./src/vec.ts");
/**
* all shapes can use jump() . Formula: jump cost = distance/4 + (size^2) / 4
*/
function jumpCost(ship, point) {
return (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(ship.position, point) / 4 + Math.pow(ship.size, 2) / 4;
}
/**
* ```raw
* The maximum distance a ship can jump.
*
* energyMargin is how much the ship needs to still have after completed jump. default 0.
*
* d/4 + (size^2)/4 = cost
* d/4 = cost - (size^2)/4
* d = 4*( cost - (size^2)/4 )
* d = 4*cost - (size^2)
*
* maxDist = 4*shipEnergy - shipSize^2
*
* affordableDistance = 4*(shipEnergy-energyMargin) - shipSize^2
* ```
*/
function maxJumpDistance(ship, energyMargin = 0) {
return 4 * (ship.energy - energyMargin) - Math.pow(ship.size, 2);
}
/**
* True if has enough energy to jump to point
*
* energyMargin is how much the ship needs to still have after completed jump. default 0.
*/
function canJump(ship, point, energyMargin = 0) {
return ship.energy - energyMargin >= jumpCost(ship, point);
}
/**
* return the point ship would land at if it jumped toward target point.
*
* energyMargin is how much the ship needs to have (at least) after jumping
*
* 1. if CAN reach point: return point
* 2. if CAN NOT reach point: return the maximum jumpable point in the point direction
*/
function jumpPoint(ship, point, energyMargin = 0) {
if (canJump(ship, point, energyMargin)) {
return point;
} else {
const d = maxJumpDistance(ship, energyMargin);
const reachablePoint = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.offset)(ship.position, point, d);
return reachablePoint;
}
}
/***/ }),
/***/ "./src/collections.ts":
/*!****************************!*\
!*** ./src/collections.ts ***!
\****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "collections": () => (/* binding */ collections)
/* harmony export */ });
/* harmony import */ var _vec__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./vec */ "./src/vec.ts");
const collections = getCollections();
function getCollections() {
const playerids = getPlayerIds();
const shapes = getShapes();
const bases = getBases();
const outposts = getOutposts();
const stars = getStars();
const {
myships,
enemyships
} = getShips();
const pylons = getPylons();
const info = getInfo(playerids, outposts, pylons);
return {
playerids,
shapes,
bases,
outposts,
stars,
myships,
enemyships,
info,
pylons
};
}
function getShapes() {
const bases = getBases(); //const me = base.shape;
//const enemy = enemy_base.shape;
return {
me: bases.me.shape,
enemy: bases.enemy.shape
};
}
function getBases() {
const playerids = getPlayerIds(); //base_zxq.player_id
//base_a2c.player_id
const myBase = base_zxq.player_id === playerids.me ? base_zxq : base_a2c;
const notMyBase = base_zxq.player_id === playerids.me ? base_a2c : base_zxq; //console.log("base_zxq.player_id", base_zxq.player_id);
return {
me: myBase,
enemy: notMyBase,
middle: base_p89,
big: base_nua
};
}
function getOutposts() {
return {
middle: outpost_mdo
};
}
function getPylons() {
return {
middle: pylon_u3p
};
}
function getPlayerIds() {
const me = this_player_id;
const enemy = players.p1 === me ? players.p2 : players.p1;
return {
me,
enemy
};
}
function getShips() {
//work with arrays instead of objects
const playerids = getPlayerIds();
const ships = Array.from(Object.values(spirits));
const myships = ships.filter(ship => ship.id.startsWith(playerids.me) && ship.hp > 0);
const enemyships = ships.filter(ship => ship.id.startsWith(playerids.enemy) && ship.hp > 0); //myships
for (const [index, ship] of myships.entries()) {
ship.index = index;
ship.nearbyfriends_includingself = myships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 200));
ship.nearbyfriends = myships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 200) && index !== s.index);
ship.nearbyfriends300 = myships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 300) && index !== s.index);
ship.nearbyfriends20 = myships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 20));
ship.nearbyfriends40 = myships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 40));
ship.nearbyfriends60 = myships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 60));
ship.nearbyenemies = enemyships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 200));
ship.nearbyenemies220 = enemyships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 220));
ship.nearbyenemies240 = enemyships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 240));
ship.nearbyenemies260 = enemyships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 260));
ship.nearbyenemies300 = enemyships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 300));
ship.nearbyenemies320 = enemyships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 320));
ship.nearbyenemies400 = enemyships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 400));
const allfriends = myships.filter(s => s.index !== index); //all myships except self
ship.nearestfriend = allfriends[(0,_vec__WEBPACK_IMPORTED_MODULE_0__.minimum)(allfriends.map(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(s.position, ship.position))).index];
ship.nearestenemy = enemyships[(0,_vec__WEBPACK_IMPORTED_MODULE_0__.minimum)(enemyships.map(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(s.position, ship.position))).index];
} //enemyships
for (const [index, ship] of enemyships.entries()) {
ship.index = index;
ship.nearbyfriends_includingself = enemyships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 200));
ship.nearbyfriends = enemyships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 200) && index !== s.index);
ship.nearbyfriends300 = myships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 300) && index !== s.index);
ship.nearbyfriends20 = enemyships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 20));
ship.nearbyfriends40 = enemyships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 40));
ship.nearbyfriends60 = enemyships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 60));
ship.nearbyenemies = myships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 200));
ship.nearbyenemies220 = myships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 220));
ship.nearbyenemies240 = myships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 240));
ship.nearbyenemies260 = myships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 260));
ship.nearbyenemies300 = myships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 300));
ship.nearbyenemies400 = myships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, s.position, 400));
const allfriends = enemyships.filter(s => s.index !== index); //all myships except self
ship.nearestfriend = allfriends[(0,_vec__WEBPACK_IMPORTED_MODULE_0__.minimum)(allfriends.map(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(s.position, ship.position))).index];
ship.nearestenemy = myships[(0,_vec__WEBPACK_IMPORTED_MODULE_0__.minimum)(myships.map(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(s.position, ship.position))).index];
}
return {
myships,
enemyships
};
}
function getStars() {
const bases = getBases();
const dist_base2zxq = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(bases.me.position, star_zxq.position);
const dist_base2a2c = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(bases.me.position, star_a2c.position); //const dist_base2p89 = vec.dist(base.position, star_p89.position)
const stars = {
me: star_zxq,
middle: star_p89,
enemy: star_a2c,
big: star_nua
};
if (dist_base2a2c < dist_base2zxq) {
stars.me = star_a2c;
stars.enemy = star_zxq;
}
return stars;
}
function getInfo(playerids, outposts, pylons) {
const outpostcontrolIsMe = playerids.me === outposts.middle.control;
const outpostcontrolIsEnemy = playerids.enemy === outposts.middle.control;
const pyloncontrolIsMe = playerids.me === pylons.middle.control;
const pyloncontrolIsEnemy = playerids.enemy === pylons.middle.control;
return {
outpostcontrolIsMe,
outpostcontrolIsEnemy,
pyloncontrolIsMe,
pyloncontrolIsEnemy
};
}
/***/ }),
/***/ "./src/combateval.ts":
/*!***************************!*\
!*** ./src/combateval.ts ***!
\***************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ combateval)
/* harmony export */ });
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./collections */ "./src/collections.ts");
/* harmony import */ var _find__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./find */ "./src/find.ts");
/* harmony import */ var _vec__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./vec */ "./src/vec.ts");
/**
* ```raw
* Evaluate (to the end) what happens if ships attack each other.
*
* return some metrics. Most importantly "myAdvantage"
* ```
*/
function combateval(myships, enemyships) {
let [myships_m, enemyships_m] = evalBattle1tick(myships, enemyships);
let someoneCanAttack = (0,_vec__WEBPACK_IMPORTED_MODULE_2__.sum)(myships_m.map(s => s.energy)) + (0,_vec__WEBPACK_IMPORTED_MODULE_2__.sum)(enemyships_m.map(s => s.energy)) > 0;
while (someoneCanAttack && myships_m.length > 0 && enemyships_m.length > 0) {
[myships_m, enemyships_m] = evalBattle1tick(myships_m, enemyships_m);
someoneCanAttack = (0,_vec__WEBPACK_IMPORTED_MODULE_2__.sum)(myships_m.map(s => s.energy)) + (0,_vec__WEBPACK_IMPORTED_MODULE_2__.sum)(enemyships_m.map(s => s.energy)) > 0;
}
const meIsLastStanding = myships_m.length > enemyships_m.length;
const myEnergycost = (0,_vec__WEBPACK_IMPORTED_MODULE_2__.sum)(myships.map(s => s.energy)) - (0,_vec__WEBPACK_IMPORTED_MODULE_2__.sum)(myships_m.map(s => s.energy));
const enemyEnergycost = (0,_vec__WEBPACK_IMPORTED_MODULE_2__.sum)(enemyships.map(s => s.energy)) - (0,_vec__WEBPACK_IMPORTED_MODULE_2__.sum)(enemyships_m.map(s => s.energy));
const myAliveIndexes = myships_m.map(s => s.index);
const myDeadShips = (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_not_in)(myships, myAliveIndexes);
const myDeadShipsCost = (0,_vec__WEBPACK_IMPORTED_MODULE_2__.sum)(myDeadShips.map(s => shipcost(s, "me")));
const enemyAliveIndexes = enemyships_m.map(s => s.index);
const enemyDeadShips = (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_not_in)(enemyships, enemyAliveIndexes);
const enemyDeadShipsCost = (0,_vec__WEBPACK_IMPORTED_MODULE_2__.sum)(enemyDeadShips.map(s => shipcost(s, "enemy")));
const myValueLoss = myEnergycost + myDeadShipsCost;
const enemyValueLoss = enemyEnergycost + enemyDeadShipsCost;
const myAdvantage = enemyValueLoss - myValueLoss;
return {
myAdvantage,
meIsLastStanding,
myEnergycost,
enemyEnergycost,
myDeadShipsCost,
enemyDeadShipsCost,
myValueLoss,
enemyValueLoss
};
}
/**
* Lowest energy first
*/
function sortByShipenergy(ships) {
return ships.slice().sort((a, b) => a.energy - b.energy);
}
/**
* Biggest energy first
*/
function sortByShipenergyReverse(ships) {
return ships.slice().sort((a, b) => b.energy - a.energy);
}
/*
function shipcost(ship: Ship | Ship_m, player = "enemy"): number {
const { bases, shapes } = collections;
const cost = bases[player].current_spirit_cost;
if (shapes[player] === "squares") {
return cost - 100;
} else if (shapes[player] === "circles") {
return cost * ship.size - 10 * ship.size;
} else if (shapes[player] === "triangles") {
return cost - 30;
}
return cost;
}
*/
function shipcost(ship, player = "enemy") {
const {
bases,
shapes
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections; //const cost = bases[player].current_spirit_cost;
if (shapes[player] === "squares") {
return 360 - 100;
} else if (shapes[player] === "circles") {
return (25 - 10) * ship.size; //for circles, ship.size effectively is NUMBER of ships (single ship has size 1)
} else {
//if (shapes[player] === "triangles") {
return 90 - 30;
}
}
function lossFromAttacking(ship) {
//ship.size, but only as much energy as it has.
return Math.min(ship.size, ship.energy);
}
function attackdmg(ship) {
//2*ship.size, but only as much energy as it has.
return 2 * Math.min(ship.size, ship.energy);
}
function evalBattle1tick(ships1, ships2) {
//first make ships1 (order by LARGEST first) attack ships2 (order by LOWEST first)
const attackers = sortByShipenergyReverse(ships1); //biggest first
const defenders = sortByShipenergy(ships2); //lowest first
const energy_attackers = attackers.map(s => s.energy);
const energy_defenders = defenders.map(s => s.energy);
const attackers_alreadyattacked = new Array(energy_attackers.length).fill(false);
for (const [i, defender] of defenders.entries()) {
const defloss = lossFromAttacking(defender);
for (const [j, attacker] of attackers.entries()) {
if (energy_defenders[i] - defloss >= 0 && !attackers_alreadyattacked[j]) {
energy_defenders[i] -= attackdmg(attacker);
energy_attackers[j] -= lossFromAttacking(attacker);
attackers_alreadyattacked[j] = true;
}
}
}
const energy_attackers_change = attackers.map((s, i) => energy_attackers[i] - s.energy);
const energy_defenders_change = defenders.map((s, i) => energy_defenders[i] - s.energy); /////
const attackers2 = sortByShipenergyReverse(ships2); //biggest first
const defenders2 = sortByShipenergy(ships1); //lowest first
const energy_attackers2 = attackers2.map(s => s.energy);
const energy_defenders2 = defenders2.map(s => s.energy);
const attackers_alreadyattacked2 = new Array(energy_attackers2.length).fill(false);
for (const [i, defender] of defenders2.entries()) {
const defloss = lossFromAttacking(defender);
for (const [j, attacker] of attackers2.entries()) {
if (energy_defenders2[i] - defloss >= 0 && !attackers_alreadyattacked2[j]) {
energy_defenders2[i] -= attackdmg(attacker);
energy_attackers2[j] -= lossFromAttacking(attacker);
attackers_alreadyattacked2[j] = true;
}
}
}
const energy_attackers2_change = attackers2.map((s, i) => energy_attackers2[i] - s.energy).reverse();
const energy_defenders2_change = defenders2.map((s, i) => energy_defenders2[i] - s.energy).reverse(); ////
//energy_attackers_change now corresponds to energy_defenders2_change and same order
//energy_defenders now corresponds to energy_attackers2_change and same order
const consolidated_attackerchange = energy_attackers_change.map((x, i) => x + energy_defenders2_change[i]);
const consolidated_defenderchange = energy_defenders_change.map((x, i) => x + energy_attackers2_change[i]);
const resulting_energy_attackers = attackers.map((s, i) => s.energy + consolidated_attackerchange[i]);
const resulting_energy_defenders = defenders.map((s, i) => s.energy + consolidated_defenderchange[i]);
const resulting_attackers = attackers.map((s, i) => ({
index: s.index,
size: s.size,
energy: resulting_energy_attackers[i]
})).filter(s => s.energy >= 0);
const resulting_defenders = defenders.map((s, i) => ({
index: s.index,
size: s.size,
energy: resulting_energy_defenders[i]
})).filter(s => s.energy >= 0);
return [resulting_attackers, resulting_defenders];
}
/***/ }),
/***/ "./src/constants.ts":
/*!**************************!*\
!*** ./src/constants.ts ***!
\**************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "D": () => (/* binding */ D),
/* harmony export */ "D_LONG": () => (/* binding */ D_LONG),
/* harmony export */ "BLOCK_RANGE": () => (/* binding */ BLOCK_RANGE),
/* harmony export */ "EXPLODE_RANGE": () => (/* binding */ EXPLODE_RANGE)
/* harmony export */ });
const D = 199.9999; //the value to use when offsetting points
const D_LONG = 299.9999;
/** disables spawning if enemy within this distance of base */
const BLOCK_RANGE = 400;
/** killing itself and dealing 10 damage to all enemy spirits */
const EXPLODE_RANGE = 160;
/***/ }),
/***/ "./src/energize/energize.ts":
/*!**********************************!*\
!*** ./src/energize/energize.ts ***!
\**********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ energize)
/* harmony export */ });
/* harmony import */ var _energize_enemy_ships__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./energize_enemy_ships */ "./src/energize/energize_enemy_ships.ts");
/* harmony import */ var _energize_self__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./energize_self */ "./src/energize/energize_self.ts");
/* harmony import */ var _energize_enemy_structures__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./energize_enemy_structures */ "./src/energize/energize_enemy_structures.ts");
/* harmony import */ var _energize_neutral_structures__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./energize_neutral_structures */ "./src/energize/energize_neutral_structures.ts");
/* harmony import */ var _energize_bases_from_starships__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./energize_bases_from_starships */ "./src/energize/energize_bases_from_starships.ts");
/* harmony import */ var _energize_friends_in_need__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./energize_friends_in_need */ "./src/energize/energize_friends_in_need.ts");
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../collections */ "./src/collections.ts");
/**
* ```raw
* The general idea is:
*
* 1. energize enemy ships (2:1)
* 2. energize self
*
* 3. energize friends in need
* 3.1. from starships (chain)
* 3.2. from nearbyfriend (but as close to a star as possible)
*
* 4. energize enemy structures
* 4.1. bases
* 4.2. outpost
* 4.3. pylon
* 5. energize neutral structures
* 5.1. bases
* 5.2. outpost
* 5.3. pylon
* 6. energize bases from from starships (chain)
* ```
*/
function energize(orders) {
const energizing = [];
const attacking = [];
if (tick < 27) {
special_earlygame(orders);
return;
}
(0,_energize_self__WEBPACK_IMPORTED_MODULE_1__.default)(orders.targets, energizing);
(0,_energize_enemy_ships__WEBPACK_IMPORTED_MODULE_0__.default)(orders.targets, energizing, attacking);
(0,_energize_friends_in_need__WEBPACK_IMPORTED_MODULE_5__.default)(orders.targets, energizing, attacking);
(0,_energize_enemy_structures__WEBPACK_IMPORTED_MODULE_2__.default)(orders.targets, energizing);
(0,_energize_neutral_structures__WEBPACK_IMPORTED_MODULE_3__.default)(orders.targets, energizing);
(0,_energize_bases_from_starships__WEBPACK_IMPORTED_MODULE_4__.default)(orders.targets, energizing);
}
function special_earlygame(orders) {
const {
myships,
stars
} = _collections__WEBPACK_IMPORTED_MODULE_6__.collections;
for (const ship of myships) {
orders.targets[ship.index] = stars.me;
}
}
/***/ }),
/***/ "./src/energize/energize_bases_from_starships.ts":
/*!*******************************************************!*\
!*** ./src/energize/energize_bases_from_starships.ts ***!
\*******************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ energize_bases_from_starships)
/* harmony export */ });
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../collections */ "./src/collections.ts");
/* harmony import */ var _find__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../find */ "./src/find.ts");
/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../utils */ "./src/utils.ts");
/* harmony import */ var _pointsLong__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../pointsLong */ "./src/pointsLong.ts");
function energize_bases_from_starships(targets, energizing) {
const {
stars,
bases,
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
energize_base_when_in_both_base_and_star_range(targets, energizing, bases.me, stars.me);
energize_base_when_in_both_base_and_star_range(targets, energizing, bases.enemy, stars.enemy);
energize_base_when_in_both_base_and_star_range(targets, energizing, bases.middle, stars.middle); //"star.big -> ship -> fragment -> ship -> base.me" chain
energize_fragment_when_in_both_fragment_and_star_range(targets, energizing, stars.big, _pointsLong__WEBPACK_IMPORTED_MODULE_3__.pointsLong.b2 //fragment point
);
energize_base_when_in_both_base_and_fragment_range(targets, energizing, bases.me, _pointsLong__WEBPACK_IMPORTED_MODULE_3__.pointsLong.b2 //fragment point
);
}
function energize_base_when_in_both_base_and_fragment_range(targets, energizing, base, fragmentPoint) {
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const myshipsInRange = (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_not_in)(myships, energizing).filter(s => (0,_utils__WEBPACK_IMPORTED_MODULE_2__.canEnergize)(s, fragmentPoint) && (0,_utils__WEBPACK_IMPORTED_MODULE_2__.canEnergize)(s, base));
for (const ship of myshipsInRange) {
if ((0,_utils__WEBPACK_IMPORTED_MODULE_2__.isFull)(ship)) {
targets[ship.index] = base;
energizing.push(ship.index);
}
}
return;
}
function energize_fragment_when_in_both_fragment_and_star_range(targets, energizing, star, fragmentPoint) {
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const myshipsInRange = (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_not_in)(myships, energizing).filter(s => (0,_utils__WEBPACK_IMPORTED_MODULE_2__.canEnergize)(s, fragmentPoint) && (0,_utils__WEBPACK_IMPORTED_MODULE_2__.canEnergize)(s, star));
for (const ship of myshipsInRange) {
if ((0,_utils__WEBPACK_IMPORTED_MODULE_2__.isFull)(ship)) {
//energize position on "ground", will "merge" with any existing fragment around this general area
//TODO: find out what size this "area" is where it auto merges with existing fragment
targets[ship.index] = fragmentPoint;
energizing.push(ship.index);
}
}
return;
}
function energize_base_when_in_both_base_and_star_range(targets, energizing, base, star) {
if (!(0,_utils__WEBPACK_IMPORTED_MODULE_2__.controlIsMe)(base.control)) return;
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const myshipsInRange = (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_not_in)(myships, energizing).filter(s => (0,_utils__WEBPACK_IMPORTED_MODULE_2__.canEnergize)(s, base) && (0,_utils__WEBPACK_IMPORTED_MODULE_2__.canEnergize)(s, star));
for (const ship of myshipsInRange) {
if ((0,_utils__WEBPACK_IMPORTED_MODULE_2__.isFull)(ship)) {
targets[ship.index] = base; //energize base
energizing.push(ship.index);
}
}
return;
}
/*
function energize_base_from_star_chain(
targets: Target[],
energizing: Vec,
star: Star,
base: Base
): void {
const { myships } = collections;
if (!controlIsMe(base.control)) return;
const sourceShips = ships_not_in(myships, energizing).filter((s) =>
isWithinDist(star.position, s.position)
);
const sourceShipsIndexes = sourceShips.map((s) => s.index);
const destinationShips = ships_not_in(myships, energizing).filter((s) =>
isWithinDist(base.position, s.position)
);
if (destinationShips.length < 1) return;
const destinationShipsIndexes = destinationShips.map((s) => s.index);
const graphShips = ships_not_in(myships, energizing);
const sending: Vec = [];
const recieving: Vec = [];
sources: for (const sourceShip of sourceShips) {
// destination ships that can recieve at least one more transfer
const availableDestinationShips = ships_not_in(destinationShips, recieving);
if (availableDestinationShips.length < 1) return;
// prune away sources, desinations and those already sending or recieving
const ignoreIndexes = sourceShipsIndexes
.concat(destinationShipsIndexes)
.concat(sending)
.concat(recieving);
let availableGraphShips = ships_not_in(graphShips, ignoreIndexes);
availableGraphShips.push(sourceShip); //add back current sourceShip
availableGraphShips = availableGraphShips.concat(availableDestinationShips); //add back available desinationships
const G = constructGraph(availableGraphShips);
const chainShips = path_firstavailable(
graphShips,
G,
sourceShip,
availableDestinationShips
);
//console.log(`chain: ${chainShips.map((s) => s.index + 1)}`);
if (chainShips.length < 2) return;
//we now know there is a chain from star to base.
//but a ship in between might be empty
for (let i = 0; i < chainShips.length - 1; i++) {
if (isEmpty(chainShips[i])) continue sources;
const sender = chainShips[i];
const reciever = chainShips[i + 1]; //next in chain
targets[sender.index] = reciever;
energizing.push(sender.index);
sending.push(sender.index);
recieving.push(reciever.index);
//sender.shout("s");
}
const destinationShip = chainShips[chainShips.length - 1];
if (notEmpty(destinationShip)) {
targets[destinationShip.index] = base; //energize base
recieving.push(destinationShip.index); //might not actually want to make this "busy" in case I want to send more to it...
//destinationShip.shout("d");
}
}
return;
}
*/
/***/ }),
/***/ "./src/energize/energize_enemy_ships.ts":
/*!**********************************************!*\
!*** ./src/energize/energize_enemy_ships.ts ***!
\**********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ energize_enemy_ships)
/* harmony export */ });
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../collections */ "./src/collections.ts");
/* harmony import */ var _find__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../find */ "./src/find.ts");
/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../utils */ "./src/utils.ts");
/**
* Attack enemies in range, in a way that does not overkill an enemy.
*/
function energize_enemy_ships(targets, energizing, attacking) {
const {
enemyships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const assumeNheals = 0;
for (const enemyship of (0,_find__WEBPACK_IMPORTED_MODULE_1__.sortByShipenergy)(enemyships)) {
const myshipsInRange300 = (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_not_in)(enemyship.nearbyenemies300, energizing);
const myshipsInRange = myshipsInRange300.filter(myship => (0,_utils__WEBPACK_IMPORTED_MODULE_2__.canEnergize)(myship, enemyship)); //const potentialHeal = sum(enemyship.nearbyfriends.map(transferamount));
const enemyHealth = enemyship.energy - (0,_utils__WEBPACK_IMPORTED_MODULE_2__.lossFromAttacking)(enemyship);
const enemyshipEnergy = enemyHealth + assumeNheals * enemyship.size;
let dmgdealt = 0;
for (const myship of myshipsInRange) {
if (dmgdealt <= enemyshipEnergy) {
if ((0,_utils__WEBPACK_IMPORTED_MODULE_2__.notEmpty)(myship)) {
targets[myship.index] = enemyship;
dmgdealt += (0,_utils__WEBPACK_IMPORTED_MODULE_2__.attackdmg)(myship);
energizing.push(myship.index);
attacking.push(myship.index);
}
}
}
}
}
/***/ }),
/***/ "./src/energize/energize_enemy_structures.ts":
/*!***************************************************!*\
!*** ./src/energize/energize_enemy_structures.ts ***!
\***************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ energize_enemy_structures)
/* harmony export */ });
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../collections */ "./src/collections.ts");
/* harmony import */ var _find__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../find */ "./src/find.ts");
/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../utils */ "./src/utils.ts");
function energize_enemy_structures(targets, energizing) {
const {
bases,
outposts,
pylons
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
for (const base of [bases.big, bases.enemy, bases.me, bases.middle]) {
energize_enemy_base(targets, energizing, base);
}
for (const outpost of [outposts.middle]) {
energize_enemy_outpost(targets, energizing, outpost);
}
for (const pylon of [pylons.middle]) {
energize_enemy_pylon(targets, energizing, pylon);
}
}
function energize_enemy_base(targets, energizing, base) {
if (!(0,_utils__WEBPACK_IMPORTED_MODULE_2__.controlIsEnemy)(base.control)) return;
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const myshipsNearBase = (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_not_in)(myships, energizing).filter(s => (0,_utils__WEBPACK_IMPORTED_MODULE_2__.canEnergize)(s, base));
for (const ship of myshipsNearBase) {
if ((0,_utils__WEBPACK_IMPORTED_MODULE_2__.notEmpty)(ship)) {
targets[ship.index] = base;
energizing.push(ship.index);
}
}
}
function energize_enemy_outpost(targets, energizing, outpost) {
if (!(0,_utils__WEBPACK_IMPORTED_MODULE_2__.controlIsEnemy)(outpost.control)) return;
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const myshipsNearOutpost = (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_not_in)(myships, energizing).filter(s => (0,_utils__WEBPACK_IMPORTED_MODULE_2__.canEnergize)(s, outpost));
for (const ship of myshipsNearOutpost) {
if ((0,_utils__WEBPACK_IMPORTED_MODULE_2__.notEmpty)(ship)) {
targets[ship.index] = outpost;
energizing.push(ship.index);
}
}
}
function energize_enemy_pylon(targets, energizing, pylon) {
if (!(0,_utils__WEBPACK_IMPORTED_MODULE_2__.controlIsEnemy)(pylon.control)) return;
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const myshipsNearOutpost = (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_not_in)(myships, energizing).filter(s => (0,_utils__WEBPACK_IMPORTED_MODULE_2__.canEnergize)(s, pylon));
for (const ship of myshipsNearOutpost) {
if ((0,_utils__WEBPACK_IMPORTED_MODULE_2__.notEmpty)(ship)) {
targets[ship.index] = pylon;
energizing.push(ship.index);
}
}
}
/***/ }),
/***/ "./src/energize/energize_friends_in_need.ts":
/*!**************************************************!*\
!*** ./src/energize/energize_friends_in_need.ts ***!
\**************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ energize_friends_in_need)
/* harmony export */ });
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../collections */ "./src/collections.ts");
/* harmony import */ var _find__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../find */ "./src/find.ts");
/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../utils */ "./src/utils.ts");
function energize_friends_in_need(targets, energizing, attacking) {
//heal_attackers_from_star_ships(targets, energizing, attacking);
heal_attackers_from_nearby_friends(targets, energizing, attacking);
}
function heal_attackers_from_nearby_friends(targets, energizing, attacking) {
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const myAttackingShips = (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_in)(myships, attacking);
for (const myAttacker of myAttackingShips) {
const shipFriends300 = (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_not_in)(myAttacker.nearbyfriends300, energizing);
const shipFriends = shipFriends300.filter(s => (0,_utils__WEBPACK_IMPORTED_MODULE_2__.canEnergize)(s, myAttacker));
let requiredHeal = myAttacker.energy_capacity - myAttacker.energy + (0,_utils__WEBPACK_IMPORTED_MODULE_2__.transferamount)(myAttacker);
for (const myHealer of shipFriends) {
const healAmount = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.transferamount)(myHealer);
if (requiredHeal < healAmount) break;
targets[myHealer.index] = myAttacker;
energizing.push(myHealer.index);
requiredHeal -= healAmount;
}
}
}
/***/ }),
/***/ "./src/energize/energize_neutral_structures.ts":
/*!*****************************************************!*\
!*** ./src/energize/energize_neutral_structures.ts ***!
\*****************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ energize_neutral_structures)
/* harmony export */ });
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../collections */ "./src/collections.ts");
/* harmony import */ var _find__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../find */ "./src/find.ts");
/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../utils */ "./src/utils.ts");
function energize_neutral_structures(targets, energizing) {
const {
bases,
outposts,
pylons
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
for (const base of [bases.big, bases.enemy, bases.me, bases.middle]) {
energize_neutral_base(targets, energizing, base);
}
for (const outpost of [outposts.middle]) {
energize_neutral_outpost(targets, energizing, outpost);
}
/*
for (const pylon of [pylons.middle]) {
energize_neutral_pylon(targets, energizing, pylon);
}
*/
}
function energize_neutral_base(targets, energizing, base) {
if (!(0,_utils__WEBPACK_IMPORTED_MODULE_2__.controlIsNeutral)(base.control)) return;
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const myshipsNearBase = (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_not_in)(myships, energizing).filter(s => (0,_utils__WEBPACK_IMPORTED_MODULE_2__.canEnergize)(s, base));
for (const ship of myshipsNearBase) {
if ((0,_utils__WEBPACK_IMPORTED_MODULE_2__.notEmpty)(ship)) {
targets[ship.index] = base;
energizing.push(ship.index);
}
}
}
function energize_neutral_outpost(targets, energizing, outpost) {
if (!(0,_utils__WEBPACK_IMPORTED_MODULE_2__.controlIsNeutral)(outpost.control)) return;
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const myshipsNearOutpost = (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_not_in)(myships, energizing).filter(s => (0,_utils__WEBPACK_IMPORTED_MODULE_2__.canEnergize)(s, outpost));
for (const ship of myshipsNearOutpost) {
if ((0,_utils__WEBPACK_IMPORTED_MODULE_2__.notEmpty)(ship)) {
targets[ship.index] = outpost;
energizing.push(ship.index);
}
}
}
function energize_neutral_pylon(targets, energizing, pylon) {
if (!(0,_utils__WEBPACK_IMPORTED_MODULE_2__.controlIsNeutral)(pylon.control)) return;
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const myshipsNearPylon = (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_not_in)(myships, energizing).filter(s => (0,_utils__WEBPACK_IMPORTED_MODULE_2__.canEnergize)(s, pylon));
for (const ship of myshipsNearPylon) {
if ((0,_utils__WEBPACK_IMPORTED_MODULE_2__.notEmpty)(ship)) {
targets[ship.index] = pylon;
energizing.push(ship.index);
}
}
}
/***/ }),
/***/ "./src/energize/energize_self.ts":
/*!***************************************!*\
!*** ./src/energize/energize_self.ts ***!
\***************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ energize_self)
/* harmony export */ });
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../collections */ "./src/collections.ts");
/* harmony import */ var _find__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../find */ "./src/find.ts");
/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../utils */ "./src/utils.ts");
/* harmony import */ var _vec__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../vec */ "./src/vec.ts");
/**
* note: If a spirit can harvest from a star or from a fragment, it will prioritize the fragment.
*/
function energize_self(targets, energizing) {
const {
stars,
bases
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
/*
if (tick < 100) {
maybeBoostInstead(targets, energizing, stars.me);
}
*/
const ignoreSustBigstar = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.controlIsEnemy)(bases.big.control);
const ignoreSustMeStar = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.controlIsEnemy)(bases.me.control);
const ignoreSustMiddleStar = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.controlIsEnemy)(bases.middle.control);
const ignoreSustEnemyStar = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.controlIsEnemy)(bases.enemy.control);
energize_self_star(targets, energizing, stars.big, ignoreSustBigstar);
energize_self_star(targets, energizing, stars.middle, ignoreSustMiddleStar);
energize_self_star(targets, energizing, stars.me, ignoreSustMeStar);
energize_self_star(targets, energizing, stars.enemy, ignoreSustEnemyStar);
for (const fragment of fragments) {
energize_self_fragment(targets, energizing, fragment);
}
}
function energize_self_fragment(targets, energizing, fragment) {
const {
myships,
bases
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const myshipsnearfragment = (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_not_in)(myships, energizing).filter(s => (0,_utils__WEBPACK_IMPORTED_MODULE_2__.canEnergize)(s, fragment.position) && (0,_utils__WEBPACK_IMPORTED_MODULE_2__.canEnergize)(s, bases.me));
let currentFragmentEnergy = fragment.energy * 1;
for (const ship of myshipsnearfragment) {
if ((0,_utils__WEBPACK_IMPORTED_MODULE_2__.notFull)(ship) && currentFragmentEnergy > 0) {
targets[ship.index] = ship; //energize self
energizing.push(ship.index);
currentFragmentEnergy -= (0,_utils__WEBPACK_IMPORTED_MODULE_2__.gainFromSelfing)(ship);
}
}
}
function energize_self_star(targets, energizing, star, ignoreSust = false) {
const {
myships,
bases
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const myshipsInRangeOfStar = (0,_find__WEBPACK_IMPORTED_MODULE_1__.sortByIsMovingToHeal)((0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_not_in)(myships, energizing).filter(s => (0,_utils__WEBPACK_IMPORTED_MODULE_2__.canEnergize)(s, star)));
let currentExtraStarEnergy = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.sustainableStarSelfingAmount)(star); //I can actually take more because it will sustain 2 constant farmers at 900 aswell
//or in the case of big star: 9 constant farmers at 2900 energy
//however, we still want it to grow.
//so only 50 for normal stars and 66 for big stars to make sure it grows.
if (star.energy_capacity === 1000 && star.energy > star.energy_capacity - 50) {
const additionalFarmable = star.energy - (star.energy_capacity - 50);
currentExtraStarEnergy += additionalFarmable;
} else if (star.energy_capacity === 3000 && star.energy > star.energy_capacity - 66) {
const additionalFarmable = star.energy - (star.energy_capacity - 66);
currentExtraStarEnergy += additionalFarmable;
} //some conditions here. in particular early game mid star farming
const ignoreSustainable = ignoreSust || myshipsInRangeOfStar.length === 1;
for (const ship of myshipsInRangeOfStar) {
const transferedEnergy = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.gainFromSelfing)(ship);
if ((0,_utils__WEBPACK_IMPORTED_MODULE_2__.notFull)(ship) && (ignoreSustainable || currentExtraStarEnergy - transferedEnergy > 0)) {
targets[ship.index] = ship; //energize self
energizing.push(ship.index);
currentExtraStarEnergy -= transferedEnergy;
}
}
}
function maybeBoostInstead(targets, energizing, star) {
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const myshipsInRangeOfStar = (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_not_in)(myships, energizing).filter(s => (0,_utils__WEBPACK_IMPORTED_MODULE_2__.canEnergize)(s, star)); //half the time the ship would not take from the star
const sumEnergyTakenPerTick = 0.5 * (0,_vec__WEBPACK_IMPORTED_MODULE_3__.sum)(myshipsInRangeOfStar.map(_utils__WEBPACK_IMPORTED_MODULE_2__.gainFromSelfing));
const currentExtraStarEnergy = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.sustainableStarSelfingAmount)(star);
if (sumEnergyTakenPerTick <= currentExtraStarEnergy) return; //no need
for (const ship of myshipsInRangeOfStar) {
targets[ship.index] = star; //boost star
energizing.push(ship.index);
}
}
/***/ }),
/***/ "./src/find.ts":
/*!*********************!*\
!*** ./src/find.ts ***!
\*********************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "ship_closest": () => (/* binding */ ship_closest),
/* harmony export */ "ship_closest_to_point": () => (/* binding */ ship_closest_to_point),
/* harmony export */ "ships_closestN": () => (/* binding */ ships_closestN),
/* harmony export */ "sortByNearestenemyDistance": () => (/* binding */ sortByNearestenemyDistance),
/* harmony export */ "sortByNearestenemyDistanceReverse": () => (/* binding */ sortByNearestenemyDistanceReverse),
/* harmony export */ "sortByNearestDistance": () => (/* binding */ sortByNearestDistance),
/* harmony export */ "sortByIsMovingToHeal": () => (/* binding */ sortByIsMovingToHeal),
/* harmony export */ "sortByNearestDistanceReverse": () => (/* binding */ sortByNearestDistanceReverse),
/* harmony export */ "sortByShipenergy": () => (/* binding */ sortByShipenergy),
/* harmony export */ "sortByShipenergyReverse": () => (/* binding */ sortByShipenergyReverse),
/* harmony export */ "ships_in": () => (/* binding */ ships_in),
/* harmony export */ "ships_not_in": () => (/* binding */ ships_not_in),
/* harmony export */ "is_in": () => (/* binding */ is_in),
/* harmony export */ "not_in": () => (/* binding */ not_in),
/* harmony export */ "shipFromIndex": () => (/* binding */ shipFromIndex),
/* harmony export */ "shipFromId": () => (/* binding */ shipFromId),
/* harmony export */ "ship_is_in_ships": () => (/* binding */ ship_is_in_ships),
/* harmony export */ "ship_is_not_in_ships": () => (/* binding */ ship_is_not_in_ships)
/* harmony export */ });
/* harmony import */ var _vec__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./vec */ "./src/vec.ts");
/**
* ```raw
* Return the ship (not in busy) that is closest to point p.
*
* Note: Will return undefined if the passed ships array is empty or none not busy ships.
* ```
*/
function ship_closest(ships, p, busy = []) {
const freeships = ships_not_in(ships, busy);
const distances = freeships.map(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(s.position, p));
const ship = freeships[(0,_vec__WEBPACK_IMPORTED_MODULE_0__.minimum)(distances).index];
return ship;
}
function ship_closest_to_point(ships, p) {
const distances = ships.map(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(s.position, p));
const ship = ships[(0,_vec__WEBPACK_IMPORTED_MODULE_0__.minimum)(distances).index];
return ship;
}
/**
* Return the N ships that is closest to point p.
*/
function ships_closestN(ships, p, N) {
const sortedships = ships.slice().sort((a, b) => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(a.position, p) - (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(b.position, p));
return sortedships.slice(0, N);
}
/**
* Smallest distance first, as compared to ship.position to ship.nearestenemy.position (which is different for each ship)
*/
function sortByNearestenemyDistance(ships) {
return ships.slice().sort((a, b) => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(a.position, a.nearestenemy.position) - (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(b.position, b.nearestenemy.position));
}
/**
* Biggest distance first, as compared to ship.position to ship.nearestenemy.position (which is different for each ship)
*/
function sortByNearestenemyDistanceReverse(ships) {
return ships.slice().sort((a, b) => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(b.position, b.nearestenemy.position) - (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(a.position, a.nearestenemy.position));
}
/**
* Smallest distance first, as compared to ship.position to targetpoint
*/
function sortByNearestDistance(ships, targetpoint) {
return ships.slice().sort((a, b) => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(a.position, targetpoint) - (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(b.position, targetpoint));
}
function isMovingToHealComparator(a, b) {
const A = memory.movingToHealIds.includes(a.id);
const B = memory.movingToHealIds.includes(b.id);
if (A && !B) {
return -1;
}
if (!A && B) {
return 1;
}
return 0;
}
/**
* Moving to heal first. uses memory.isMovingToHealComparator
*/
function sortByIsMovingToHeal(ships) {
return ships.slice().sort(isMovingToHealComparator);
}
/**
* Biggest distance first, as compared to ship.position to targetpoint
*/
function sortByNearestDistanceReverse(ships, targetpoint) {
return ships.slice().sort((a, b) => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(b.position, targetpoint) - (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(a.position, targetpoint));
}
/**
* Lowest energy first
*/
function sortByShipenergy(ships) {
return ships.slice().sort((a, b) => a.energy - b.energy);
}
/**
* Biggest energy first
*/
function sortByShipenergyReverse(ships) {
return ships.slice().sort((a, b) => b.energy - a.energy);
}
/**
* Return all ships that DOES have a ship.index listed in the vector indexes.
*/
function ships_in(ships, indexes) {
return ships.filter(ship => indexes.includes(ship.index));
}
/**
* Return all ships that does NOT have a ship.index listed in the vector indexes.
*/
function ships_not_in(ships, indexes) {
return ships.filter(ship => !indexes.includes(ship.index));
}
/**
* Return true if ship.index is in indexes
*/
function is_in(ship, indexes) {
return indexes.includes(ship.index);
}
/**
* Return true if ship.index is NOT in indexes
*/
function not_in(ship, indexes) {
return !indexes.includes(ship.index);
}
/**
* Return the ship with index i (if it exists)
*/
function shipFromIndex(ships, i) {
return ships.find(s => s.index === i);
}
/**
* Return the ship with index i (if it exists)
*/
function shipFromId(ships, id) {
return ships.find(s => s.id === id);
}
/**
* Return true if ship exist in array ships
*/
function ship_is_in_ships(ship, ships) {
const foundShip = ships.find(s => s.index === ship.index);
if (foundShip === undefined) {
return false;
} else {
return true;
}
}
/**
* Return true if ship.index is NOT in any of ships indexes
*/
function ship_is_not_in_ships(ship, ships) {
return !ship_is_in_ships(ship, ships);
}
/***/ }),
/***/ "./src/move/move.ts":
/*!**************************!*\
!*** ./src/move/move.ts ***!
\**************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ move)
/* harmony export */ });
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../collections */ "./src/collections.ts");
/* harmony import */ var _find__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../find */ "./src/find.ts");
/* harmony import */ var _move_defend_against_harassers__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./move_defend_against_harassers */ "./src/move/move_defend_against_harassers.ts");
/* harmony import */ var _move_farm__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./move_farm */ "./src/move/move_farm.ts");
/* harmony import */ var _move_avoid__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./move_avoid */ "./src/move/move_avoid.ts");
/* harmony import */ var _move_heal__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./move_heal */ "./src/move/move_heal.ts");
/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../constants */ "./src/constants.ts");
/* harmony import */ var _vec__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../vec */ "./src/vec.ts");
/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../utils */ "./src/utils.ts");
/* harmony import */ var _move_strategic__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./move_strategic */ "./src/move/move_strategic.ts");
/**
* ```raw
* The general idea is:
* - Farm and prevent spawn blocking
* - Strategic orders
* - Avoid bad movements (combat eval)
* - go and heal - some sort of "go heal before you can be useful again"
* ```
*/
function move(orders) {
(0,_move_defend_against_harassers__WEBPACK_IMPORTED_MODULE_2__.default)(orders);
(0,_move_farm__WEBPACK_IMPORTED_MODULE_3__.default)(orders);
(0,_move_strategic__WEBPACK_IMPORTED_MODULE_9__.default)(orders);
(0,_move_avoid__WEBPACK_IMPORTED_MODULE_4__.default)(orders);
(0,_move_heal__WEBPACK_IMPORTED_MODULE_5__.default)(orders);
}
function move_poststrat(orders) {
const {
stars,
bases,
outposts,
pylons
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
/*
for (const star of [stars.big]) {
goToStar(orders, star);
}
*/
//for (const structure of [bases.big]) {
for (const structure of [bases.middle, bases.me, bases.enemy, bases.big, outposts.middle, pylons.middle]) {
goToStructureIfUncontrolled(orders, structure);
}
}
function goToStructureIfUncontrolled(orders, base) {
if (!(0,_utils__WEBPACK_IMPORTED_MODULE_8__.controlIsEnemy)(base.control)) return;
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
for (const ship of (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_not_in)(myships, orders.moving)) {
orders.targetps[ship.index] = base.position;
orders.moving.push(ship.index);
if ((0,_vec__WEBPACK_IMPORTED_MODULE_7__.isWithinDist)(ship.position, base.position, _constants__WEBPACK_IMPORTED_MODULE_6__.D_LONG)) {
//ship.lock();
ship.unlock();
}
}
}
function goToStar(orders, star) {
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
for (const ship of (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_not_in)(myships, orders.moving)) {
orders.targetps[ship.index] = star.position;
orders.moving.push(ship.index);
if ((0,_vec__WEBPACK_IMPORTED_MODULE_7__.isWithinDist)(ship.position, star.position, _constants__WEBPACK_IMPORTED_MODULE_6__.D_LONG)) {
//ship.lock();
ship.unlock();
}
}
}
/***/ }),
/***/ "./src/move/move_avoid.ts":
/*!********************************!*\
!*** ./src/move/move_avoid.ts ***!
\********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ move_void)
/* harmony export */ });
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../collections */ "./src/collections.ts");
/* harmony import */ var _combateval__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../combateval */ "./src/combateval.ts");
/* harmony import */ var _positioning__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../positioning */ "./src/positioning.ts");
/* harmony import */ var _vec__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../vec */ "./src/vec.ts");
function move_void(orders) {
//clamp_movement(orders.targetps);
const COMMON_PLACE_MAX_RANGE = 60; //how far to look for a common avoid place
const {
myships,
shapes
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const myMovingShips = myships.filter(s => !s.locked);
const pickedAvoidPoints = [];
for (const ship of myMovingShips) {
const desiredPoint = orders.targetps[ship.index];
const desiredAvoidPoint = (0,_positioning__WEBPACK_IMPORTED_MODULE_2__.avoidEnemy)(ship, desiredPoint, ship.nearestenemy);
const {
myAdvantage
} = (0,_combateval__WEBPACK_IMPORTED_MODULE_1__.default)(ship.nearbyfriends20, ship.nearbyenemies240);
if (myAdvantage > -1) {
//can continue as planned
//TODO: what about triangles exploding? might not be safe to continue maxstep forward.
orders.targetps[ship.index] = desiredPoint;
if (shapes.enemy === "triangles" && ship.nearbyenemies240.length > 1) {
const desired_moved_p = (0,_vec__WEBPACK_IMPORTED_MODULE_3__.offsetmax20)(ship.position, desiredPoint);
orders.targetps[ship.index] = (0,_positioning__WEBPACK_IMPORTED_MODULE_2__.avoidCircle)(ship.position, desired_moved_p, ship.nearestenemy.position, 160.00001);
}
} else {
orders.avoiding.push(ship.index); //in danger
const reachableAvoidPoints2steps = pickedAvoidPoints.filter(p => (0,_vec__WEBPACK_IMPORTED_MODULE_3__.isWithinDist)(p.point, ship.position, COMMON_PLACE_MAX_RANGE));
if (reachableAvoidPoints2steps.length === 0) {
//no common place in range, pick your own avoid point.
const pickedAvoidPoint = desiredAvoidPoint;
orders.targetps[ship.index] = pickedAvoidPoint;
pickedAvoidPoints.push({
point: pickedAvoidPoint,
count: 1
});
} else if (reachableAvoidPoints2steps.length === 1) {
//only one common place in range, pick it.
const {
point: pickedAvoidPoint
} = reachableAvoidPoints2steps[0];
orders.targetps[ship.index] = pickedAvoidPoint;
pickedAvoidPoints.push({
point: pickedAvoidPoint,
count: 1
});
} else {
//pick one of the common places in range.
//IDEA1: pick the closest one
//const { index: closestIndex } = minimum(reachableAvoidPoints2steps.map((p) => dist(p.point, ship.position)));
//const {point: pickedAvoidPoint} = pickedAvoidPoints[closestIndex];
//pickedAvoidPoints[closestIndex].count += 1
//orders.targetps[ship.index] = pickedAvoidPoint;
//IDEA2: pick the most popular one
const {
index: popularIndex
} = (0,_vec__WEBPACK_IMPORTED_MODULE_3__.maximum)(reachableAvoidPoints2steps.map(p => p.count));
const {
point: pickedAvoidPoint
} = pickedAvoidPoints[popularIndex];
pickedAvoidPoints[popularIndex].count += 1;
orders.targetps[ship.index] = pickedAvoidPoint;
}
}
}
}
/**
* A Ship can only move 20 units. make targetps reflect that.
*/
function clamp_movement(targetps) {
const {
myships,
stars,
outposts,
bases,
pylons
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
for (const ship of myships) {
if (targetps[ship.index]) {
targetps[ship.index] = (0,_vec__WEBPACK_IMPORTED_MODULE_3__.offsetmax20)(ship.position, targetps[ship.index]);
} else {
//its possible ship was never assigned at targetp but unlikely
targetps[ship.index] = ship.position;
}
} //avoid structures
for (const ship of myships) {
for (const structure of [stars.big, stars.enemy, stars.me, stars.middle, bases.big, bases.enemy, bases.me, bases.middle, outposts.middle, pylons.middle]) {
targetps[ship.index] = (0,_positioning__WEBPACK_IMPORTED_MODULE_2__.avoidCircle)(ship.position, targetps[ship.index], structure.position, structure.collision_radius);
}
}
}
/***/ }),
/***/ "./src/move/move_defend_against_harassers.ts":
/*!***************************************************!*\
!*** ./src/move/move_defend_against_harassers.ts ***!
\***************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ move_defend_against_harassers)
/* harmony export */ });
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../collections */ "./src/collections.ts");
/* harmony import */ var _pointsLong__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../pointsLong */ "./src/pointsLong.ts");
/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../utils */ "./src/utils.ts");
/* harmony import */ var _positioning__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./positioning */ "./src/move/positioning.ts");
function move_defend_against_harassers(orders) {
const {
bases,
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const shouldDefMeOverride = false;
const shouldDefMiddleOverride = false;
const shouldDefEnemyOverride = false; //me
const shouldDefMe = shouldDefMeOverride || (0,_utils__WEBPACK_IMPORTED_MODULE_2__.controlIsMe)(bases.me.control) && couldSpawnNships(bases.me, 2); //middle
const shouldDefMiddle = shouldDefMiddleOverride || (0,_utils__WEBPACK_IMPORTED_MODULE_2__.controlIsMe)(bases.middle.control) && couldSpawnNships(bases.middle, 2); //enemy
const shouldDefEnemy = shouldDefEnemyOverride || (0,_utils__WEBPACK_IMPORTED_MODULE_2__.controlIsMe)(bases.enemy.control) && couldSpawnNships(bases.enemy, 2);
if (shouldDefMe) {
const points = [_pointsLong__WEBPACK_IMPORTED_MODULE_1__.pointsLong.h_def_front, _pointsLong__WEBPACK_IMPORTED_MODULE_1__.pointsLong.h_def_side, _pointsLong__WEBPACK_IMPORTED_MODULE_1__.pointsLong.h_def_back];
(0,_positioning__WEBPACK_IMPORTED_MODULE_3__.position_at_points)(orders, points);
}
if (shouldDefMiddle) {
const points = [_pointsLong__WEBPACK_IMPORTED_MODULE_1__.pointsLong.m_def_front, _pointsLong__WEBPACK_IMPORTED_MODULE_1__.pointsLong.m_def_side, _pointsLong__WEBPACK_IMPORTED_MODULE_1__.pointsLong.m_def_back];
(0,_positioning__WEBPACK_IMPORTED_MODULE_3__.position_at_points)(orders, points);
}
if (shouldDefEnemy) {
const points = [_pointsLong__WEBPACK_IMPORTED_MODULE_1__.pointsLong.e_def_front, _pointsLong__WEBPACK_IMPORTED_MODULE_1__.pointsLong.e_def_side, _pointsLong__WEBPACK_IMPORTED_MODULE_1__.pointsLong.e_def_back];
(0,_positioning__WEBPACK_IMPORTED_MODULE_3__.position_at_points)(orders, points);
}
}
/**
* True if base is full or could make N ships
*
* note: Will actually only return true if it is currently blocked because ships are auto spawned if could make 1 ship.
*/
function couldSpawnNships(base, N) {
return base.energy >= Math.min(base.energy_capacity, N * base.current_spirit_cost);
}
/***/ }),
/***/ "./src/move/move_farm.ts":
/*!*******************************!*\
!*** ./src/move/move_farm.ts ***!
\*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ move_farm)
/* harmony export */ });
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../collections */ "./src/collections.ts");
/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils */ "./src/utils.ts");
/* harmony import */ var _pointsLong__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../pointsLong */ "./src/pointsLong.ts");
/* harmony import */ var _positioning__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./positioning */ "./src/move/positioning.ts");
/* harmony import */ var _move_strategic__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./move_strategic */ "./src/move/move_strategic.ts");
function move_farm(orders) {
const {
bases
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections; //how much of maxfarm should be allocated
let ff_home = 1;
if (tick < 85) {
ff_home = 0.5;
} else if (tick < 120) {
ff_home = 0.75;
} else {
ff_home = 1;
}
const ff_mid = 1;
const ff_big = 1;
const ff_enemy = 1;
const {
stars
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections; //me
if (!(0,_utils__WEBPACK_IMPORTED_MODULE_1__.controlIsEnemy)(bases.me.control) || !(0,_move_strategic__WEBPACK_IMPORTED_MODULE_4__.enemyHasAnyWithinCircle)(stars.me.position, 220)) {
move_farm_longrange_single_point(orders, stars.me, _pointsLong__WEBPACK_IMPORTED_MODULE_2__.pointsLong.h1, ff_home);
} //mid
if (!(0,_utils__WEBPACK_IMPORTED_MODULE_1__.controlIsEnemy)(bases.middle.control) || !(0,_move_strategic__WEBPACK_IMPORTED_MODULE_4__.enemyHasAnyWithinCircle)(stars.middle.position, 220)) {
move_farm_longrange_single_point(orders, stars.middle, _pointsLong__WEBPACK_IMPORTED_MODULE_2__.pointsLong.m1);
} //enemy
if (!(0,_utils__WEBPACK_IMPORTED_MODULE_1__.controlIsEnemy)(bases.enemy.control) || !(0,_move_strategic__WEBPACK_IMPORTED_MODULE_4__.enemyHasAnyWithinCircle)(stars.enemy.position, 220)) {
move_farm_longrange_single_point(orders, stars.enemy, _pointsLong__WEBPACK_IMPORTED_MODULE_2__.pointsLong.e1);
} //big
/*
move_farm_longrange_two_points(
orders,
stars.big,
pointsLong.b1,
pointsLong.b3
);
*/
}
function move_farm_longrange_single_point(orders, star, point, maxfarmfraction = 1 //how much of maxfarm should be allocated,
) {
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const shipsize = myships[0].size;
const selfers_max = maxfarmfraction * (0,_utils__WEBPACK_IMPORTED_MODULE_1__.maxStarSelfers)(star, shipsize); //const selfers_sustainable = sustainableStarSelfers(stars.middle, shipsize);
let nselfers = 0;
while (nselfers < selfers_max) {
const addedSelfersPerTick = (0,_positioning__WEBPACK_IMPORTED_MODULE_3__.positionClosestShipAtPoint)(orders, point);
if (addedSelfersPerTick === 0) {
//couldnt find any free ship
break;
}
nselfers += addedSelfersPerTick;
}
}
function move_farm_longrange_two_points(orders, star, point1, point2, maxfarmfraction = 1 //how much of maxfarm should be allocated,
) {
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const shipsize = myships[0].size;
const selfers_max = maxfarmfraction * (0,_utils__WEBPACK_IMPORTED_MODULE_1__.maxStarSelfers)(star, shipsize); //const selfers_sustainable = sustainableStarSelfers(stars.middle, shipsize);
let nselfers = 0;
while (nselfers < selfers_max) {
const addedSelfersPerTick = (0,_positioning__WEBPACK_IMPORTED_MODULE_3__.positionClosestShipAtPoint)(orders, point1);
if (addedSelfersPerTick === 0) break;
nselfers += addedSelfersPerTick;
const addedSelfersPerTick2 = (0,_positioning__WEBPACK_IMPORTED_MODULE_3__.positionClosestShipAtPoint)(orders, point2);
if (addedSelfersPerTick2 === 0) break;
}
}
/***/ }),
/***/ "./src/move/move_heal.ts":
/*!*******************************!*\
!*** ./src/move/move_heal.ts ***!
\*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ move_heal)
/* harmony export */ });
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../collections */ "./src/collections.ts");
/* harmony import */ var _find__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../find */ "./src/find.ts");
/* harmony import */ var _vec__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../vec */ "./src/vec.ts");
/* harmony import */ var _move_strategic__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./move_strategic */ "./src/move/move_strategic.ts");
/* harmony import */ var _positioning__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./positioning */ "./src/move/positioning.ts");
/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../constants */ "./src/constants.ts");
/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../utils */ "./src/utils.ts");
/* harmony import */ var _positioning__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../positioning */ "./src/positioning.ts");
function move_heal(orders) {
const {
myships,
stars
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const avoidingShouldHeal = (0,_find__WEBPACK_IMPORTED_MODULE_1__.ships_in)(myships, orders.avoiding).filter(s => s.energy <= 0.3 * s.energy_capacity);
const emptyShouldHeal = myships.filter(s => s.energy === 0 && !(0,_utils__WEBPACK_IMPORTED_MODULE_6__.canReachAnyStar)(s));
const mightAswellHealMid = myships.filter(s => s.energy <= 0.6 * s.energy_capacity && !s.locked && (0,_vec__WEBPACK_IMPORTED_MODULE_2__.isWithinDist)(s.position, stars.middle.position, 300) && !(0,_vec__WEBPACK_IMPORTED_MODULE_2__.isWithinDist)(s.position, stars.middle.position, 200));
const currentTickShouldHealShips = avoidingShouldHeal.concat(mightAswellHealMid, emptyShouldHeal);
const shouldHealShips = updateMemoryMovingToHealIds(currentTickShouldHealShips);
for (const ship of shouldHealShips) {
const closestSafeStarPoint = getBestHealPoint(ship);
const desired_p = (0,_positioning__WEBPACK_IMPORTED_MODULE_7__.avoidCircle)(ship.position, closestSafeStarPoint, ship.nearestenemy.position, 240);
(0,_positioning__WEBPACK_IMPORTED_MODULE_4__.positionShipAtPoint)(orders, ship, desired_p);
}
return;
}
/**
* ```raw
* combine currentTickShouldHealShips with memory.movingToHealIds
* - remove full/undefined/duplicate ships
* - update memory.movingToHealIds
* - return the actual ships (instead of the ids) that still needs to heal.
* ```
*/
function updateMemoryMovingToHealIds(currentTickShouldHealShips) {
const currentTickShouldHealIds = currentTickShouldHealShips.map(s => s.id);
const movingToHealIds = [...new Set(memory.movingToHealIds.concat(currentTickShouldHealIds))]; //concat and unique
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const shoulMoveToStar = movingToHealIds.map(id => (0,_find__WEBPACK_IMPORTED_MODULE_1__.shipFromId)(myships, id)).filter(s => s !== undefined && s.energy < s.energy_capacity // && !anyStarIsWithinDist(s.position, 200)
);
memory.movingToHealIds = shoulMoveToStar.map(s => s.id);
return shoulMoveToStar;
}
/**
* find a point near a star without an enemy near it. fallback to mid star.
*/
function getBestHealPoint(ship) {
const {
stars
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const allStars = [stars.big, stars.enemy, stars.me, stars.middle];
const starPoints = allStars.map(star => (0,_vec__WEBPACK_IMPORTED_MODULE_2__.offset)(star.position, ship.position, _constants__WEBPACK_IMPORTED_MODULE_5__.D));
const safeStarPoints = starPoints.filter(p => !(0,_move_strategic__WEBPACK_IMPORTED_MODULE_3__.enemyHasAnyWithinCircle)(p, 220));
if (safeStarPoints.length < 1) {
const healpointMid = (0,_vec__WEBPACK_IMPORTED_MODULE_2__.offset)(stars.middle.position, ship.position, _constants__WEBPACK_IMPORTED_MODULE_5__.D);
return healpointMid;
}
return (0,_vec__WEBPACK_IMPORTED_MODULE_2__.nearestPointOfPoints)(safeStarPoints, ship.position);
}
/***/ }),
/***/ "./src/move/move_strategic.ts":
/*!************************************!*\
!*** ./src/move/move_strategic.ts ***!
\************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ move_strategic),
/* harmony export */ "enemyHasAnyWithinCircle": () => (/* binding */ enemyHasAnyWithinCircle)
/* harmony export */ });
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../collections */ "./src/collections.ts");
/* harmony import */ var _combateval__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../combateval */ "./src/combateval.ts");
/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../utils */ "./src/utils.ts");
/* harmony import */ var _vec__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../vec */ "./src/vec.ts");
/* harmony import */ var _positioning__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./positioning */ "./src/move/positioning.ts");
function move_strategic(orders) {
const {
bases,
myships,
stars
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const goFrontMid = shouldPositionInFrontOfStar(stars.middle, bases.middle);
const goFrontMe = shouldPositionInFrontOfStar(stars.me, bases.me);
const goFrontEnemy = shouldPositionInFrontOfStar(stars.enemy, bases.enemy);
for (let i = 0; i < 10; i++) {
//middle
if ((0,_utils__WEBPACK_IMPORTED_MODULE_2__.controlIsEnemy)(bases.middle.control)) {
if (goFrontMid) {
put4infrontofstar(orders, bases.middle, stars.middle);
} else {
put4behindstar(orders, bases.middle, stars.middle);
}
} //me
if ((0,_utils__WEBPACK_IMPORTED_MODULE_2__.controlIsEnemy)(bases.me.control)) {
if (goFrontMe) {
put4infrontofstar(orders, bases.me, stars.me);
} else {
put4behindstar(orders, bases.me, stars.me);
}
} //enemy
if ((0,_utils__WEBPACK_IMPORTED_MODULE_2__.controlIsEnemy)(bases.enemy.control)) {
if (goFrontEnemy) {
put4infrontofstar(orders, bases.enemy, stars.enemy);
} else {
put4behindstar(orders, bases.enemy, stars.enemy);
}
}
}
(0,_positioning__WEBPACK_IMPORTED_MODULE_4__.positionClosestShipAtPoint)(orders, bases.big.position); //positionClosestShipAtPoint(orders, bases.big.position);
for (let i = 0; i < 10; i++) {
//big
if ((0,_utils__WEBPACK_IMPORTED_MODULE_2__.controlIsEnemy)(bases.big.control)) {
put4behindstar(orders, bases.big, stars.big);
put4infrontofstar(orders, bases.big, stars.big);
/*
if (enemyHasAnyWithinCircle(stars.big.position, 200)) {
} else {
}
*/
}
}
}
function shouldPositionInFrontOfStar(star, base) {
const frontPosition = (0,_vec__WEBPACK_IMPORTED_MODULE_3__.offset)(star.position, base.position, star.collision_radius + 0.0000001);
const {
myships,
enemyships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
const myShipsAtStar = myships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_3__.isWithinDist)(s.position, frontPosition, 300));
const enemyShipsNearby = enemyships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_3__.isWithinDist)(s.position, frontPosition, 300));
if (enemyShipsNearby.length < 1) {
return true;
}
const {
myAdvantage
} = (0,_combateval__WEBPACK_IMPORTED_MODULE_1__.default)(myShipsAtStar, enemyShipsNearby);
return myAdvantage > 0;
}
/**
* true if any enemy ship is within this circle
*/
function enemyHasAnyWithinCircle(c, r) {
return enemiesWithinCircle(c, r).length > 0;
}
function enemiesWithinCircle(c, r) {
const {
enemyships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
return enemyships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_3__.isWithinDist)(c, s.position, r));
}
function put4behindstar(orders, base, star) {
const p = (0,_vec__WEBPACK_IMPORTED_MODULE_3__.offset)(star.position, base.position, -(star.collision_radius + 0.0000001)); //negative
const c = star.position;
const r = 200;
(0,_positioning__WEBPACK_IMPORTED_MODULE_4__.positionClosestShipAtPoint)(orders, p);
(0,_positioning__WEBPACK_IMPORTED_MODULE_4__.positionClosestShipAtPoint)(orders, p);
(0,_positioning__WEBPACK_IMPORTED_MODULE_4__.positionClosestShipAtPoint)(orders, p);
(0,_positioning__WEBPACK_IMPORTED_MODULE_4__.positionClosestShipAtPoint)(orders, p);
}
function put4infrontofstar(orders, base, star) {
const p = (0,_vec__WEBPACK_IMPORTED_MODULE_3__.offset)(star.position, base.position, star.collision_radius + 0.0000001); //positive
const c = star.position;
const r = 200;
(0,_positioning__WEBPACK_IMPORTED_MODULE_4__.positionClosestShipAtPoint)(orders, p);
(0,_positioning__WEBPACK_IMPORTED_MODULE_4__.positionClosestShipAtPoint)(orders, p);
(0,_positioning__WEBPACK_IMPORTED_MODULE_4__.positionClosestShipAtPoint)(orders, p);
(0,_positioning__WEBPACK_IMPORTED_MODULE_4__.positionClosestShipAtPoint)(orders, p);
}
/***/ }),
/***/ "./src/move/positioning.ts":
/*!*********************************!*\
!*** ./src/move/positioning.ts ***!
\*********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "position_at_points": () => (/* binding */ position_at_points),
/* harmony export */ "positionClosestShipAtPoint": () => (/* binding */ positionClosestShipAtPoint),
/* harmony export */ "positionShipAtPoint": () => (/* binding */ positionShipAtPoint),
/* harmony export */ "jumpTowardPointIfGood": () => (/* binding */ jumpTowardPointIfGood),
/* harmony export */ "interceptPoint": () => (/* binding */ interceptPoint),
/* harmony export */ "positionClosestShipAtPoint_stayInCircle": () => (/* binding */ positionClosestShipAtPoint_stayInCircle)
/* harmony export */ });
/* harmony import */ var _ability_jump__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../ability/jump */ "./src/ability/jump.ts");
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../collections */ "./src/collections.ts");
/* harmony import */ var _combateval__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../combateval */ "./src/combateval.ts");
/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../constants */ "./src/constants.ts");
/* harmony import */ var _find__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../find */ "./src/find.ts");
/* harmony import */ var _positioning__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../positioning */ "./src/positioning.ts");
/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../utils */ "./src/utils.ts");
/* harmony import */ var _vec__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../vec */ "./src/vec.ts");
function uniqueIds(v) {
return [...new Set(v)];
}
/**
* positionClosestShipAtPoint() for multiple points
*/
function position_at_points(orders, points) {
let allocated = 0;
for (const point of points) {
allocated += positionClosestShipAtPoint(orders, point);
}
return allocated;
}
/**
* return `0.5` or `0` which is the number of "selfers per tick" that was just added:
*
* note: Half the time an allocated ship will not be selfing. Thats where 0.5 comes from.
*
* Will return 0 if no ship was available.
*
* also: Lock the ship if the picked ship is at the point.
* */
function positionClosestShipAtPoint(orders, point) {
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_1__.collections;
const freeships = (0,_find__WEBPACK_IMPORTED_MODULE_4__.ships_not_in)(myships, orders.moving);
if (freeships.length < 1) {
return 0;
} else {
const ship = (0,_find__WEBPACK_IMPORTED_MODULE_4__.ship_closest_to_point)(freeships, point);
return positionShipAtPoint(orders, ship, point);
}
}
/**
* position this ship at point, return 0.5 always
*/
function positionShipAtPoint(orders, ship, point) {
orders.targetps[ship.index] = point;
orders.moving.push(ship.index);
const isLocked = ship.locked; //const isAtPoint = isWithinDist(s2.position, point, Number.EPSILON) //too small
const isAtCorrectPlace = (0,_vec__WEBPACK_IMPORTED_MODULE_7__.isWithinDist)(ship.position, point, 0.00001);
if (!isAtCorrectPlace && isLocked) {
ship.unlock();
}
if (!isAtCorrectPlace && !isLocked) {
jumpTowardPointIfGood(orders, ship, point);
}
if (isAtCorrectPlace && !isLocked) {
ship.lock();
}
return 0.5;
}
/**
* return true if we decided to jump and called ship.jump()
* "if good" refers to some conditions, which I havn't completely decided yet.
*
* experiment...
*/
function jumpTowardPointIfGood(orders, ship, point) {
const {
myships,
enemyships
} = _collections__WEBPACK_IMPORTED_MODULE_1__.collections;
const energyMargin = ship.size * 2;
const landingPoint = (0,_ability_jump__WEBPACK_IMPORTED_MODULE_0__.jumpPoint)(ship, point, energyMargin);
/*
if (!canJump(ship, point, energyMargin)) {
//cant afford
return false;
}
*/
if ((0,_vec__WEBPACK_IMPORTED_MODULE_7__.isWithinDist)(ship.position, landingPoint, 40)) {
//could just walk (2 ticks)
return false;
}
if ((0,_utils__WEBPACK_IMPORTED_MODULE_6__.anyStarIsWithinDist)(ship.position, 200)) {
//never jump if already inside a star
return false;
}
const relevantStars = (0,_utils__WEBPACK_IMPORTED_MODULE_6__.starsWithinDist)(landingPoint, 200);
if (relevantStars.length === 0) {
//dont ever jump to a point that is not near a star
return false;
}
if (relevantStars[0].energy < 400) {
//dont deplete energy without quick way to get it back..
return false;
}
const enemyShipsNearLandingpoint = enemyships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_7__.isWithinDist)(s.position, landingPoint, 220));
const myShipsAlreadyAtLandingpoint = myships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_7__.isWithinDist)(s.position, landingPoint, 20));
const myShipsAtLandingpointNextTick = myShipsAlreadyAtLandingpoint.concat([ship]); //remember energy
const prevEnergy = ship.energy * 1; //modify energy before combateval
const spentEnergy = (0,_ability_jump__WEBPACK_IMPORTED_MODULE_0__.jumpCost)(ship, landingPoint);
ship.energy -= spentEnergy;
const {
myAdvantage
} = (0,_combateval__WEBPACK_IMPORTED_MODULE_2__.default)(myShipsAtLandingpointNextTick, enemyShipsNearLandingpoint); //restore energy
ship.energy = prevEnergy;
if (myAdvantage > -1) {
ship.jump(landingPoint);
return true;
}
return false;
}
/** an appropriate point for defending base from a blocking enemy ship */
function interceptPoint(base, enemy) {
const enemyDistFromBaseRadius = (0,_vec__WEBPACK_IMPORTED_MODULE_7__.dist)(base.position, enemy.position) - base.collision_radius;
if (enemyDistFromBaseRadius > _constants__WEBPACK_IMPORTED_MODULE_3__.D) {
return (0,_vec__WEBPACK_IMPORTED_MODULE_7__.offset)(enemy.position, base.position, _constants__WEBPACK_IMPORTED_MODULE_3__.D);
} else {
return (0,_vec__WEBPACK_IMPORTED_MODULE_7__.offset)(base.position, enemy.position, base.collision_radius + 1);
}
}
/**
* same as positionClosestShipAtPoint stay in circle with center c and radius r
*/
function positionClosestShipAtPoint_stayInCircle(orders, point, c, r) {
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_1__.collections;
const freeships = (0,_find__WEBPACK_IMPORTED_MODULE_4__.ships_not_in)(myships, orders.moving);
if (freeships.length < 1) {
return 0;
}
const ship = (0,_find__WEBPACK_IMPORTED_MODULE_4__.ship_closest_to_point)(freeships, point);
orders.targetps[ship.index] = (0,_positioning__WEBPACK_IMPORTED_MODULE_5__.stayinCircle)(ship.position, point, c, r);
orders.moving.push(ship.index);
const isLocked = ship.locked; //const isAtPoint = isWithinDist(s2.position, point, Number.EPSILON) //too small
const isAtCorrectPlace = (0,_vec__WEBPACK_IMPORTED_MODULE_7__.isWithinDist)(ship.position, point, 0.00001);
if (!isAtCorrectPlace && isLocked) {
ship.unlock();
}
if (isAtCorrectPlace && !isLocked) {
ship.lock();
}
return 0.5;
}
/***/ }),
/***/ "./src/pointsLong.ts":
/*!***************************!*\
!*** ./src/pointsLong.ts ***!
\***************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "pointsLong": () => (/* binding */ pointsLong)
/* harmony export */ });
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./collections */ "./src/collections.ts");
/* harmony import */ var _vec__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./vec */ "./src/vec.ts");
/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./constants */ "./src/constants.ts");
const pointsLong = pointsOfInterest();
function pointsOfInterest() {
const {
bases,
stars,
outposts,
pylons
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections; //home star and base
const {
farm: h1,
front: h_def_front,
side: h_def_side,
back: h_def_back
} = defpoints(bases.me, stars.me, stars.enemy.position); //enemy star and base
const {
farm: e1,
front: e_def_front,
side: e_def_side,
back: e_def_back
} = defpoints(bases.enemy, stars.enemy, stars.me.position); //mid star and base
const {
farm: m1,
front: m_def_front,
side: m_def_side,
back: m_def_back
} = defpoints_mid(bases.middle, stars.middle, stars.enemy.position); //big star
const b1 = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.offset)(stars.big.position, bases.me.position, _constants__WEBPACK_IMPORTED_MODULE_2__.D_LONG);
const b2 = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.offset)(b1, bases.me.position, _constants__WEBPACK_IMPORTED_MODULE_2__.D_LONG); //between point, put fragment here
const b3 = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.offset)(bases.me.position, stars.big.position, _constants__WEBPACK_IMPORTED_MODULE_2__.D_LONG); //outpost
const o1 = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.offset)(stars.middle.position, outposts.middle.position, _constants__WEBPACK_IMPORTED_MODULE_2__.D_LONG);
/** 199 from big base */
const a_b = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.offset)(bases.big.position, stars.big.position, 199); //outpost
const a_p = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.offset)(pylons.middle.position, outposts.middle.position, 199);
return {
h1,
h_def_front,
h_def_side,
h_def_back,
e1,
e_def_front,
e_def_side,
e_def_back,
m1,
m_def_front,
m_def_side,
m_def_back,
b1,
b2,
b3,
o1,
a_b,
a_p
};
}
/**
* 4 well spaces points around base such that a chain can go from
* star -> h1 -> front -> side -> back
*
* AND
*
* if they are locked (range 300) covers the bases spawn block radius (400)
*/
function defpoints(base, star, fronttarget) {
const BASE2DEF = 202;
const farm = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.offset)(star.position, base.position, _constants__WEBPACK_IMPORTED_MODULE_2__.D_LONG);
const corner1 = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.intersectPointFarthest)(base.position, 400, farm, _constants__WEBPACK_IMPORTED_MODULE_2__.D_LONG, fronttarget);
const back = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.intersectPointFarthest)(corner1, _constants__WEBPACK_IMPORTED_MODULE_2__.D_LONG, base.position, BASE2DEF, fronttarget);
const corner2 = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.intersectPoint)(base.position, 400, back, _constants__WEBPACK_IMPORTED_MODULE_2__.D_LONG, fronttarget);
const side = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.intersectPoint)(corner2, _constants__WEBPACK_IMPORTED_MODULE_2__.D_LONG, base.position, BASE2DEF, fronttarget);
const corner3 = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.intersectPoint)(base.position, 400, side, _constants__WEBPACK_IMPORTED_MODULE_2__.D_LONG, fronttarget);
const front = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.intersectPoint)(corner3, _constants__WEBPACK_IMPORTED_MODULE_2__.D_LONG, base.position, BASE2DEF, fronttarget);
return {
farm,
back,
side,
front
};
}
function defpoints_mid(base, star, fronttarget) {
const BASE2DEF = 202;
const farm = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.offset)(star.position, base.position, 100);
const corner1 = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.intersectPointFarthest)(base.position, 400, farm, _constants__WEBPACK_IMPORTED_MODULE_2__.D_LONG, fronttarget);
const back = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.intersectPointFarthest)(corner1, _constants__WEBPACK_IMPORTED_MODULE_2__.D_LONG, base.position, BASE2DEF, fronttarget);
const corner2 = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.intersectPointFarthest)(base.position, 400, back, _constants__WEBPACK_IMPORTED_MODULE_2__.D_LONG, fronttarget);
const side = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.intersectPoint)(corner2, _constants__WEBPACK_IMPORTED_MODULE_2__.D_LONG, base.position, BASE2DEF, fronttarget);
const corner3 = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.intersectPoint)(base.position, 400, side, _constants__WEBPACK_IMPORTED_MODULE_2__.D_LONG, fronttarget);
const front = (0,_vec__WEBPACK_IMPORTED_MODULE_1__.intersectPoint)(corner3, _constants__WEBPACK_IMPORTED_MODULE_2__.D_LONG, base.position, BASE2DEF, fronttarget);
return {
farm,
back,
side,
front
};
}
/***/ }),
/***/ "./src/positioning.ts":
/*!****************************!*\
!*** ./src/positioning.ts ***!
\****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "avoidEnemy": () => (/* binding */ avoidEnemy),
/* harmony export */ "avoidCircle": () => (/* binding */ avoidCircle),
/* harmony export */ "stayinCircle": () => (/* binding */ stayinCircle),
/* harmony export */ "staynearstructure": () => (/* binding */ staynearstructure),
/* harmony export */ "stayinTwoCircles": () => (/* binding */ stayinTwoCircles)
/* harmony export */ });
/* harmony import */ var _vec__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./vec */ "./src/vec.ts");
/**
* essentially avoidCircle() but call it with myShip and enemyShip instead.
*
* Will properly avoid locked ship (with increased range) aswell.
*/
function avoidEnemy(myShip, myShip_desired_p, enemyShip) {
if (enemyShip.locked) {
return avoidCircle(myShip.position, myShip_desired_p, enemyShip.position, Math.min(300, enemyShip.range + 25) //locked ones will grow next turn (instead of moving)
);
} else {
return avoidCircle(myShip.position, myShip_desired_p, enemyShip.position, enemyShip.range + 20);
}
}
/**
* ```raw
* Return a point the ship can move to that avoids the circle c with radius r
* argument position is the current position
*
* 1. If moving will NOT put ship inside: just move
* 2. IF INSIDE:
* 2.1 if near edge: go diagonal (land on circumference) in the direction most similar to desired_p
* 2.2 if further in: go straight outward from circle center
* 3. IF OUTSIDE:
* 3.1 (if step1 wasnt triggered) go along tangent direction most similar to desired_p
*```
*/
function avoidCircle(position, desired_p, c, r) {
const p_moved = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.offsetmax20)(position, desired_p);
if ((0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(c, p_moved) > r) {
//moving wont put ship inside.. just move.
return p_moved;
}
const dir_desired = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.unitvecFromPositions)(position, desired_p); //const dir_center = unitvecFromPositions(position, c);
const tps = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.tangentPoints)(position, c, r);
if (tps.length === 0) {
//inside.
if ((0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(c, position) > r - 20) {
//Ship is pretty close to circumference, there exists 2 "diagonal" moves to get outside
//choose the one most similar to dir_desired
const [a, b] = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.intersectTwoCircles)(c, r, position, 20);
const dir_diag0 = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.unitvecFromPositions)(position, a);
const dir_diag1 = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.unitvecFromPositions)(position, b);
const s0 = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.directionSimilarity)(dir_diag0, dir_desired);
const s1 = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.directionSimilarity)(dir_diag1, dir_desired);
const p_diag = s0 > s1 ? a : b;
return p_diag;
} else {
//otherwise straight out
return (0,_vec__WEBPACK_IMPORTED_MODULE_0__.offset)(c, position, r);
}
} else {
//outside, there exists 2 tangent points
//choose the one most similar to dir_desired
const dir_tangent0 = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.unitvecFromPositions)(position, tps[0]);
const dir_tangent1 = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.unitvecFromPositions)(position, tps[1]);
const s0 = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.directionSimilarity)(dir_tangent0, dir_desired);
const s1 = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.directionSimilarity)(dir_tangent1, dir_desired);
const p_tangent = s0 > s1 ? tps[0] : tps[1]; //const p_tangent_moved = offset(position, p_tangent, Math.min(20, dist(position, p_tangent)));
const p_tangent_moved = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.offset)(position, p_tangent, 20);
return p_tangent_moved;
}
}
/**
* If outside, go inside
* If inside go to the point inside closest to desired_p
*/
function stayinCircle(position, desired_p, c, r) {
//the actual point Im going towards: the point closest desired_p BUT ALSO INSIDE
const inside_p = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.offset)(c, desired_p, Math.min(r, (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(c, desired_p)));
const p_moved = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.offsetmax20)(position, inside_p);
if ((0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(c, p_moved) <= r) {
//moving wont put ship outside.. just move.
return p_moved;
} else if ((0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(c, position) < r + 20) {
//is outside but pretty close to circumference...
const p = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.offset)(c, position, r); //at border
return p;
} else {
//is simply far outside, go toward center
return (0,_vec__WEBPACK_IMPORTED_MODULE_0__.offset)(position, c, 20);
}
}
/**
* stay within range of star but toward desired_p, but avoid its collision radius when moving towar the inside point
*/
function staynearstructure(position, desired_p, structure) {
const D = 199.99999;
const adjusted_p = stayinCircle(position, desired_p, structure.position, D);
return avoidCircle(position, adjusted_p, structure.position, structure.collision_radius);
}
/**
* ```raw
* Try to stay in both circles, prioritize staying in c1.
*
* 1. Always stay inside c1
* 2. If not possible to stay in both, stay in c1 but position toward c2
* 3. If possible to stay in both, stay in both but position toward desired_p
* ```
*/
function stayinTwoCircles(position, desired_p, c1, r1, c2, r2) {
//const [a, b] = intersectTwoCircles(c1, r1, c2, r2);
//const p_inside = dist(a, desired_p) < dist(b, desired_p) ? a : b;
if ((0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(c1, c2) > r1 + r2) {
//impossible, stay in c1, but toward c2
return stayinCircle(position, c2, c1, r1);
} else {
//possible, go from betweenpoint toward desired_p but still inside both
const between_p = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.mix)(c1, c2);
const p1 = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.nearestPointOfPoints)((0,_vec__WEBPACK_IMPORTED_MODULE_0__.intersectLineCircle)(between_p, desired_p, c1, r1), desired_p);
const p2 = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.nearestPointOfPoints)((0,_vec__WEBPACK_IMPORTED_MODULE_0__.intersectLineCircle)(between_p, desired_p, c2, r2), desired_p);
const p = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(position, p1) < (0,_vec__WEBPACK_IMPORTED_MODULE_0__.dist)(position, p2) ? p1 : p2;
const p_moved = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.offsetmax20)(position, p);
return p_moved;
}
}
/***/ }),
/***/ "./src/sendcommands.ts":
/*!*****************************!*\
!*** ./src/sendcommands.ts ***!
\*****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ sendcommands)
/* harmony export */ });
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./collections */ "./src/collections.ts");
function sendcommands(targetps, targets) {
const {
myships
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
for (const [i, ship] of myships.entries()) {
targetps[i] && ship.move(targetps[i]); //maybe jump if targetps is out of range?
targets[i] && ship.energize(targets[i]);
}
}
/***/ }),
/***/ "./src/sendendgamecommands.ts":
/*!************************************!*\
!*** ./src/sendendgamecommands.ts ***!
\************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ sendendgamecommands)
/* harmony export */ });
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./collections */ "./src/collections.ts");
/* harmony import */ var _vec__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./vec */ "./src/vec.ts");
/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./constants */ "./src/constants.ts");
function sendendgamecommands() {
const {
myships,
enemyships,
bases,
stars,
playerids,
outposts,
pylons
} = _collections__WEBPACK_IMPORTED_MODULE_0__.collections;
if (enemyships.length === 0 || myships.length === 0) {
for (const ship of myships) {
if (ship.energy > 0) {
for (const base of [bases.me, bases.middle, bases.enemy, bases.big, outposts.middle]) {
if (base.control === playerids.enemy) {
ship.move(base.position);
ship.energize(base);
} else {
continue;
}
}
} else {
ship.move((0,_vec__WEBPACK_IMPORTED_MODULE_1__.offset)(stars.middle.position, outposts.middle.position, _constants__WEBPACK_IMPORTED_MODULE_2__.D));
ship.energize(ship);
}
}
return true;
} else {
return false;
}
}
/***/ }),
/***/ "./src/utils.ts":
/*!**********************!*\
!*** ./src/utils.ts ***!
\**********************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "myOutpostEnergy": () => (/* binding */ myOutpostEnergy),
/* harmony export */ "enemyOutpostEnergy": () => (/* binding */ enemyOutpostEnergy),
/* harmony export */ "isFull": () => (/* binding */ isFull),
/* harmony export */ "almostFull": () => (/* binding */ almostFull),
/* harmony export */ "almostEmpty": () => (/* binding */ almostEmpty),
/* harmony export */ "canTransfer": () => (/* binding */ canTransfer),
/* harmony export */ "hasRoomLess": () => (/* binding */ hasRoomLess),
/* harmony export */ "hasRoom": () => (/* binding */ hasRoom),
/* harmony export */ "notEmpty": () => (/* binding */ notEmpty),
/* harmony export */ "notFull": () => (/* binding */ notFull),
/* harmony export */ "isEmpty": () => (/* binding */ isEmpty),
/* harmony export */ "maxStarSelfers": () => (/* binding */ maxStarSelfers),
/* harmony export */ "sustainableStarSelfers": () => (/* binding */ sustainableStarSelfers),
/* harmony export */ "sustainableStarSelfingAmount": () => (/* binding */ sustainableStarSelfingAmount),
/* harmony export */ "maxStarSelfingAmount": () => (/* binding */ maxStarSelfingAmount),
/* harmony export */ "outpostdmg": () => (/* binding */ outpostdmg),
/* harmony export */ "outpostlossFromAttacking": () => (/* binding */ outpostlossFromAttacking),
/* harmony export */ "attackdmg": () => (/* binding */ attackdmg),
/* harmony export */ "lossFromAttacking": () => (/* binding */ lossFromAttacking),
/* harmony export */ "gainFromSelfing": () => (/* binding */ gainFromSelfing),
/* harmony export */ "transferamount": () => (/* binding */ transferamount),
/* harmony export */ "weightedmeanposition": () => (/* binding */ weightedmeanposition),
/* harmony export */ "meanposition": () => (/* binding */ meanposition),
/* harmony export */ "distanceWeightedMeanPosition": () => (/* binding */ distanceWeightedMeanPosition),
/* harmony export */ "anyShipIsWithinDist": () => (/* binding */ anyShipIsWithinDist),
/* harmony export */ "canReachAnyStar": () => (/* binding */ canReachAnyStar),
/* harmony export */ "anyStarIsWithinDist": () => (/* binding */ anyStarIsWithinDist),
/* harmony export */ "starsWithinDist": () => (/* binding */ starsWithinDist),
/* harmony export */ "enemyShipCost": () => (/* binding */ enemyShipCost),
/* harmony export */ "myShipCost": () => (/* binding */ myShipCost),
/* harmony export */ "isNearStar": () => (/* binding */ isNearStar),
/* harmony export */ "notNearStar": () => (/* binding */ notNearStar),
/* harmony export */ "controlIsMe": () => (/* binding */ controlIsMe),
/* harmony export */ "controlIsEnemy": () => (/* binding */ controlIsEnemy),
/* harmony export */ "controlIsNeutral": () => (/* binding */ controlIsNeutral),
/* harmony export */ "canEnergize": () => (/* binding */ canEnergize)
/* harmony export */ });
/* harmony import */ var _vec__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./vec */ "./src/vec.ts");
/* harmony import */ var _collections__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./collections */ "./src/collections.ts");
/**
* Return 0 If I dont have outpost, else return the outpost energy
*/
function myOutpostEnergy() {
const {
outposts,
info
} = _collections__WEBPACK_IMPORTED_MODULE_1__.collections;
return info.outpostcontrolIsMe ? outposts.middle.energy : 0;
}
/**
* Return 0 If ENEMY dont have outpost, else return the outpost energy
*/
function enemyOutpostEnergy() {
const {
outposts,
info
} = _collections__WEBPACK_IMPORTED_MODULE_1__.collections;
return info.outpostcontrolIsEnemy ? outposts.middle.energy : 0;
}
/**
* s.energy === s.energy_capacity
*/
function isFull(s) {
return s.energy === s.energy_capacity;
}
/**
* s.energy >= s.energy_capacity - s.size * n
*/
function almostFull(s, n = 1) {
return s.energy >= s.energy_capacity - s.size * n;
}
/**
* s.energy <= s.size * n
*/
function almostEmpty(s, n = 1) {
return s.energy <= s.size * n;
}
/**
* ```raw
* True if ship has energy to (fully) transfer n times. default n=1
*
* ship.energy >= ship.size * n
* ```
*/
function canTransfer(ship, n = 1) {
return ship.energy >= ship.size * n;
}
/**
* ```raw
* Has room for n heals and still not be completely full, default n=1
*
* ship.energy < ship.energy_capacity - ship.size * n;
* ```
*/
function hasRoomLess(ship, n = 1) {
return ship.energy < ship.energy_capacity - ship.size * n;
}
/**
* ```raw
* Has room for n heals, default n=1
*
* ship.energy <= ship.energy_capacity - ship.size * n;
* ```
*/
function hasRoom(ship, n = 1) {
return ship.energy <= ship.energy_capacity - ship.size * n;
}
/**
* ship.energy > 0
*/
function notEmpty(ship) {
return ship.energy > 0;
}
/**
* ship.energy < ship.energy_capacity
*/
function notFull(ship) {
return ship.energy < ship.energy_capacity;
}
/**
* ship.energy === 0
*/
function isEmpty(ship) {
return ship.energy === 0;
}
function star_gain(star) {
if (star.energy_capacity == 3000) {
return 3 + 0.03 * star.energy;
} else {
return 2 + 0.02 * star.energy;
}
}
function star_gain_max(star) {
if (star.energy_capacity == 3000) {
return 3 + 0.03 * star.energy_capacity;
} else {
return 2 + 0.02 * star.energy_capacity;
}
}
/**
* ```raw
* The maximum number of farmers (farming each tick) possible at star max energy. ignoring sustainable.
* ```
*/
function maxStarSelfers(star, shipsize) {
return Math.floor(star_gain_max(star) / shipsize);
}
/**
* The maximum number of farmers (farming each tick) to still have star grow by atleast 1 each tick.
*/
function sustainableStarSelfers(star, shipsize) {
if (star.energy === star.energy_capacity) {
return Math.floor(star_gain(star) / shipsize);
} else {
return Math.floor((star_gain(star) - 1) / shipsize);
}
}
/**
* The amount of energy that ships can take from star and still have it grow.
*/
function sustainableStarSelfingAmount(star) {
if (star.energy === star.energy_capacity) {
return star_gain(star);
} else {
return star_gain(star) - 1;
}
}
/**
* simply `star.energy`
*/
function maxStarSelfingAmount(star) {
return star.energy;
}
function outpostdmg(outpost) {
return outpost.energy < 500 ? Math.min(2, outpost.energy) : Math.min(8, outpost.energy);
}
function outpostlossFromAttacking(outpost) {
return outpost.energy < 500 ? Math.min(1, outpost.energy) : Math.min(4, outpost.energy);
}
/**
* ```raw
* How much damage a ship does to another ship.
*
* 2 * Math.min(ship.size, ship.energy)
* ```
*/
function attackdmg(ship) {
//2*ship.size, but only as much energy as it has.
return 2 * Math.min(ship.size, ship.energy);
}
/**
* ```raw
* How much energy a ship loses (by energizing)
*
* Math.min(ship.size, ship.energy);
* ```
*/
function lossFromAttacking(ship) {
//ship.size, but only as much energy as it has.
return Math.min(ship.size, ship.energy);
}
/**
* essentially ship.size, except when its almost full in which case its less.
*
*/
function gainFromSelfing(ship) {
//ship.size, but only as much energy as it has.
return Math.min(ship.size, ship.energy_capacity - ship.energy);
}
/**
* ```raw
* How much energy a ship transfers (by energizing)
*
* note: actually same as lossFromAttacking() but use this for clarity when appropriate.
*
* Math.min(ship.size, ship.energy);
* ```
*/
function transferamount(ship) {
return Math.min(ship.size, ship.energy);
}
/**
* Average position of ships, but weighted toward ships with more energy.
* Also add 1 to each ship to avoid potential zero division.
*/
function weightedmeanposition(ships) {
const x = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.sum)(ships.map(s => (s.energy + 1) * s.position[0]));
const y = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.sum)(ships.map(s => (s.energy + 1) * s.position[1]));
const energysum = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.sum)(ships.map(s => s.energy + 1));
return [x / energysum, y / energysum];
}
/**
* Average position of ships.
*/
function meanposition(ships) {
const x = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.sum)(ships.map(s => s.position[0]));
const y = (0,_vec__WEBPACK_IMPORTED_MODULE_0__.sum)(ships.map(s => s.position[1]));
return [x / ships.length, y / ships.length];
}
function distanceWeightedMeanPosition(ships) {
const points = ships.map(s => s.position);
return (0,_vec__WEBPACK_IMPORTED_MODULE_0__.distanceWeightedMean)(points);
}
/**
* True if any in ships isWithinDist d, default d=200
*/
function anyShipIsWithinDist(ships, p, d = 200) {
return ships.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(s.position, p, d)).length > 0;
}
/**
* true if ship can reach any star.
*
* assuming range 300 if locked (even if not fully at 300 yet)
* and 200 if not locked
*/
function canReachAnyStar(ship) {
return ship.locked ? anyStarIsWithinDist(ship.position, 300) : anyStarIsWithinDist(ship.position, 200);
}
/**
* true if any star is within r of point
*/
function anyStarIsWithinDist(point, r) {
return starsWithinDist(point, r).length > 0;
}
function starsWithinDist(point, r) {
const {
stars
} = _collections__WEBPACK_IMPORTED_MODULE_1__.collections;
const structures = [stars.big, stars.enemy, stars.me, stars.middle];
return structures.filter(s => (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(point, s.position, r));
}
/**
* ```raw
* What a ship would cost to replace for enemy.
*
* note: the cost of the ship itself is NOT simply current_spirit_cost becuase the ship starts with some energy.
* Examples:
* 1. squares in early game cost 360 but get 100 so the ship itself only costs 260.
* 2. triangles in early game cost 90 but get 30 so the ship itself only costs 60.
* 3. circles in early game cost 25 but get 10 so the ship itself only costs 15.
*
* ```
*/
function enemyShipCost() {
const {
bases,
shapes
} = _collections__WEBPACK_IMPORTED_MODULE_1__.collections;
let cost = bases.enemy.current_spirit_cost;
if (shapes.enemy === "squares") {
cost -= 100;
} else if (shapes.enemy === "circles") {
cost -= 10;
} else if (shapes.enemy === "triangles") {
cost -= 30;
}
return cost;
}
/**
* ```raw
* What a ship would cost to replace for me.
*
* note: the cost of the ship itself is NOT simply current_spirit_cost becuase the ship starts with some energy.
* For example squares in early game cost 360 but get 100 so the ship itself only cost 260.
* ```
*/
function myShipCost() {
const {
bases,
shapes
} = _collections__WEBPACK_IMPORTED_MODULE_1__.collections;
let cost = bases.me.current_spirit_cost;
if (shapes.me === "squares") {
cost -= 100;
} else if (shapes.me === "circles") {
cost -= 10;
} else if (shapes.me === "triangles") {
cost -= 30;
}
return cost;
}
function isNearStar(s) {
const {
stars
} = _collections__WEBPACK_IMPORTED_MODULE_1__.collections;
return (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(s.position, stars.me.position) || (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(s.position, stars.middle.position) || (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(s.position, stars.enemy.position);
}
function notNearStar(s) {
return !isNearStar(s);
}
function controlIsMe(controlId) {
const {
playerids
} = _collections__WEBPACK_IMPORTED_MODULE_1__.collections;
return controlId === playerids.me;
}
function controlIsEnemy(controlId) {
const {
playerids
} = _collections__WEBPACK_IMPORTED_MODULE_1__.collections;
return controlId === playerids.enemy;
}
function controlIsNeutral(controlId) {
const {
playerids
} = _collections__WEBPACK_IMPORTED_MODULE_1__.collections;
return controlId !== playerids.enemy && controlId != playerids.me;
}
/**
* check if ship can reach target
*
* `isWithinDist(ship.position, target.position, ship.range)` but allows target to be a Vec2 aswell.
*/
function canEnergize(ship, target) {
const shipRange = ship.range;
if (Array.isArray(target)) {
//is just a Vec2 (without position property)
return (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, target, shipRange);
} else {
return (0,_vec__WEBPACK_IMPORTED_MODULE_0__.isWithinDist)(ship.position, target.position, shipRange);
}
}
/***/ }),
/***/ "./src/vec.ts":
/*!********************!*\
!*** ./src/vec.ts ***!
\********************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "add": () => (/* binding */ add),
/* harmony export */ "mul": () => (/* binding */ mul),
/* harmony export */ "div": () => (/* binding */ div),
/* harmony export */ "len": () => (/* binding */ len),
/* harmony export */ "sum": () => (/* binding */ sum),
/* harmony export */ "dot": () => (/* binding */ dot),
/* harmony export */ "normalize": () => (/* binding */ normalize),
/* harmony export */ "minimum": () => (/* binding */ minimum),
/* harmony export */ "maximum": () => (/* binding */ maximum),
/* harmony export */ "offsetmax20": () => (/* binding */ offsetmax20),
/* harmony export */ "unique": () => (/* binding */ unique),
/* harmony export */ "vecFromPositions": () => (/* binding */ vecFromPositions),
/* harmony export */ "unitvecFromPositions": () => (/* binding */ unitvecFromPositions),
/* harmony export */ "dist": () => (/* binding */ dist),
/* harmony export */ "isWithinDist": () => (/* binding */ isWithinDist),
/* harmony export */ "directionSimilarity": () => (/* binding */ directionSimilarity),
/* harmony export */ "clamp": () => (/* binding */ clamp),
/* harmony export */ "mix": () => (/* binding */ mix),
/* harmony export */ "offset": () => (/* binding */ offset),
/* harmony export */ "tangentPoints": () => (/* binding */ tangentPoints),
/* harmony export */ "mostSimilarVec": () => (/* binding */ mostSimilarVec),
/* harmony export */ "intersectTwoCircles": () => (/* binding */ intersectTwoCircles),
/* harmony export */ "intersectPoint": () => (/* binding */ intersectPoint),
/* harmony export */ "intersectPointFarthest": () => (/* binding */ intersectPointFarthest),
/* harmony export */ "perpendicularCW": () => (/* binding */ perpendicularCW),
/* harmony export */ "perpendicularCCW": () => (/* binding */ perpendicularCCW),
/* harmony export */ "falses": () => (/* binding */ falses),
/* harmony export */ "trues": () => (/* binding */ trues),
/* harmony export */ "all": () => (/* binding */ all),
/* harmony export */ "any": () => (/* binding */ any),
/* harmony export */ "none": () => (/* binding */ none),
/* harmony export */ "newVec": () => (/* binding */ newVec),
/* harmony export */ "indexVec": () => (/* binding */ indexVec),
/* harmony export */ "popfirst": () => (/* binding */ popfirst),
/* harmony export */ "pushfirst": () => (/* binding */ pushfirst),
/* harmony export */ "circleFrom3points": () => (/* binding */ circleFrom3points),
/* harmony export */ "distanceWeightedMean": () => (/* binding */ distanceWeightedMean),
/* harmony export */ "weightedmean": () => (/* binding */ weightedmean),
/* harmony export */ "nearestPointOfPoints": () => (/* binding */ nearestPointOfPoints),
/* harmony export */ "farthestPointOfPoints": () => (/* binding */ farthestPointOfPoints),
/* harmony export */ "intersectLineCircle": () => (/* binding */ intersectLineCircle),
/* harmony export */ "sortAscending": () => (/* binding */ sortAscending),
/* harmony export */ "sortDescending": () => (/* binding */ sortDescending)
/* harmony export */ });
/** [v1[0] + v2[0], v1[1] + v2[1]] */
function add(v1, v2) {
return [v1[0] + v2[0], v1[1] + v2[1]];
}
/** [v[0] * k, v[1] * k] */
function mul(v, k) {
return [v[0] * k, v[1] * k];
}
/** [v[0] / k, v[1] / k]*/
function div(v, k) {
return [v[0] / k, v[1] / k];
}
/** Length of a Vec2 */
function len(v) {
return Math.hypot(v[0], v[1]);
}
/** Sum values of v */
function sum(v) {
let sum = 0;
for (const x of v) {
sum += x;
}
return sum;
}
function dot(v1, v2) {
return v1[0] * v2[0] + v1[1] * v2[1];
}
function normalize(v) {
const l = len(v);
return [v[0] / l, v[1] / l];
}
/**
* Return the minimum value and its index in vector vec
* (return value: Infinity if vec=[])
*/
function minimum(vec) {
let index = -1;
let value = Infinity;
for (const [i, v] of vec.entries()) {
if (v < value) {
value = v;
index = i;
}
}
return {
value,
index
};
}
/**
* Return the maximum value and its index in vector vec
* * (return value: -Infinity if vec=[])
*/
function maximum(vec) {
let index = -1;
let value = -Infinity;
for (const [i, v] of vec.entries()) {
if (v > value) {
value = v;
index = i;
}
}
return {
value,
index
};
}
/**
* offset p1 a maximum of 20 units toward p2 (stop at p2)
*/
function offsetmax20(p1, p2) {
const d = Math.min(20, dist(p1, p2));
return offset(p1, p2, d);
}
/**
* Return a vector without duplicate values.
*/
function unique(v) {
return [...new Set(v)];
}
/**
* Return a vector that points from p1 to p2.
*/
function vecFromPositions(p1, p2) {
return [p2[0] - p1[0], p2[1] - p1[1]];
}
/**
* Return a unitvector that points from p1 to p2.
*/
function unitvecFromPositions(p1, p2) {
return normalize(vecFromPositions(p1, p2));
}
function dist(p1, p2) {
const v = vecFromPositions(p1, p2);
return len(v);
}
/**
* ```raw
* True if distance between p1 and p2 is leq than d.
*
* default d=200 which is ship range
* ```
*/
function isWithinDist(p1, p2, d = 200) {
return dist(p1, p2) <= d;
}
/**
* normalization followed by dot product gives a measure of direction similarity -1..1 zero means perpendicular
*/
function directionSimilarity(v1, v2) {
return dot(normalize(v1), normalize(v2));
}
/**
* clamp x to lie in a..b range
*/
function clamp(x, a, b) {
return Math.min(b, Math.max(a, x));
}
function clamp01(x) {
return clamp(x, 0, 1);
}
/**
* ```raw
* Return a point that lies fraction t from p1 toward p2, default t=0.5
* ```
*/
function mix(p1, p2, t = 0.5) {
const v = vecFromPositions(p1, p2);
const v_scaled = mul(v, clamp01(t)); //might not want to clamp t?
const p = add(p1, v_scaled);
return p;
}
/**
* ```raw
* Return a point that lies distance d away from p1, in the direction of p2.
* note: d can be negative
* ```
*/
function offset(p1, p2, d) {
if (Math.abs(d) < 0.000000001) {
return p1;
}
if (dist(p1, p2) < 0.00000001) {
return p2;
}
const unitvec = unitvecFromPositions(p1, p2);
const v = mul(unitvec, d);
const p = add(p1, v);
return p;
}
/**
*```raw
* The points where a line from p1 would tangent a circle at center p2 with radius r
*
* Returns 2 points as list [p1, p2] or
* returns empty list [] if no tangentpoint exist. (it means p is inside the circle)
* ```
*/
function tangentPoints(p, c, r) {
//https://math.stackexchange.com/questions/543496/how-to-find-the-equation-of-a-line-tangent-to-a-circle-that-passes-through-a-g
//r is radius of circle with center c
const Cx = c[0];
const Cy = c[1];
const Px = p[0];
const Py = p[1];
const dx = Px - Cx;
const dy = Py - Cy;
const dxr = -dy;
const dyr = dx;
const d = Math.sqrt(dx * dx + dy * dy);
if (d < r) {
return []; //no tangentpoints (p is inside circle c)
}
const rho = r / d;
const ad = rho * rho;
const bd = rho * Math.sqrt(1 - rho * rho);
const T1x = Cx + ad * dx + bd * dxr;
const T1y = Cy + ad * dy + bd * dyr;
const T2x = Cx + ad * dx - bd * dxr;
const T2y = Cy + ad * dy - bd * dyr; //tangentpoints
const tp1 = [T1x, T1y];
const tp2 = [T2x, T2y];
return [tp1, tp2];
}
/**
* Return either vector v1 or v2
*
* whichever points in the direction most similar to the direciton of vector v
*/
function mostSimilarVec(v1, v2, v) {
const s1 = directionSimilarity(v, v1);
const s2 = directionSimilarity(v, v2);
const v_mostsimilar = s1 > s2 ? v1 : v2;
return v_mostsimilar;
}
/**
* ```raw
* Where a circle at p1 with radius r1 intersects a circle at p2 with radius r2.
*
* Returns 2 points as list [p1, p2] or
* returns empty list [] if no intersection exist.
* ```
*/
function intersectTwoCircles(p1, r1, p2, r2) {
//https://gist.github.com/jupdike/bfe5eb23d1c395d8a0a1a4ddd94882ac
const x1 = p1[0];
const y1 = p1[1];
const x2 = p2[0];
const y2 = p2[1];
const centerdx = x1 - x2;
const centerdy = y1 - y2;
const R = Math.sqrt(centerdx * centerdx + centerdy * centerdy);
if (!(Math.abs(r1 - r2) <= R && R <= r1 + r2)) {
return []; // no intersections
} // intersection(s) should exist
const R2 = R * R;
const R4 = R2 * R2;
const a = (r1 * r1 - r2 * r2) / (2 * R2);
const r2r2 = r1 * r1 - r2 * r2;
const c = Math.sqrt(2 * (r1 * r1 + r2 * r2) / R2 - r2r2 * r2r2 / R4 - 1);
const fx = (x1 + x2) / 2 + a * (x2 - x1);
const gx = c * (y2 - y1) / 2;
const ix1 = fx + gx;
const ix2 = fx - gx;
const fy = (y1 + y2) / 2 + a * (y2 - y1);
const gy = c * (x1 - x2) / 2;
const iy1 = fy + gy;
const iy2 = fy - gy; // note if gy == 0 and gx == 0 then the circles are tangent and there is only one solution
// but that one solution will just be duplicated as the code is currently written
return [[ix1, iy1], [ix2, iy2]];
}
/**
* intersectTwoCircles but pick the point (of the two points) nearest to targetpoint
*/
function intersectPoint(p1, r1, p2, r2, targetpoint) {
const ps = intersectTwoCircles(p1, r1, p2, r2);
return nearestPointOfPoints(ps, targetpoint);
}
/**
* intersectTwoCircles but pick the point (of the two points) farthest away from targetpoint
*/
function intersectPointFarthest(p1, r1, p2, r2, targetpoint) {
const ps = intersectTwoCircles(p1, r1, p2, r2);
return farthestPointOfPoints(ps, targetpoint);
}
/**
* perpendicular Clockwise
*/
function perpendicularCW(v) {
return [v[1], -v[0]];
}
/**
* perpendicular Counter Clockwise
*/
function perpendicularCCW(v) {
return [-v[1], v[0]];
}
/**
* Return a boolean vector filled with false
*/
function falses(n) {
return new Array(n).fill(false);
}
/**
* Return a boolean vector filled with true
*/
function trues(n) {
return new Array(n).fill(true);
}
/**
* Return true if all elements in v are true
*/
function all(v) {
return v.every(x => x === true);
}
/**
* Return true if any element in v is true
*/
function any(v) {
return v.some(x => x === true);
}
/**
* Return true if all elements in v are false
*/
function none(v) {
return !any(v);
}
/**
* Return a new vector of length n, filled with x (default x=0)
*/
function newVec(n, x = 0) {
return new Array(n).fill(x);
}
/**
* Returns a new vector [0,1,2,...,n-1]
* starting from x default 0
*/
function indexVec(n, x = 0) {
const v = new Array(n).fill(0);
return v.map((v, i) => i + x);
}
/**
* modifies v.
*
* Remove first item from and return it.
* (v.pop() removes last item and returns it)
*/
function popfirst(v) {
const x = v.shift();
if (x === undefined) {
return -1; //make typescript happy
} else {
return x;
}
}
/**
* modifies v.
*
* Put x at the begining of v and return v
* * (v.push(x) puts x at end)
*/
function pushfirst(v, x) {
//const len = v.unshift(x);
v.unshift(x);
return v;
}
/**
* Construct a circle from 3 points on its circumference.
*
* Return [centerpoint, radius]
*/
function circleFrom3points(p1, p2, p3) {
//https://math.stackexchange.com/questions/213658/get-the-equation-of-a-circle-when-given-3-points
const x1 = p1[0];
const y1 = p1[1];
const x2 = p2[0];
const y2 = p2[1];
const x3 = p3[0];
const y3 = p3[1];
const A = x1 * (y2 - y3) - y1 * (x2 - x3) + x2 * y3 - x3 * y2;
const B = (x1 * x1 + y1 * y1) * (y3 - y2) + (x2 * x2 + y2 * y2) * (y1 - y3) + (x3 * x3 + y3 * y3) * (y2 - y1);
const C = (x1 * x1 + y1 * y1) * (x2 - x3) + (x2 * x2 + y2 * y2) * (x3 - x1) + (x3 * x3 + y3 * y3) * (x1 - x2);
const D = (x1 * x1 + y1 * y1) * (x3 * y2 - x2 * y3) + (x2 * x2 + y2 * y2) * (x1 * y3 - x3 * y1) + (x3 * x3 + y3 * y3) * (x2 * y1 - x1 * y2);
const center = [-B / (2 * A), -C / (2 * A)];
const radius = Math.sqrt((B * B + C * C - 4 * A * D) / (4 * A * A));
return [center, radius];
}
/**
* ```raw
* Weighted mean, where weighting coefficient for each data point is
* the inverse sum of distances between this data point and the other data points
* ```
*/
function distanceWeightedMean(points) {
//https://encyclopediaofmath.org/wiki/Distance-weighted_mean
if (points.length === 1) {
return points[0];
} //const k = points.length;
const k = 1;
const w = [];
for (const point of points) {
const sumdistances = sum(points.map(p => dist(p, point)));
w.push(k / sumdistances);
}
const sumw = sum(w);
const wx = sum(points.map((p, i) => w[i] * p[0]));
const wy = sum(points.map((p, i) => w[i] * p[1]));
const x = wx / sumw;
const y = wy / sumw; //if all points are the same (or there is only a single point) this produces [NaN,NaN]
if (isNaN(x) || isNaN(y)) {
return points[0];
} else {
return [x, y];
}
}
function weightedmean(points, weights) {
const x = sum(points.map((p, i) => weights[i] * p[0]));
const y = sum(points.map((p, i) => weights[i] * p[1]));
const weightsum = sum(weights);
return [x / weightsum, y / weightsum];
}
/**
* Return the point in the vector ps=[p1,p2,p2] that is closest to target point targetpoint
*/
function nearestPointOfPoints(ps, targetpoint) {
const d = ps.map(p => dist(p, targetpoint));
const i = minimum(d).index;
return ps[i];
}
/**
* Return the point in the vector ps=[p1,p2,p2] that is farthest away from point targetpoint
*/
function farthestPointOfPoints(ps, targetpoint) {
const d = ps.map(p => dist(p, targetpoint));
const i = maximum(d).index;
return ps[i];
}
/**
* A*x^2 + B*x + C = 0
* return [x1,x2]
*/
function quadraticroots(A, B, C) {
const r = Math.sqrt(B * B - 4 * A * C);
const x1 = (-B + r) / (2 * A);
const x2 = (-B - r) / (2 * A);
return [x1, x2];
}
/**
* ```raw
* return two points [a, b] where (infinite) line created by p1->p2 intersects circle with center center and radius r.
*
* note: return empty list [] if no intersection exist.
* ```
*/
function intersectLineCircle(p1, p2, center, r) {
//https://math.stackexchange.com/questions/228841/how-do-i-calculate-the-intersections-of-a-straight-line-and-a-circle
const x1 = p1[0];
const y1 = p1[1];
const x2 = p2[0];
const y2 = p2[1];
const p = center[0];
const q = center[1];
if (x1 === x2) {
//vertical line
const k = x1;
const A = 1;
const B = -2 * q;
const C = p * p + q * q - r * r - 2 * k * p + k * k;
if (B * B - 4 * A * C < 0) {
//no intersection
return [];
}
const [y_1, y_2] = quadraticroots(A, B, C);
return [[k, y_1], [k, y_2]];
}
const m = (y2 - y1) / (x2 - x1);
const c = y1 - m * x1;
const A = m * m + 1;
const B = 2 * (m * c - m * q - p);
const C = q * q - r * r + p * p - 2 * c * q + c * c;
if (B * B - 4 * A * C < 0) {
//no intersection
return [];
}
const [x_1, x_2] = quadraticroots(A, B, C); //y = m*x + c
const y_1 = m * x_1 + c;
const y_2 = m * x_2 + c;
return [[x_1, y_1], [x_2, y_2]];
}
/**
* smallest first
*/
function sortAscending(v) {
return v.slice().sort((a, b) => a - b);
}
/**
* biggest first
*/
function sortDescending(v) {
return v.slice().sort((a, b) => b - a);
}
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
(() => {
/*!**********************!*\
!*** ./src/index.ts ***!
\**********************/
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _move_move__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./move/move */ "./src/move/move.ts");
/* harmony import */ var _energize_energize__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./energize/energize */ "./src/energize/energize.ts");
/* harmony import */ var _sendcommands__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./sendcommands */ "./src/sendcommands.ts");
/* harmony import */ var _sendendgamecommands__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./sendendgamecommands */ "./src/sendendgamecommands.ts");
function main() {
memory.Npathcalls = 0;
memory.movingToHealIds = memory.movingToHealIds ? memory.movingToHealIds : [];
const orders = {
targets: [],
targetps: [],
moving: [],
farmPositioned: [],
defPositioned: [],
attackPositioned: [],
avoiding: []
};
(0,_move_move__WEBPACK_IMPORTED_MODULE_0__.default)(orders);
(0,_energize_energize__WEBPACK_IMPORTED_MODULE_1__.default)(orders);
(0,_sendcommands__WEBPACK_IMPORTED_MODULE_2__.default)(orders.targetps, orders.targets); //console.log(`tick ${tick}, Npathcalls: ${memory.Npathcalls}`);
} //console.log(Object.keys(globalThis));
(0,_sendendgamecommands__WEBPACK_IMPORTED_MODULE_3__.default)() || main();
})();
/******/ })()
;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment