Skip to content
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

Fix typing of creep.body[n].boost to use mineral boosts #257

Open
wants to merge 2 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
20 changes: 17 additions & 3 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,6 @@ declare const REACTION_TIME: {
};

declare const BOOSTS: {
[part: string]: { [boost: string]: { [action: string]: number } };
work: {
UO: {
harvest: 3;
Expand Down Expand Up @@ -739,7 +738,7 @@ declare const BOOSTS: {
damage: 0.3;
};
};
};
} & Record<BodyPartConstant, Record<MineralBoostConstant, Record<BoostModifier, number>>>;

declare const INTERSHARD_RESOURCES: InterShardResourceConstant[];

Expand Down Expand Up @@ -1746,7 +1745,7 @@ type BodyPartDefinition<T extends BodyPartConstant = BodyPartConstant> = T exten
*
* If the body part is boosted, this property specifies the mineral type which is used for boosting.
*/
boost?: keyof (typeof BOOSTS)[T];
boost?: keyof typeof BOOSTS[T];
/**
* One of the body part types constants.
*/
Expand Down Expand Up @@ -2777,6 +2776,21 @@ type EffectConstant = EFFECT_INVULNERABILITY | EFFECT_COLLAPSE_TIMER;

type EFFECT_INVULNERABILITY = 1001;
type EFFECT_COLLAPSE_TIMER = 1002;

type BoostModifier =
| "harvest"
| "build"
| "repair"
| "dismantle"
| "upgradeController"
| "attack"
| "rangedAttack"
| "rangedMassAttack"
| "heal"
| "rangedHeal"
| "capacity"
| "fatigue"
| "damage";
/**
* The options that can be accepted by `findRoute()` and friends.
*/
Expand Down
161 changes: 159 additions & 2 deletions dist/screeps-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1030,8 +1030,165 @@ function resources(o: GenericStore): ResourceConstant[] {
EXTENSION_ENERGY_CAPACITY[Game.rooms.myRoom.controller!.level];

REACTIONS[Object.keys(creep.carry)[0]];
}

{
// Test the BOOSTS constant

// Can be used with a body part, returns a record of mineral -> boosted property -> level
const c = BOOSTS[creep.body[0].type];

// Can be used with all body part types, returns undefined
const undef = BOOSTS["claim"];

// Can still be iterated over
for (const bodyPart of Object.keys(BOOSTS) as BodyPartConstant[]) {
const boosts = BOOSTS[bodyPart];
for (const mineral of Object.keys(boosts) as MineralBoostConstant[]) {
const upgrades = boosts[mineral];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without the fixes, this fails with

Element implicitly has an 'any' type because expression of type 'MineralBoostConstant' can't be used to index type '{ [boost: string]: { [action: string]: number; }; } | { UO: { harvest: 3; }; UHO2: { harvest: 5; }; XUHO2: { harvest: 7; }; LH: { build: 1.5; repair: 1.5; }; LH2O: { build: 1.8; repair: 1.8; }; XLH2O: { build: 2; repair: 2; }; ... 5 more ...; XGH2O: { ...; }; } | ... 5 more ... | { ...; }'.
  Property 'UH' does not exist on type '{ [boost: string]: { [action: string]: number; }; } | { UO: { harvest: 3; }; UHO2: { harvest: 5; }; XUHO2: { harvest: 7; }; LH: { build: 1.5; repair: 1.5; }; LH2O: { build: 1.8; repair: 1.8; }; XLH2O: { build: 2; repair: 2; }; ... 5 more ...; XGH2O: { ...; }; } | ... 5 more ... | { ...; }'.ts(7053)

}
}
}

