Improve send resources task
This commit is contained in:
		| @@ -1,27 +1,30 @@ | ||||
| import { ActionController, taskError, registerAction } from './ActionController'; | ||||
| import { AbortTaskError, TryLaterError } from '../Errors'; | ||||
| import { TryLaterError } from '../Errors'; | ||||
| import { Resources } from '../Core/Resources'; | ||||
| import { Coordinates, Village } from '../Core/Village'; | ||||
| import { grabVillageResources } from '../Page/ResourcesBlock'; | ||||
| import { grabActiveVillageId, grabVillageList } from '../Page/VillageBlock'; | ||||
| import { Coordinates } from '../Core/Village'; | ||||
| import { aroundMinutes, timestamp } from '../utils'; | ||||
| import { VillageStorage } from '../Storage/VillageStorage'; | ||||
| import { Args } from '../Queue/Args'; | ||||
| import { Task } from '../Queue/TaskProvider'; | ||||
| import { clickSendButton, fillSendResourcesForm, grabMerchantsInfo } from '../Page/BuildingPage/MarketPage'; | ||||
| import { VillageState } from '../VillageState'; | ||||
|  | ||||
| const TIMEOUT = 15; | ||||
| const AMOUNT_THRESHOLD = 100; | ||||
|  | ||||
| @registerAction | ||||
| export class SendResourcesAction extends ActionController { | ||||
|     async run(args: Args, task: Task): Promise<any> { | ||||
|         this.ensureSameVillage(args, task); | ||||
|  | ||||
|         const senderVillageId = args.villageId || taskError('No source village id'); | ||||
|         const targetVillageId = args.targetVillageId || taskError('No target village id'); | ||||
|  | ||||
|         const coordinates = Coordinates.fromObject(args.coordinates || taskError('No coordinates')); | ||||
|  | ||||
|         const recipientVillage = args.targetVillageId | ||||
|             ? this.findRecipientVillageById(args.targetVillageId) | ||||
|             : this.findRecipientVillage(coordinates); | ||||
|         const senderVillage = this.villageStateRepository.getVillageState(senderVillageId); | ||||
|         const recipientVillage = this.villageStateRepository.getVillageState(targetVillageId); | ||||
|  | ||||
|         const readyToTransfer = this.getResourcesForTransfer(recipientVillage.id); | ||||
|         const readyToTransfer = this.getResourcesForTransfer(senderVillage, recipientVillage); | ||||
|  | ||||
|         console.log('To transfer res', readyToTransfer); | ||||
|  | ||||
| @@ -32,24 +35,6 @@ export class SendResourcesAction extends ActionController { | ||||
|         clickSendButton(); | ||||
|     } | ||||
|  | ||||
|     private findRecipientVillageById(villageId: number): Village { | ||||
|         const villageList = grabVillageList(); | ||||
|         const village = villageList.find(v => v.id === villageId); | ||||
|         if (!village) { | ||||
|             throw new AbortTaskError('No village'); | ||||
|         } | ||||
|         return village; | ||||
|     } | ||||
|  | ||||
|     private findRecipientVillage(coordinates: Coordinates): Village { | ||||
|         const villageList = grabVillageList(); | ||||
|         const village = villageList.find(v => v.crd.eq(coordinates)); | ||||
|         if (!village) { | ||||
|             throw new AbortTaskError('No village'); | ||||
|         } | ||||
|         return village; | ||||
|     } | ||||
|  | ||||
|     private getMerchantsCapacity(): number { | ||||
|         const merchants = grabMerchantsInfo(); | ||||
|         const capacity = merchants.available * merchants.carry; | ||||
| @@ -59,55 +44,67 @@ export class SendResourcesAction extends ActionController { | ||||
|         return capacity; | ||||
|     } | ||||
|  | ||||
|     private getSenderAvailableResources(): Resources { | ||||
|         const villageId = grabActiveVillageId(); | ||||
|         const resources = grabVillageResources(); | ||||
|         const requirements = this.scheduler.getVillageRequiredResources(villageId); | ||||
|         const free = resources.sub(requirements).max(Resources.zero()); | ||||
|         console.log('Sender res', resources); | ||||
|         console.log('Sender req', requirements); | ||||
|         console.log('Sender free', free); | ||||
|         if (free.amount() < 100) { | ||||
|     private getSenderAvailableResources(senderState: VillageState): Resources { | ||||
|         const balance = senderState.required.balance; | ||||
|         const free = balance.max(Resources.zero()); | ||||
|  | ||||
|         console.table([ | ||||
|             { name: 'Sender balance', ...balance }, | ||||
|             { name: 'Sender free', ...free }, | ||||
|         ]); | ||||
|  | ||||
|         if (free.amount() < AMOUNT_THRESHOLD) { | ||||
|             throw new TryLaterError(aroundMinutes(TIMEOUT), 'Little free resources'); | ||||
|         } | ||||
|         return free; | ||||
|     } | ||||
|  | ||||
|     private getRecipientRequirements(villageId: number): Resources { | ||||
|         const state = new VillageStorage(villageId); | ||||
|         const resources = state.getResources(); | ||||
|         const incoming = state.getIncomingMerchants().reduce((m, i) => m.add(i.resources), Resources.zero()); | ||||
|         const requirements = this.scheduler.getVillageRequiredResources(villageId); | ||||
|         const missing = requirements | ||||
|             .sub(incoming) | ||||
|             .sub(resources) | ||||
|     private getRecipientRequirements(recipientState: VillageState): Resources { | ||||
|         const maxPossibleToStore = recipientState.storage.sub(recipientState.performance); | ||||
|         const currentResources = recipientState.resources; | ||||
|         const incomingResources = recipientState.incomingResources; | ||||
|         const requirementResources = recipientState.required.resources; | ||||
|         const missingResources = requirementResources | ||||
|             .min(maxPossibleToStore) | ||||
|             .sub(incomingResources) | ||||
|             .sub(currentResources) | ||||
|             .max(Resources.zero()); | ||||
|         console.log('Recipient res', resources); | ||||
|         console.log('Recipient incoming', incoming); | ||||
|         console.log('Recipient req', requirements); | ||||
|         console.log('Recipient missing', missing); | ||||
|         if (missing.empty()) { | ||||
|  | ||||
|         console.table([ | ||||
|             { name: 'Recipient max possible', ...maxPossibleToStore }, | ||||
|             { name: 'Recipient resources', ...currentResources }, | ||||
|             { name: 'Recipient incoming', ...incomingResources }, | ||||
|             { name: 'Recipient requirements', ...requirementResources }, | ||||
|             { name: 'Recipient missing', ...missingResources }, | ||||
|         ]); | ||||
|  | ||||
|         if (missingResources.empty()) { | ||||
|             throw new TryLaterError(aroundMinutes(TIMEOUT), 'No missing resources'); | ||||
|         } | ||||
|         return missing; | ||||
|  | ||||
|         return missingResources; | ||||
|     } | ||||
|  | ||||
|     private getResourcesForTransfer(recipientVillageId: number): Resources { | ||||
|         const senderResources = this.getSenderAvailableResources(); | ||||
|         const recipientNeeds = this.getRecipientRequirements(recipientVillageId); | ||||
|         const prepared = senderResources.min(recipientNeeds); | ||||
|         const capacity = this.getMerchantsCapacity(); | ||||
|     private getResourcesForTransfer(senderState: VillageState, recipientState: VillageState): Resources { | ||||
|         const senderReadySendResources = this.getSenderAvailableResources(senderState); | ||||
|         const recipientNeedsResources = this.getRecipientRequirements(recipientState); | ||||
|         const contractResources = senderReadySendResources.min(recipientNeedsResources); | ||||
|         const merchantsCapacity = this.getMerchantsCapacity(); | ||||
|  | ||||
|         let readyToTransfer = prepared; | ||||
|         if (prepared.amount() > capacity) { | ||||
|             readyToTransfer = prepared.scale(capacity / prepared.amount()); | ||||
|         let readyToTransfer = contractResources; | ||||
|         if (contractResources.amount() > merchantsCapacity) { | ||||
|             const merchantScale = merchantsCapacity / contractResources.amount(); | ||||
|             readyToTransfer = contractResources.scale(merchantScale); | ||||
|         } | ||||
|  | ||||
|         console.log('Sender', senderResources); | ||||
|         console.log('Recipient', recipientNeeds); | ||||
|         console.log('Prepared', prepared); | ||||
|         console.log('Capacity', capacity); | ||||
|         console.log('Ready to transfer', readyToTransfer); | ||||
|         console.log('Merchants capacity', merchantsCapacity); | ||||
|  | ||||
|         console.table([ | ||||
|             { name: 'Sender', ...senderReadySendResources }, | ||||
|             { name: 'Recipient', ...recipientNeedsResources }, | ||||
|             { name: 'Prepared', ...contractResources }, | ||||
|             { name: 'Ready to transfer', ...readyToTransfer }, | ||||
|         ]); | ||||
|  | ||||
|         return readyToTransfer; | ||||
|     } | ||||
|   | ||||
| @@ -16,14 +16,32 @@ interface StorageBalance { | ||||
| } | ||||
|  | ||||
| interface RequiredResources { | ||||
|     /** | ||||
|      * Required resources (always positive) | ||||
|      */ | ||||
|     resources: Resources; | ||||
|     /** | ||||
|      * Balance resources (current - required), may be negative | ||||
|      */ | ||||
|     balance: Resources; | ||||
|     /** | ||||
|      * Time to gather all type of resources (slowest time) | ||||
|      */ | ||||
|     time: GatheringTime; | ||||
| } | ||||
|  | ||||
| interface VillageOwnState { | ||||
|     /** | ||||
|      * Village id | ||||
|      */ | ||||
|     id: number; | ||||
|     /** | ||||
|      * Village object | ||||
|      */ | ||||
|     village: Village; | ||||
|     /** | ||||
|      * Current village resources | ||||
|      */ | ||||
|     resources: Resources; | ||||
|     performance: Resources; | ||||
|     storage: Resources; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user