diff --git a/src/Action/BalanceHeroResourcesAction.ts b/src/Action/BalanceHeroResourcesAction.ts index cb929d8..fbe8db3 100644 --- a/src/Action/BalanceHeroResourcesAction.ts +++ b/src/Action/BalanceHeroResourcesAction.ts @@ -6,7 +6,7 @@ import { changeHeroResource, grabCurrentHeroResource } from '../Page/HeroPage'; import { HeroAllResources } from '../Game'; import { grabActiveVillageId } from '../Page/VillageBlock'; import { HeroState } from '../State/HeroState'; -import { Core } from '../Core/HeroBalance'; +import { calcHeroResource } from '../Core/HeroBalance'; @registerAction export class BalanceHeroResourcesAction extends ActionController { @@ -25,7 +25,7 @@ export class BalanceHeroResourcesAction extends ActionController { const storage = grabResourceStorage(); const currentType = grabCurrentHeroResource(); - const heroType = Core.calcHeroResource(resources, requiredResources, totalRequiredResources, storage); + const heroType = calcHeroResource(resources, requiredResources, totalRequiredResources, storage); if (heroType !== currentType) { changeHeroResource(heroType); diff --git a/src/Command.ts b/src/Command.ts index 3a010f0..f28dfbd 100644 --- a/src/Command.ts +++ b/src/Command.ts @@ -1,5 +1,5 @@ -import { ResourcesInterface } from './Game'; import { TaskId } from './Queue/TaskQueue'; +import { ResourcesInterface } from './Core/Resources'; export interface Args { taskId?: TaskId; diff --git a/src/ControlPanel.ts b/src/ControlPanel.ts index c7dbc2a..4267c2a 100644 --- a/src/ControlPanel.ts +++ b/src/ControlPanel.ts @@ -14,7 +14,8 @@ import DashboardApp from './DashboardView/Dashboard.vue'; import { ResourcesToLevel } from './Task/ResourcesToLevel'; import { ConsoleLogger, Logger } from './Logger'; import { VillageState } from './State/VillageState'; -import { Resources, Village } from './Game'; +import { Village } from './Game'; +import { Resources } from './Core/Resources'; interface QuickAction { label: string; diff --git a/src/Core/HeroBalance.ts b/src/Core/HeroBalance.ts index d68bd1e..d857203 100644 --- a/src/Core/HeroBalance.ts +++ b/src/Core/HeroBalance.ts @@ -1,39 +1,38 @@ -import { HeroAllResources, HeroResourceType, Resources, ResourceStorage } from '../Game'; +import { Resources } from './Resources'; +import { HeroAllResources, HeroResourceType, ResourceStorage } from '../Game'; -export namespace Core { - export function calcHeroResource( - current: Resources, - required: Resources, - totalRequired: Resources, - storage: ResourceStorage - ): HeroResourceType { - const resourceDiff = calcNeedResources(current, required, totalRequired, storage); - const resourcesAsList = resourceDiff.asList(); +export function calcHeroResource( + current: Resources, + required: Resources, + totalRequired: Resources, + storage: ResourceStorage +): HeroResourceType { + const resourceDiff = calcNeedResources(current, required, totalRequired, storage); + const resourcesAsList = resourceDiff.asList(); - const sorted = resourcesAsList.sort((x, y) => y.value - x.value); + const sorted = resourcesAsList.sort((x, y) => y.value - x.value); - const maxRequirement = sorted[0]; - const minRequirement = sorted[sorted.length - 1]; - const delta = maxRequirement.value - minRequirement.value; - const eps = maxRequirement.value / 10; + const maxRequirement = sorted[0]; + const minRequirement = sorted[sorted.length - 1]; + const delta = maxRequirement.value - minRequirement.value; + const eps = maxRequirement.value / 10; - return delta > eps ? maxRequirement.type : HeroAllResources; - } - - function calcNeedResources( - current: Resources, - required: Resources, - totalRequired: Resources, - storage: ResourceStorage - ): Resources { - if (!current.gt(required)) { - return required.sub(current); - } - - if (!current.gt(totalRequired)) { - return totalRequired.sub(current); - } - - return Resources.fromStorage(storage).sub(current); - } + return delta > eps ? maxRequirement.type : HeroAllResources; +} + +function calcNeedResources( + current: Resources, + required: Resources, + totalRequired: Resources, + storage: ResourceStorage +): Resources { + if (!current.gt(required)) { + return required.sub(current); + } + + if (!current.gt(totalRequired)) { + return totalRequired.sub(current); + } + + return Resources.fromStorage(storage).sub(current); } diff --git a/src/Core/ResourceType.ts b/src/Core/ResourceType.ts new file mode 100644 index 0000000..b74a684 --- /dev/null +++ b/src/Core/ResourceType.ts @@ -0,0 +1,24 @@ +export enum ResourceType { + Lumber = 1, + Clay = 2, + Iron = 3, + Crop = 4, +} + +export const ResourceMapping: ReadonlyArray<{ num: number; type: ResourceType }> = [ + { num: 1, type: ResourceType.Lumber }, + { num: 2, type: ResourceType.Clay }, + { num: 3, type: ResourceType.Iron }, + { num: 4, type: ResourceType.Crop }, +]; + +export function numberToResourceType(typeAsNumber: number): ResourceType { + for (let mp of ResourceMapping) { + if (typeAsNumber === mp.num) { + return mp.type; + } + } + throw new Error(`Type ${typeAsNumber} in not valid`); +} + +export type ResourceList = Array<{ num: number; type: ResourceType; value: number }>; diff --git a/src/Core/Resources.ts b/src/Core/Resources.ts new file mode 100644 index 0000000..e3f7bae --- /dev/null +++ b/src/Core/Resources.ts @@ -0,0 +1,90 @@ +import { ResourceStorage } from '../Game'; +import { ResourceList, ResourceMapping, ResourceType } from './ResourceType'; + +export interface ResourcesInterface { + lumber: number; + clay: number; + iron: number; + crop: number; +} + +export class Resources implements ResourcesInterface { + readonly lumber: number; + readonly clay: number; + readonly iron: number; + readonly crop: number; + + constructor(lumber: number, clay: number, iron: number, crop: number) { + this.lumber = Math.floor(lumber); + this.clay = Math.floor(clay); + this.iron = Math.floor(iron); + this.crop = Math.floor(crop); + } + + static fromObject(obj: ResourcesInterface): Resources { + return new Resources(obj.lumber, obj.clay, obj.iron, obj.crop); + } + + static fromStorage(storage: ResourceStorage): Resources { + return new Resources(storage.warehouse, storage.warehouse, storage.warehouse, storage.granary); + } + + getByType(type: ResourceType): number { + switch (type) { + case ResourceType.Lumber: + return this.lumber; + case ResourceType.Clay: + return this.clay; + case ResourceType.Iron: + return this.iron; + case ResourceType.Crop: + return this.crop; + } + } + + asList(): ResourceList { + const result: ResourceList = []; + for (let mp of ResourceMapping) { + result.push({ num: mp.num, type: mp.type, value: this.getByType(mp.type) }); + } + return result; + } + + scale(n: number): Resources { + return new Resources(this.lumber * n, this.clay * n, this.iron * n, this.crop * n); + } + + add(other: ResourcesInterface): Resources { + return new Resources( + this.lumber + other.lumber, + this.clay + other.clay, + this.iron + other.iron, + this.crop + other.crop + ); + } + + sub(other: ResourcesInterface): Resources { + return new Resources( + this.lumber - other.lumber, + this.clay - other.clay, + this.iron - other.iron, + this.crop - other.crop + ); + } + + lt(other: Resources): boolean { + return this.lumber < other.lumber && this.clay < other.clay && this.iron < other.iron && this.crop < other.crop; + } + + gt(other: Resources): boolean { + return this.lumber > other.lumber && this.clay > other.clay && this.iron > other.iron && this.crop > other.crop; + } + + lte(other: Resources): boolean { + return !this.gt(other); + } + + gte(other: Resources): boolean { + return !this.lt(other); + } +} diff --git a/src/Game.ts b/src/Game.ts index 2de847e..f2d28dc 100644 --- a/src/Game.ts +++ b/src/Game.ts @@ -1,115 +1,4 @@ -export enum ResourceType { - Lumber = 1, - Clay = 2, - Iron = 3, - Crop = 4, -} - -export const ResourceMapping: ReadonlyArray<{ num: number; type: ResourceType }> = [ - { num: 1, type: ResourceType.Lumber }, - { num: 2, type: ResourceType.Clay }, - { num: 3, type: ResourceType.Iron }, - { num: 4, type: ResourceType.Crop }, -]; - -export function numberToResourceType(typeAsNumber: number): ResourceType { - for (let mp of ResourceMapping) { - if (typeAsNumber === mp.num) { - return mp.type; - } - } - throw new Error(`Type ${typeAsNumber} in not valid`); -} - -export type ResourceList = Array<{ num: number; type: ResourceType; value: number }>; - -export interface ResourcesInterface { - lumber: number; - clay: number; - iron: number; - crop: number; -} - -export class Resources implements ResourcesInterface { - readonly lumber: number; - readonly clay: number; - readonly iron: number; - readonly crop: number; - - constructor(lumber: number, clay: number, iron: number, crop: number) { - this.lumber = Math.floor(lumber); - this.clay = Math.floor(clay); - this.iron = Math.floor(iron); - this.crop = Math.floor(crop); - } - - static fromObject(obj: ResourcesInterface): Resources { - return new Resources(obj.lumber, obj.clay, obj.iron, obj.crop); - } - - static fromStorage(storage: ResourceStorage): Resources { - return new Resources(storage.warehouse, storage.warehouse, storage.warehouse, storage.granary); - } - - getByType(type: ResourceType): number { - switch (type) { - case ResourceType.Lumber: - return this.lumber; - case ResourceType.Clay: - return this.clay; - case ResourceType.Iron: - return this.iron; - case ResourceType.Crop: - return this.crop; - } - } - - asList(): ResourceList { - const result: ResourceList = []; - for (let mp of ResourceMapping) { - result.push({ num: mp.num, type: mp.type, value: this.getByType(mp.type) }); - } - return result; - } - - scale(n: number): Resources { - return new Resources(this.lumber * n, this.clay * n, this.iron * n, this.crop * n); - } - - add(other: ResourcesInterface): Resources { - return new Resources( - this.lumber + other.lumber, - this.clay + other.clay, - this.iron + other.iron, - this.crop + other.crop - ); - } - - sub(other: ResourcesInterface): Resources { - return new Resources( - this.lumber - other.lumber, - this.clay - other.clay, - this.iron - other.iron, - this.crop - other.crop - ); - } - - lt(other: Resources): boolean { - return this.lumber < other.lumber && this.clay < other.clay && this.iron < other.iron && this.crop < other.crop; - } - - gt(other: Resources): boolean { - return this.lumber > other.lumber && this.clay > other.clay && this.iron > other.iron && this.crop > other.crop; - } - - lte(other: Resources): boolean { - return !this.gt(other); - } - - gte(other: Resources): boolean { - return !this.lt(other); - } -} +import { ResourceType } from './Core/ResourceType'; export class ResourceStorage { readonly warehouse: number; diff --git a/src/Page/BuildingPage.ts b/src/Page/BuildingPage.ts index e2a1c5e..bfb4ab3 100644 --- a/src/Page/BuildingPage.ts +++ b/src/Page/BuildingPage.ts @@ -1,8 +1,6 @@ import { GrabError } from '../Errors'; -import { elClassId, getNumber, split, trimPrefix, uniqId } from '../utils'; -import { Resources } from '../Game'; -import { grabActiveVillageId } from './VillageBlock'; -import { TrainTroopTask } from '../Task/TrainTroopTask'; +import { elClassId, getNumber, trimPrefix, uniqId } from '../utils'; +import { Resources } from '../Core/Resources'; export function clickBuildButton(typeId: number) { const section = jQuery(`#contract_building${typeId}`); diff --git a/src/Page/BuildingPageController.ts b/src/Page/BuildingPageController.ts index 28f2de6..916a7cb 100644 --- a/src/Page/BuildingPageController.ts +++ b/src/Page/BuildingPageController.ts @@ -6,7 +6,7 @@ import { grabActiveVillageId } from './VillageBlock'; import { ConsoleLogger } from '../Logger'; import { createBuildButton, createTrainTroopButtons, createUpgradeButton } from './BuildingPage'; import { BuildBuildingTask } from '../Task/BuildBuildingTask'; -import { Resources } from '../Game'; +import { Resources } from '../Core/Resources'; const QUARTERS_ID = 19; const HORSE_STABLE_ID = 20; diff --git a/src/Page/HeroPage.ts b/src/Page/HeroPage.ts index f51c0ee..062c4ea 100644 --- a/src/Page/HeroPage.ts +++ b/src/Page/HeroPage.ts @@ -1,6 +1,7 @@ -import { ActionError, GrabError } from '../Errors'; -import { HeroAllResources, HeroAttributes, HeroResourceType, ResourceMapping, ResourceType } from '../Game'; +import { GrabError } from '../Errors'; +import { HeroAllResources, HeroAttributes, HeroResourceType } from '../Game'; import { getNumber } from '../utils'; +import { ResourceMapping, ResourceType } from '../Core/ResourceType'; export function grabHeroAttributes(): HeroAttributes { const healthElement = jQuery('#attributes .attribute.health .powervalue .value'); diff --git a/src/Page/ResourcesBlock.ts b/src/Page/ResourcesBlock.ts index 59c3f25..57eb526 100644 --- a/src/Page/ResourcesBlock.ts +++ b/src/Page/ResourcesBlock.ts @@ -1,6 +1,8 @@ -import { Resources, ResourceStorage, ResourceType } from '../Game'; +import { ResourceStorage } from '../Game'; import { GrabError } from '../Errors'; import { getNumber } from '../utils'; +import { Resources } from '../Core/Resources'; +import { ResourceType } from '../Core/ResourceType'; export function grabResources(): Resources { const lumber = grabResource(ResourceType.Lumber); diff --git a/src/Page/SlotBlock.ts b/src/Page/SlotBlock.ts index 701323d..53efb2b 100644 --- a/src/Page/SlotBlock.ts +++ b/src/Page/SlotBlock.ts @@ -1,5 +1,6 @@ import { elClassId, getNumber } from '../utils'; -import { numberToResourceType, ResourceDeposit } from '../Game'; +import { ResourceDeposit } from '../Game'; +import { numberToResourceType } from '../Core/ResourceType'; interface Slot { el: HTMLElement; diff --git a/src/Page/VillageBlock.ts b/src/Page/VillageBlock.ts index 6f7f3bb..9ef3114 100644 --- a/src/Page/VillageBlock.ts +++ b/src/Page/VillageBlock.ts @@ -1,6 +1,7 @@ -import { BuildingQueueInfo, Coordinates, Resources, Village, VillageList } from '../Game'; +import { BuildingQueueInfo, Coordinates, Village, VillageList } from '../Game'; import { GrabError } from '../Errors'; import { getNumber, parseLocation } from '../utils'; +import { Resources } from '../Core/Resources'; function getVillageListItems() { const $elements = jQuery('#sidebarBoxVillagelist ul li a'); diff --git a/src/Scheduler.ts b/src/Scheduler.ts index 50283fa..3c68ab6 100644 --- a/src/Scheduler.ts +++ b/src/Scheduler.ts @@ -8,9 +8,9 @@ import { ConsoleLogger, Logger } from './Logger'; import { BuildBuildingTask } from './Task/BuildBuildingTask'; import { GrabVillageState } from './Task/GrabVillageState'; import { ActionQueue, ImmutableActionList } from './Queue/ActionQueue'; -import { Resources, ResourcesInterface } from './Game'; import { UpdateResourceContracts } from './Task/UpdateResourceContracts'; import { TrainTroopTask } from './Task/TrainTroopTask'; +import { Resources, ResourcesInterface } from './Core/Resources'; export class Scheduler { private taskQueue: TaskQueue; diff --git a/src/State/VillageState.ts b/src/State/VillageState.ts index fb5f4fb..2457203 100644 --- a/src/State/VillageState.ts +++ b/src/State/VillageState.ts @@ -1,5 +1,6 @@ import { DataStorage } from '../DataStorage'; -import { BuildingQueueInfo, Resources, ResourceStorage } from '../Game'; +import { BuildingQueueInfo, ResourceStorage } from '../Game'; +import { Resources } from '../Core/Resources'; const RESOURCES_KEY = 'res'; const CAPACITY_KEY = 'cap'; diff --git a/tests/Core/HeroBalanceTest.ts b/tests/Core/HeroBalanceTest.ts index ed97943..035a16d 100644 --- a/tests/Core/HeroBalanceTest.ts +++ b/tests/Core/HeroBalanceTest.ts @@ -1,8 +1,10 @@ import { it, describe } from 'mocha'; import { expect } from 'chai'; -import { Resources, ResourceStorage, ResourceType } from '../../src/Game'; -import { Core } from '../../src/Core/HeroBalance'; +import { ResourceStorage } from '../../src/Game'; +import { calcHeroResource } from '../../src/Core/HeroBalance'; +import { Resources } from '../../src/Core/Resources'; +import { ResourceType } from '../../src/Core/ResourceType'; describe('HeroBalance', function() { it('Get resource for requirement', function() { @@ -10,7 +12,7 @@ describe('HeroBalance', function() { const required = new Resources(200, 200, 400, 300); const totalRequired = new Resources(200, 200, 400, 300); const storage = new ResourceStorage(1000, 1000); - const heroRes = Core.calcHeroResource(current, required, totalRequired, storage); + const heroRes = calcHeroResource(current, required, totalRequired, storage); expect(ResourceType.Iron).to.equals(heroRes); }); @@ -19,7 +21,7 @@ describe('HeroBalance', function() { const required = new Resources(200, 200, 400, 300); const totalRequired = new Resources(200, 200, 400, 300); const storage = new ResourceStorage(1000, 1000); - const heroRes = Core.calcHeroResource(current, required, totalRequired, storage); + const heroRes = calcHeroResource(current, required, totalRequired, storage); expect(ResourceType.Iron).to.equals(heroRes); }); @@ -28,7 +30,7 @@ describe('HeroBalance', function() { const required = new Resources(400, 400, 400, 300); const totalRequired = new Resources(400, 400, 400, 300); const storage = new ResourceStorage(1000, 1000); - const heroRes = Core.calcHeroResource(current, required, totalRequired, storage); + const heroRes = calcHeroResource(current, required, totalRequired, storage); expect(ResourceType.Lumber).to.equals(heroRes); }); @@ -37,7 +39,7 @@ describe('HeroBalance', function() { const required = new Resources(100, 100, 100, 100); const totalRequired = new Resources(100, 100, 100, 100); const storage = new ResourceStorage(1000, 1000); - const heroRes = Core.calcHeroResource(current, required, totalRequired, storage); + const heroRes = calcHeroResource(current, required, totalRequired, storage); expect(ResourceType.Iron).to.equals(heroRes); }); });