BOOSTS[creep.body[0].type];
{
// Boost estimation code lifted from Overmind

type HARVEST = "harvest";
type CONSTRUCT = "construct";
type DISMANTLE = "dismantle";
type UPGRADE = "upgrade";
const HARVEST: HARVEST = "harvest";
const CONSTRUCT: CONSTRUCT = "construct";
const DISMANTLE: DISMANTLE = "dismantle";
const UPGRADE: UPGRADE = "upgrade";

type BoostTier = "T1" | "T2" | "T3";
type BoostType = ATTACK | CARRY | RANGED_ATTACK | HEAL | MOVE | TOUGH | HARVEST | CONSTRUCT | DISMANTLE | UPGRADE;

const BOOST_TIERS: {
[boostType in BoostType]: {
[boostTier in BoostTier]: MineralBoostConstant;
};
} = {
attack: {
T1: "UH",
T2: "UH2O",
T3: "XUH2O",
},
carry: {
T1: "KH",
T2: "KH2O",
T3: "XKH2O",
},
ranged_attack: {
T1: "KO",
T2: "KHO2",
T3: "XKHO2",
},
heal: {
T1: "LO",
T2: "LHO2",
T3: "XLHO2",
},
move: {
T1: "ZO",
T2: "ZHO2",
T3: "XZHO2",
},
tough: {
T1: "GO",
T2: "GHO2",
T3: "XGHO2",
},
harvest: {
T1: "UO",
T2: "UHO2",
T3: "XUHO2",
},
construct: {
T1: "LH",
T2: "LH2O",
T3: "XLH2O",
},
dismantle: {
T1: "ZH",
T2: "ZH2O",
T3: "XZH2O",
},
upgrade: {
T1: "GH",
T2: "GH2O",
T3: "XGH2O",
},
};

const BoostTypeBodyparts: {
[boostType in BoostType]: BodyPartConstant;
} = {
[ATTACK]: ATTACK,
[CARRY]: CARRY,
[RANGED_ATTACK]: RANGED_ATTACK,
[HEAL]: HEAL,
[MOVE]: MOVE,
[TOUGH]: TOUGH,
[HARVEST]: WORK,
[CONSTRUCT]: WORK,
[DISMANTLE]: WORK,
[UPGRADE]: WORK,
};

const BoostTypeToBoostArray: {
[boostType in BoostType]: BoostModifier;
} = {
[ATTACK]: ATTACK,
[CARRY]: "capacity",
[RANGED_ATTACK]: "rangedAttack",
// [RANGED_MASS_ATTACK]: "rangedMassAttack",
[HEAL]: HEAL,
[MOVE]: "fatigue",
[TOUGH]: "damage",
[HARVEST]: "harvest",
[CONSTRUCT]: "build",
// [REPAIR]: "repair",
[DISMANTLE]: "dismantle",
[UPGRADE]: "upgradeController",
};

/**
*
* @param body
* @param type
* @param intendedBoosts
* @returns
*/
function getBodyPotential(body: BodyPartDefinition[], type: BoostType, intendedBoosts: MineralBoostConstant[] = []): number {
const bodyPart = BoostTypeBodyparts[type];
return body.reduce((sum, part) => {
if (part.hits === 0) {
return sum + 0;
}
if (part.type === bodyPart) {
let boost = part.boost;
if (!boost && intendedBoosts) {
boost = intendedBoosts.find(
(boost) => boost === BOOST_TIERS[type].T1 || boost === BOOST_TIERS[type].T2 || boost === BOOST_TIERS[type].T3,
);
}
if (!boost) {
return sum + 1;
}

const key = BoostTypeToBoostArray[type];
const partBoost = BOOSTS[bodyPart];
if (!partBoost || !(boost in partBoost) || !partBoost[boost] || !(key in partBoost[boost])) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the partBoost[boost] checks error with

Element implicitly has an 'any' type because expression of type 'string | number' can't be used to index type '{ [boost: string]: { [action: string]: number; }; } | { UO: { harvest: 3; }; UHO2: { harvest: 5; }; XUHO2: { harvest: 7; }; LH: { build: 1.5; repair: 1.5; }; LH2O: { build: 1.8; repair: 1.8; }; XLH2O: { build: 2; repair: 2; }; ... 5 more ...; XGH2O: { ...; }; } | ... 5 more ... | { ...; }'.
  No index signature with a parameter of type 'string' was found on type '{ [boost: string]: { [action: string]: number; }; } | { UO: { harvest: 3; }; UHO2: { harvest: 5; }; XUHO2: { harvest: 7; }; LH: { build: 1.5; repair: 1.5; }; LH2O: { build: 1.8; repair: 1.8; }; XLH2O: { build: 2; repair: 2; }; ... 5 more ...; XGH2O: { ...; }; } | ... 5 more ... | { ...; }'.ts(7053)

return sum + 0;
}

return partBoost[boost][key];
}
return sum + 0;
}, 0);
}
}

// Tombstones
Expand Down Expand Up @@ -1185,7 +1342,7 @@ function atackPower(creep: Creep) {
return creep.body
.map((part) => {
if (part.type === ATTACK) {
const multiplier = part.boost ? BOOSTS[part.type][part.boost].attack : 1;
const multiplier = part.boost ? BOOSTS[part.type][part.boost]?.attack ?? 0 : 1;
return multiplier * ATTACK_POWER;
}
return 0;
Expand Down
3 changes: 1 addition & 2 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,6 @@ declare const REACTION_TIME: {
};

declare const BOOSTS: {
[part: string]: { [boost: string]: { [action: string]: number } };
work: {
UO: {
harvest: 3;
Expand Down Expand Up @@ -724,7 +723,7 @@ declare const BOOSTS: {
damage: 0.3;
};
};
};
} & Record<BodyPartConstant, Record<MineralBoostConstant, Record<BoostModifier, number>>>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
} & Record<BodyPartConstant, Record<MineralBoostConstant, Record<BoostModifier, number>>>;
} & Record<BodyPartConstant, Record<MineralBoostConstant, Record<BoostModifier, number>>>;

I think this change ruins some indexing into BOOSTS that people may expect to do.
I would argue that there are better solutions to that - I don't even think this Record type should be there, nor the BoostModifier type.
Normal iterations result in a key of type string, thus you can only use it on objects with an index signature Record<string, T>.

I think it is a bad idea to just add that to all objects though...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know what's the fix then. Right now, the code I have fails unless I overlay that over BOOSTS. And to be fair the initial issue is about creep.body[0].boost being wrong. That's just the part I brought from OM since I think it acts as documentation over what the keys actually are.

Also, I'm using my own wrappers over Object.keys/values/entries to make them return the correct key/value/tuple type instead of string, which maybe that's just a me thing.


declare const INTERSHARD_RESOURCES: InterShardResourceConstant[];

Expand Down
2 changes: 1 addition & 1 deletion src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ type BodyPartDefinition<T extends BodyPartConstant = BodyPartConstant> = T exten
*
* If the body part is boosted, this property specifies the mineral type which is used for boosting.
*/
boost?: keyof (typeof BOOSTS)[T];
boost?: keyof typeof BOOSTS[T];
/**
* One of the body part types constants.
*/
Expand Down
15 changes: 15 additions & 0 deletions src/literals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -700,3 +700,18 @@ type EffectConstant = EFFECT_INVULNERABILITY | EFFECT_COLLAPSE_TIMER;

type EFFECT_INVULNERABILITY = 1001;
type EFFECT_COLLAPSE_TIMER = 1002;

type BoostModifier =
| "harvest"
| "build"
| "repair"
| "dismantle"
| "upgradeController"
| "attack"
| "rangedAttack"
| "rangedMassAttack"
| "heal"
| "rangedHeal"
| "capacity"
| "fatigue"
| "damage";
Loading