Skip to content

Defense improvements #54

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 52 additions & 10 deletions MissileKite/MissileKite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ const update = function() {
tryFireMissiles();
}

// This is a temporary hack to help protect against cheese.
tryAntiCheeseShield();

// Do we see anything nearby?
const closestEnemy = findEntity(
ENEMY,
Expand Down Expand Up @@ -78,13 +81,17 @@ const update = function() {
else defaultMove();
}

// At this point we know there is an enemy bot nearby.
setEnemySeen(closestEnemyBot);

const allEnemyBots = findEntities(ENEMY, BOT, false);
const numEnemyBots = size(allEnemyBots);
const numEnemyBots = size(findEntities(ENEMY, BOT, false));
const enemyBotDistance = getDistanceTo(closestEnemyBot);

// At this point we know there is an enemy bot nearby.
const shouldDisengage = markEnemyLocation(
closestEnemyBot,
enemyBotDistance,
numEnemyBots
);
if (shouldDisengage) moveToCPU();

const allFriendlyBots = findEntities(IS_OWNED_BY_ME, BOT, true);
const numFriendlyBots = size(allFriendlyBots);

Expand All @@ -96,11 +103,13 @@ const update = function() {
// Protect against missiles/lasers if we have reflection
if (enemyBotDistance < 5.1) {
tryReflect();
if (!isShielded()) {
tryShieldSelf();
} else {
tryShieldFriendlyBots(4);
}
// Throw shields on other bots if possible. This is especially good for
// defense, where the tanks / other low health units will get shield
// priority and can last longer from the multiple DPS units supporting
// them.
tryShieldFriendlyBots(4);
// If no friendly bots shieldable, try myself
if (!isShielded()) tryShieldSelf();
}

// Mine layers should not do it from too far, so they have time to lay mine
Expand Down Expand Up @@ -176,3 +185,36 @@ const shieldTanks = function() {
findEntity(IS_OWNED_BY_ME, BOT, SORT_BY_DISTANCE, SORT_ASCENDING)
);
};

// If enemies spotted in cheesing location, cast shield on CPU (multiple times)
// if possible.
const tryAntiCheeseShield = function() {
const cpuX = arenaWidth - 2;
const cpuY = floor(arenaHeight / 2);
// Check enemy location 1
if (exists(sharedA)) {
const dist1 = abs(sharedA - cpuX) + abs(sharedB - cpuY);
if (sharedA >= arenaWidth - 1 - 1 && dist1 <= 5) {
tryShieldCPU();
}
}
// Check enemy location 2
if (exists(sharedC)) {
const dist2 = abs(sharedC - cpuX) + abs(sharedD - cpuY);
if (sharedC >= arenaWidth - 1 - 1 && dist2 <= 5) {
tryShieldCPU();
}
}
};

const tryShieldCPU = function(): void {
const cpu = findEntity(
IS_OWNED_BY_ME,
CPU,
SORT_BY_DISTANCE,
SORT_ASCENDING
);
if (!exists(cpu)) return;
// Don't check if the CPU is shielded, cause we can multiple cast.
if (canShield(cpu)) shield(cpu);
};
50 changes: 48 additions & 2 deletions SmartMelee/SmartMelee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
* bot moves. So effective DPS can be twice as high (!!) as with normal zapper.
*/
const update = function() {
// Hack for anti-telecloak: if we are in the area where cloakers may be
// running around, always try to (inferno) zap.
if (x >= arenaWidth - 1 - 2) tryZap();

// Equip when we see someone, not blindly
const closestEnemyBot = findEntity(
ENEMY,
Expand All @@ -14,9 +18,16 @@ const update = function() {
SORT_ASCENDING
);
if (exists(closestEnemyBot)) {
setEnemySeen(closestEnemyBot);

const enemyBotDistance = getDistanceTo(closestEnemyBot);
const numEnemyBots = size(findEntities(ENEMY, BOT, false));

const shouldDisengage = markEnemyLocation(
closestEnemyBot,
enemyBotDistance,
numEnemyBots
);
if (shouldDisengage) moveToCPU();

// Zap first or shield first? The great debate. We rarely start zappers
// next to bots because they will get killed too fast. Starting on
// diagonals allows an extra turn to either start zap or arm a defense.
Expand All @@ -34,6 +45,12 @@ const update = function() {
// defender
checkZapActivation(enemyBotDistance);
checkDefenseActivation(enemyBotDistance);

// Hack for evading (dumb, straight-line) miners on defense. Just
// jump to a different row to pursue them. 2 or less and we are in
// charge range, so no evasion needed.
if (numEnemyBots == 1)
tryEvadeMiners(closestEnemyBot, enemyBotDistance);
}
}

Expand Down Expand Up @@ -98,3 +115,32 @@ const checkZapActivation = function(enemyBotDistance: number): void {
if (canZap()) zap();
}
};

/**
* Defensive function for melee bots to avoid running blindly into mines.
* @param closestEnemyBot entity representing the closest bot we see
*/
const tryEvadeMiners = function(
closestEnemyBot: Entity,
enemyBotDistance: number
) {
// This is the most likely scenario, chasing enemies across the map horizontally
if (y == closestEnemyBot.y && enemyBotDistance >= 3) {
// Move up or down randomly if both directions are available
if (canMove("up") && canMove("down")) {
if (percentChance(50)) move("up");
else move("down");
}
if (canMove("up")) move("up");
if (canMove("down")) move("down");
}
// Less likely scenario, chasing a miner vertically
if (x == closestEnemyBot.x && enemyBotDistance >= 3) {
if (canMove("forward") && canMove("backward")) {
if (percentChance(50)) move("forward");
else move("backward");
}
if (canMove("backward")) move("backward");
if (canMove("forward")) move("forward");
}
};
1 change: 1 addition & 0 deletions SmartMelee/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"compilerOptions": {
"target": "es3",
"module": "none",
"removeComments": true,
"sourceMap": false,
"outFile": "bot.js"
},
Expand Down
14 changes: 9 additions & 5 deletions ZapKite/ZapKite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,17 @@ const update = function() {
else defaultMove();
}

// At this point we know there is an enemy bot nearby.
setEnemySeen(closestEnemyBot);

const allEnemyBots = findEntities(ENEMY, BOT, false);
const numEnemyBots = size(allEnemyBots);
const numEnemyBots = size(findEntities(ENEMY, BOT, false));
const enemyBotDistance = getDistanceTo(closestEnemyBot);

// At this point we know there is an enemy bot nearby.
const shouldDisengage = markEnemyLocation(
closestEnemyBot,
enemyBotDistance,
numEnemyBots
);
if (shouldDisengage) moveToCPU();

const allFriendlyBots = findEntities(IS_OWNED_BY_ME, BOT, true);
const numFriendlyBots = size(allFriendlyBots);

Expand Down
70 changes: 54 additions & 16 deletions lib/movement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,57 @@ const defaultMove = function() {

// Where to go?
if (isAttacker) {
const cpuX = arenaWidth - 1;
const cpuY = floor(arenaHeight / 2);
moveTo(cpuX, cpuY);
moveToCPU();
} else {
defenderMove();
}
};

const moveToCPU = function() {
const cpuX = arenaWidth - 2;
const cpuY = floor(arenaHeight / 2);
moveTo(cpuX, cpuY);
};

/**
* We have seen some baddies. Setting this causes other bots to move accordingly
* to the enemy's location.
* @returns true if we should disengage from chasing this bot.
*/
const setEnemySeen = function(enemy: Entity): void {
const markEnemyLocation = function(
enemy: Entity,
distToEnemy: number,
totalEnemies: number
): boolean {
let targetX = enemy.x;
let targetY = enemy.y;

// First decide if we should pursue this enemy. The risks to pursuing are
// lures and landmines. When bots are far left on the map, we'll only mark a
// bot's location for pursuit if someone sees either more than one bot, or
// target is <= 2 hexes away from someone. If neither of these are true,
// don't try to pursue.

// For 13x17 maps this is 16 // 3 = 5.
const pursuitBoundary = floor(arenaWidth / 3);
if (targetX < pursuitBoundary && distToEnemy > 2 && totalEnemies == 1)
return true;

// If we see a target at the top or bottom edge of the map, assume they're
// trying to rush the CPU and set intercept accordingly.
if (targetX >= arenaWidth - 1 - 4) {
const cpuX = arenaWidth - 2;
const cpuY = floor(arenaHeight / 2);
if (targetY <= 0 + 1) {
targetX = cpuX;
targetY = cpuY - 5;
}
if (targetY >= arenaHeight - 1 - 1) {
targetX = cpuX;
targetY = cpuY + 5;
}
}

// There are 5 shared variables, A-E.
// - shared(A,B): location of one last seen enemy
// - shared(C,D): location of second last seen enemy, that is not close to
Expand All @@ -66,29 +104,29 @@ const setEnemySeen = function(enemy: Entity): void {

// Record 1st location if we don't already have one.
if (!exists(sharedA)) {
sharedA = enemy.x;
sharedB = enemy.y;
sharedA = targetX;
sharedB = targetY;
return;
}
const locOneDiff = abs(enemy.x - sharedA) + abs(enemy.y - sharedB);
const locOneDiff = abs(targetX - sharedA) + abs(targetY - sharedB);
// If it's sufficiently close, count it as the same "area" and just
// update.
if (locOneDiff < 6) {
sharedA = enemy.x;
sharedB = enemy.y;
sharedA = targetX;
sharedB = targetY;
return;
}

// This seems like a different location. Do we have something recorded for location 2?
if (!exists(sharedC)) {
sharedC = enemy.x;
sharedD = enemy.y;
sharedC = targetX;
sharedD = targetY;
return;
}
const locTwoDiff = abs(enemy.x - sharedC) + abs(enemy.y - sharedD);
const locTwoDiff = abs(targetX - sharedC) + abs(targetY - sharedD);
if (locTwoDiff < 8) {
sharedC = enemy.x;
sharedD = enemy.y;
sharedC = targetX;
sharedD = targetY;
return;
}

Expand Down Expand Up @@ -125,7 +163,7 @@ const defenderMove = function(): void {
// Check if we're close to either of the known enemy locations, and if we
// don't see anyone there (with sensors) clear it.
if (exists(sharedA)) {
if (getDistanceTo(sharedA, sharedB) <= 1) {
if (getDistanceTo(sharedA, sharedB) <= 2) {
tryActivateSensors();
if (areSensorsActivated()) {
sharedA = undefined;
Expand All @@ -134,7 +172,7 @@ const defenderMove = function(): void {
}
}
if (exists(sharedC)) {
if (getDistanceTo(sharedC, sharedD) <= 1) {
if (getDistanceTo(sharedC, sharedD) <= 2) {
tryActivateSensors();
if (areSensorsActivated()) {
sharedC = undefined;
Expand Down