Move first task calculation to state

This commit is contained in:
Anton Vakhrushev 2020-06-06 21:39:35 +03:00
parent 2622d0cc6e
commit 277a338164
4 changed files with 68 additions and 58 deletions

View File

@ -68,6 +68,9 @@
<resource-line <resource-line
v-if="villageState.required.active" v-if="villageState.required.active"
:title="'След. задача:'" :title="'След. задача:'"
:color="false"
:sign="false"
:hide-zero="false"
:resources="villageState.required.resources" :resources="villageState.required.resources"
/> />

View File

@ -35,7 +35,7 @@ export class VillageController {
} }
getReadyProductionTask(): Task | undefined { getReadyProductionTask(): Task | undefined {
return this.taskCollection.getReadyForProductionTask(); return this.state.firstReadyTask;
} }
addTask(name: string, args: Args) { addTask(name: string, args: Args) {

View File

@ -4,10 +4,11 @@ import { VillageStorage } from './Storage/VillageStorage';
import { calcGatheringTimings, GatheringTime } from './Core/GatheringTimings'; import { calcGatheringTimings, GatheringTime } from './Core/GatheringTimings';
import { VillageRepositoryInterface } from './VillageRepository'; import { VillageRepositoryInterface } from './VillageRepository';
import { VillageNotFound } from './Errors'; import { VillageNotFound } from './Errors';
import { ProductionQueue, OrderedProductionQueues } from './Core/ProductionQueue'; import { ProductionQueue } from './Core/ProductionQueue';
import { Task } from './Queue/TaskProvider'; import { Task } from './Queue/TaskProvider';
import { timestamp } from './utils'; import { timestamp } from './utils';
import { VillageTaskCollection } from './VillageTaskCollection'; import { QueueTasks, VillageTaskCollection } from './VillageTaskCollection';
import { TrainTroopTask } from './Task/TrainTroopTask';
interface VillageStorageState { interface VillageStorageState {
resources: Resources; resources: Resources;
@ -42,6 +43,7 @@ interface ResourceLineState {
interface VillageProductionQueueState { interface VillageProductionQueueState {
queue: ProductionQueue; queue: ProductionQueue;
tasks: Array<Task>;
isActive: boolean; isActive: boolean;
currentTaskFinishTimestamp: number; currentTaskFinishTimestamp: number;
currentTaskFinishSeconds: number; currentTaskFinishSeconds: number;
@ -50,6 +52,10 @@ interface VillageProductionQueueState {
taskCount: number; taskCount: number;
} }
interface VillageProductionQueueStateDict {
[queue: string]: VillageProductionQueueState;
}
interface VillageOwnState { interface VillageOwnState {
/** /**
* Village id * Village id
@ -68,6 +74,8 @@ interface VillageOwnState {
upperCriticalLevel: Resources; upperCriticalLevel: Resources;
storageOptimumFullness: Resources; storageOptimumFullness: Resources;
isOverflowing: boolean; isOverflowing: boolean;
queues: VillageProductionQueueStateDict;
firstReadyTask: Task | undefined;
/** /**
* Required resources for nearest task * Required resources for nearest task
*/ */
@ -82,7 +90,6 @@ interface VillageOwnState {
totalRequired: ResourceLineState; totalRequired: ResourceLineState;
incomingResources: Resources; incomingResources: Resources;
settings: VillageSettings; settings: VillageSettings;
queues: { [queue: string]: VillageProductionQueueState | undefined };
} }
interface VillageOwnStateDictionary { interface VillageOwnStateDictionary {
@ -96,7 +103,7 @@ export interface VillageState extends VillageOwnState {
commitments: Resources; commitments: Resources;
} }
function calcResourceBalance( function makeResourceBalance(
resources: Resources, resources: Resources,
current: Resources, current: Resources,
performance: Resources performance: Resources
@ -109,7 +116,7 @@ function calcResourceBalance(
}; };
} }
function calcStorageBalance( function makeStorageBalance(
resources: Resources, resources: Resources,
storage: Resources, storage: Resources,
performance: Resources performance: Resources
@ -153,28 +160,29 @@ function taskResourceReducer(resources: Resources, task: Task) {
} }
function createProductionQueueState( function createProductionQueueState(
queue: ProductionQueue, taskQueueInfo: QueueTasks,
storage: VillageStorage, storage: VillageStorage
taskCollection: VillageTaskCollection
): VillageProductionQueueState { ): VillageProductionQueueState {
const queue = taskQueueInfo.queue;
const tasks = taskQueueInfo.tasks;
const resources = storage.getResources(); const resources = storage.getResources();
const performance = storage.getResourcesPerformance(); const performance = storage.getResourcesPerformance();
const tasks = taskCollection.getTasksInProductionQueue(queue);
const firstTaskResources = tasks.slice(0, 1).reduce(taskResourceReducer, Resources.zero()); const firstTaskResources = tasks.slice(0, 1).reduce(taskResourceReducer, Resources.zero());
const allTaskResources = tasks.reduce(taskResourceReducer, Resources.zero()); const allTaskResources = tasks.reduce(taskResourceReducer, Resources.zero());
const taskEndingTimestamp = storage.getQueueTaskEnding(queue); const taskEndingTimestamp = taskQueueInfo.finishTs;
return { return {
queue, queue,
tasks,
isActive: tasks.length !== 0 || taskEndingTimestamp > timestamp(), isActive: tasks.length !== 0 || taskEndingTimestamp > timestamp(),
currentTaskFinishTimestamp: taskEndingTimestamp, currentTaskFinishTimestamp: taskEndingTimestamp,
currentTaskFinishSeconds: Math.max( currentTaskFinishSeconds: Math.max(
taskEndingTimestamp ? taskEndingTimestamp - timestamp() : 0, taskEndingTimestamp ? taskEndingTimestamp - timestamp() : 0,
0 0
), ),
firstTask: calcResourceBalance(firstTaskResources, resources, performance), firstTask: makeResourceBalance(firstTaskResources, resources, performance),
allTasks: calcResourceBalance(allTaskResources, resources, performance), allTasks: makeResourceBalance(allTaskResources, resources, performance),
taskCount: tasks.length, taskCount: tasks.length,
}; };
} }
@ -183,25 +191,54 @@ function createAllProductionQueueStates(
storage: VillageStorage, storage: VillageStorage,
taskCollection: VillageTaskCollection taskCollection: VillageTaskCollection
) { ) {
let result: { [queue: string]: VillageProductionQueueState } = {}; let result: VillageProductionQueueStateDict = {};
for (let queue of OrderedProductionQueues) { for (let taskQueueInfo of taskCollection.getQueueGroupedTasks()) {
result[queue] = createProductionQueueState(queue, storage, taskCollection); result[taskQueueInfo.queue] = createProductionQueueState(taskQueueInfo, storage);
} }
return result; return result;
} }
function getReadyForProductionTask(
queues: VillageProductionQueueStateDict,
maxResourcesForTask: Resources
): Task | undefined {
const nowTs = timestamp();
const firstReadyGroup = Object.values(queues).find(
group => group.currentTaskFinishTimestamp <= nowTs && group.tasks.length !== 0
);
if (!firstReadyGroup) {
return undefined;
}
return firstReadyGroup.tasks.find(
t =>
t.name === TrainTroopTask.name ||
!t.args.resources ||
maxResourcesForTask.allGreaterOrEqual(Resources.fromObject(t.args.resources))
);
}
function getReadyTaskRequiredResources(task: Task | undefined): Resources {
if (task && task.args.resources) {
return Resources.fromObject(task.args.resources);
}
return Resources.zero();
}
function createVillageOwnState( function createVillageOwnState(
village: Village, village: Village,
storage: VillageStorage, storage: VillageStorage,
taskCollection: VillageTaskCollection taskCollection: VillageTaskCollection
): VillageOwnState { ): VillageOwnState {
const resources = storage.getResources(); const resources = storage.getResources();
const resourceStorage = storage.getResourceStorage(); const storageResources = Resources.fromStorage(storage.getResourceStorage());
const performance = storage.getResourcesPerformance(); const performance = storage.getResourcesPerformance();
const upperCriticalLevel = Resources.fromStorage(resourceStorage).sub(performance.scale(1)); const upperCriticalLevel = storageResources.sub(performance.scale(1));
const storageOptimumFullness = Resources.fromStorage(resourceStorage).sub(performance.scale(3)); const storageOptimumFullness = storageResources.sub(performance.scale(3));
const isOverflowing = upperCriticalLevel.anyLower(resources); const isOverflowing = upperCriticalLevel.anyLower(resources);
const requiredResources = taskCollection.getReadyTaskRequiredResources(); const queues = createAllProductionQueueStates(storage, taskCollection);
const firstReadyTask = getReadyForProductionTask(queues, storageOptimumFullness);
const requiredResources = getReadyTaskRequiredResources(firstReadyTask);
const frontierResources = taskCollection.getFrontierResources(); const frontierResources = taskCollection.getFrontierResources();
const totalRequiredResources = taskCollection.getAllTasksRequiredResources(); const totalRequiredResources = taskCollection.getAllTasksRequiredResources();
@ -210,16 +247,17 @@ function createVillageOwnState(
village, village,
resources, resources,
performance, performance,
storage: calcStorageBalance(resources, Resources.fromStorage(resourceStorage), performance), storage: makeStorageBalance(resources, storageResources, performance),
required: calcResourceBalance(requiredResources, resources, performance), required: makeResourceBalance(requiredResources, resources, performance),
upperCriticalLevel, upperCriticalLevel,
storageOptimumFullness, storageOptimumFullness,
isOverflowing, isOverflowing,
frontierRequired: calcResourceBalance(frontierResources, resources, performance), queues,
totalRequired: calcResourceBalance(totalRequiredResources, resources, performance), firstReadyTask,
frontierRequired: makeResourceBalance(frontierResources, resources, performance),
totalRequired: makeResourceBalance(totalRequiredResources, resources, performance),
incomingResources: calcIncomingResources(storage), incomingResources: calcIncomingResources(storage),
settings: storage.getSettings(), settings: storage.getSettings(),
queues: createAllProductionQueueStates(storage, taskCollection),
}; };
} }

View File

@ -8,9 +8,8 @@ import { ContractAttributes, ContractType } from './Core/Contract';
import { UpgradeBuildingTask } from './Task/UpgradeBuildingTask'; import { UpgradeBuildingTask } from './Task/UpgradeBuildingTask';
import { ForgeImprovementTask } from './Task/ForgeImprovementTask'; import { ForgeImprovementTask } from './Task/ForgeImprovementTask';
import * as _ from 'underscore'; import * as _ from 'underscore';
import { TrainTroopTask } from './Task/TrainTroopTask';
interface QueueTasks { export interface QueueTasks {
queue: ProductionQueue; queue: ProductionQueue;
tasks: Array<Task>; tasks: Array<Task>;
finishTs: number; finishTs: number;
@ -61,7 +60,7 @@ export class VillageTaskCollection {
this.removeTasks(t => t.id === taskId); this.removeTasks(t => t.id === taskId);
} }
private getQueueGroupedTasks(): Array<QueueTasks> { getQueueGroupedTasks(): Array<QueueTasks> {
const tasks = this.storage.getTasks(); const tasks = this.storage.getTasks();
const result: Array<QueueTasks> = []; const result: Array<QueueTasks> = [];
for (let queue of OrderedProductionQueues) { for (let queue of OrderedProductionQueues) {
@ -74,28 +73,6 @@ export class VillageTaskCollection {
return result; return result;
} }
getTasksInProductionQueue(queue: ProductionQueue): Array<Task> {
return this.storage.getTasks().filter(isInQueue(queue));
}
getReadyForProductionTask(): Task | undefined {
const groups = this.getQueueGroupedTasks();
const nowTs = timestamp();
const firstReadyGroup = groups.find(g => g.finishTs <= nowTs && g.tasks.length !== 0);
if (!firstReadyGroup) {
return undefined;
}
const maxCapacity = Resources.fromStorage(this.storage.getResourceStorage());
return firstReadyGroup.tasks.find(
t =>
t.name === TrainTroopTask.name ||
!t.args.resources ||
maxCapacity.allGreaterOrEqual(Resources.fromObject(t.args.resources))
);
}
postponeTask(taskId: TaskId, seconds: number) { postponeTask(taskId: TaskId, seconds: number) {
const modifyTime = withTime(timestamp() + seconds); const modifyTime = withTime(timestamp() + seconds);
this.modifyTasks(task => task.id === taskId, modifyTime); this.modifyTasks(task => task.id === taskId, modifyTime);
@ -116,14 +93,6 @@ export class VillageTaskCollection {
} }
} }
getReadyTaskRequiredResources(): Resources {
const first = this.getReadyForProductionTask();
if (first && first.args.resources) {
return Resources.fromObject(first.args.resources);
}
return Resources.zero();
}
getFrontierResources(): Resources { getFrontierResources(): Resources {
let result = Resources.zero(); let result = Resources.zero();
const groups = this.getQueueGroupedTasks(); const groups = this.getQueueGroupedTasks();