From 1b053de16af9ca9993d574a68c9abe54ac853041 Mon Sep 17 00:00:00 2001 From: Anton Vakhrushev Date: Mon, 12 Oct 2020 10:00:06 +0300 Subject: [PATCH] Refactoring: plan actions as classes --- src/Plan/CropBuildingPlan.ts | 62 +++++++++++++++ src/Plan/WarehouseBuildingPlan.ts | 70 +++++++++++++++++ src/Queue/Args.ts | 1 + src/Village/VillageController.ts | 125 +++++------------------------- 4 files changed, 154 insertions(+), 104 deletions(-) create mode 100644 src/Plan/CropBuildingPlan.ts create mode 100644 src/Plan/WarehouseBuildingPlan.ts diff --git a/src/Plan/CropBuildingPlan.ts b/src/Plan/CropBuildingPlan.ts new file mode 100644 index 0000000..efe2921 --- /dev/null +++ b/src/Plan/CropBuildingPlan.ts @@ -0,0 +1,62 @@ +import { ConstructionPlan } from '../Village/VillageController'; +import { ResourceType } from '../Core/ResourceType'; +import { isBuildingPlanned } from '../Queue/Task'; +import { UpgradeBuildingTask } from '../Handler/Task/UpgradeBuildingTask'; +import { first } from '../Helpers/Collection'; +import { VillageState } from '../Village/VillageState'; +import { VillageTaskCollection } from '../Village/VillageTaskCollection'; +import { VillageStorage } from '../Storage/VillageStorage'; + +export class CropBuildingPlan implements ConstructionPlan { + constructor( + private readonly state: VillageState, + private readonly storage: VillageStorage, + private readonly taskCollection: VillageTaskCollection + ) {} + + execute() { + const performance = this.state.performance; + if (performance.crop >= 30) { + return; + } + + const resourceSlots = this.storage.getResourceSlots(); + const tasks = this.state.tasks; + + const cropSlots = resourceSlots.filter( + (s) => s.type === ResourceType.Crop && !s.isMaxLevel + ); + if (cropSlots.length === 0) { + return; + } + + // Check, if crop field is building now + const underContraction = cropSlots.find((s) => s.isUnderConstruction); + if (underContraction !== undefined) { + return; + } + + // Check, if we already have crop task in queue + const cropBuildIds = cropSlots.map((s) => s.buildId); + for (let buildId of cropBuildIds) { + const upgradeTask = tasks.find( + isBuildingPlanned(UpgradeBuildingTask.name, buildId, undefined) + ); + if (upgradeTask !== undefined) { + return; + } + } + + // Find ready for building slots and sort them by level + cropSlots.sort((s1, s2) => s1.level - s2.level); + + const targetCropBuildId = first(cropSlots)?.buildId; + if (!targetCropBuildId) { + return; + } + + this.taskCollection.addTaskAsFirst(UpgradeBuildingTask.name, { + buildId: targetCropBuildId, + }); + } +} diff --git a/src/Plan/WarehouseBuildingPlan.ts b/src/Plan/WarehouseBuildingPlan.ts new file mode 100644 index 0000000..fe3aa04 --- /dev/null +++ b/src/Plan/WarehouseBuildingPlan.ts @@ -0,0 +1,70 @@ +import { ConstructionPlan } from '../Village/VillageController'; +import { isBuildingPlanned } from '../Queue/Task'; +import { UpgradeBuildingTask } from '../Handler/Task/UpgradeBuildingTask'; +import { first } from '../Helpers/Collection'; +import { TaskState, VillageState } from '../Village/VillageState'; +import { VillageTaskCollection } from '../Village/VillageTaskCollection'; +import { VillageStorage } from '../Storage/VillageStorage'; +import { BuildingSlot } from '../Core/Slot'; + +export class WarehouseBuildingPlan implements ConstructionPlan { + constructor( + private readonly buildTypeId: number, + private readonly checkNeedEnlargeFunc: (task: TaskState) => boolean, + private readonly state: VillageState, + private readonly storage: VillageStorage, + private readonly taskCollection: VillageTaskCollection + ) {} + + execute() { + const storageSlots = this.findStorageSlots(); + if (storageSlots.length === 0) { + return; + } + + // Check, if warehouse is building now + const underConstructionSlot = storageSlots.find((s) => s.isUnderConstruction); + if (underConstructionSlot !== undefined) { + return; + } + + if (this.isWarehouseInBuildingQueue(storageSlots)) { + return; + } + + const needStorageEnlargeTasks = this.state.tasks.filter(this.checkNeedEnlargeFunc); + if (needStorageEnlargeTasks.length === 0) { + return; + } + + const firstSlot = first(storageSlots); + if (firstSlot) { + this.taskCollection.addTask(UpgradeBuildingTask.name, { + buildId: firstSlot.buildId, + buildTypeId: this.buildTypeId, + }); + } + } + + private findStorageSlots() { + const buildingSlots = this.storage.getBuildingSlots(); + + return buildingSlots.filter( + (slot) => slot.buildTypeId === this.buildTypeId && !slot.isMaxLevel + ); + } + + private isWarehouseInBuildingQueue(storageSlots: ReadonlyArray): boolean { + const storageBuildIds = storageSlots.map((slot) => slot.buildId); + for (let buildId of storageBuildIds) { + const upgradeTask = this.state.tasks.find( + isBuildingPlanned(UpgradeBuildingTask.name, buildId, this.buildTypeId) + ); + if (upgradeTask !== undefined) { + return true; + } + } + + return false; + } +} diff --git a/src/Queue/Args.ts b/src/Queue/Args.ts index 30e3fc5..0fde1da 100644 --- a/src/Queue/Args.ts +++ b/src/Queue/Args.ts @@ -15,6 +15,7 @@ export interface Args { troopId?: number; troopResources?: ResourcesInterface; trainCount?: number; + count?: number; resources?: ResourcesInterface; coordinates?: CoordinatesInterface; unitId?: number; diff --git a/src/Village/VillageController.ts b/src/Village/VillageController.ts index 91d7826..3bb4c2c 100644 --- a/src/Village/VillageController.ts +++ b/src/Village/VillageController.ts @@ -5,12 +5,14 @@ import { Resources } from '../Core/Resources'; import { MerchantsInfo } from '../Core/Market'; import { VillageStorage } from '../Storage/VillageStorage'; import { ReceiveResourcesMode } from '../Core/Village'; -import { ResourceType } from '../Core/ResourceType'; -import { UpgradeBuildingTask } from '../Handler/Task/UpgradeBuildingTask'; import { GARNER_ID, WAREHOUSE_ID } from '../Core/Buildings'; -import { first } from '../Helpers/Collection'; -import { isBuildingPlanned } from '../Queue/Task'; import { TaskId } from '../Queue/TaskId'; +import { CropBuildingPlan } from '../Plan/CropBuildingPlan'; +import { WarehouseBuildingPlan } from '../Plan/WarehouseBuildingPlan'; + +export interface ConstructionPlan { + execute(): void; +} export class VillageController { private readonly villageId: number; @@ -157,105 +159,20 @@ export class VillageController { if (this.state.tasks.length >= 100) { return; } - this.planCropBuilding(); - this.planWarehouseBuilding(); - this.planGranaryBuilding(); - } - - private planCropBuilding() { - const performance = this.state.performance; - if (performance.crop >= 30) { - return; - } - - const resourceSlots = this.storage.getResourceSlots(); - const tasks = this.taskCollection.getTasks(); - - const cropSlots = resourceSlots.filter( - (s) => s.type === ResourceType.Crop && !s.isMaxLevel - ); - if (cropSlots.length === 0) { - return; - } - - // Check, if crop field is building now - const underContraction = cropSlots.find((s) => s.isUnderConstruction); - if (underContraction !== undefined) { - return; - } - - // Check, if we already have crop task in queue - const cropBuildIds = cropSlots.map((s) => s.buildId); - for (let buildId of cropBuildIds) { - const upgradeTask = tasks.find( - isBuildingPlanned(UpgradeBuildingTask.name, buildId, undefined) - ); - if (upgradeTask !== undefined) { - return; - } - } - - // Find ready for building slots and sort them by level - cropSlots.sort((s1, s2) => s1.level - s2.level); - - const targetCropBuildId = first(cropSlots)?.buildId; - if (!targetCropBuildId) { - return; - } - - this.taskCollection.addTaskAsFirst(UpgradeBuildingTask.name, { - buildId: targetCropBuildId, - }); - } - - private planWarehouseBuilding(): void { - this.planStorageBuilding(WAREHOUSE_ID, (t) => !t.isEnoughWarehouseCapacity); - } - - private planGranaryBuilding(): void { - this.planStorageBuilding(GARNER_ID, (t) => !t.isEnoughGranaryCapacity); - } - - private planStorageBuilding( - buildTypeId: number, - checkNeedEnlargeFunc: (task: TaskState) => boolean - ): void { - const buildingSlots = this.storage.getBuildingSlots(); - - const storageSlots = buildingSlots.filter( - (s) => s.buildTypeId === buildTypeId && !s.isMaxLevel - ); - if (storageSlots.length === 0) { - return; - } - - // Check, if warehouse is building now - const underConstruction = storageSlots.find((s) => s.isUnderConstruction); - if (underConstruction !== undefined) { - return; - } - - const tasks = this.state.tasks; - - // Check, if we have warehouse is in building queue - const storageBuildIds = storageSlots.map((s) => s.buildId); - for (let buildId of storageBuildIds) { - const upgradeTask = tasks.find( - isBuildingPlanned(UpgradeBuildingTask.name, buildId, buildTypeId) - ); - if (upgradeTask !== undefined) { - return; - } - } - - const needStorageEnlargeTasks = tasks.filter(checkNeedEnlargeFunc); - if (needStorageEnlargeTasks.length === 0) { - return; - } - - const firstSlot = first(storageSlots); - if (firstSlot) { - this.addTask(UpgradeBuildingTask.name, { buildId: firstSlot.buildId, buildTypeId }); - } + new CropBuildingPlan(this.state, this.storage, this.taskCollection).execute(); + new WarehouseBuildingPlan( + WAREHOUSE_ID, + (t) => !t.isEnoughWarehouseCapacity, + this.state, + this.storage, + this.taskCollection + ).execute(); + new WarehouseBuildingPlan( + GARNER_ID, + (t) => !t.isEnoughGranaryCapacity, + this.state, + this.storage, + this.taskCollection + ).execute(); } }