Remove tasks from village task queue state if task can not be build now

This commit is contained in:
Anton Vakhrushev 2020-07-12 18:09:41 +03:00
parent effc1b1626
commit b6d86ee659
3 changed files with 64 additions and 63 deletions

View File

@ -21,6 +21,7 @@ export function uniqTaskId(): TaskId {
} }
export interface TaskCore { export interface TaskCore {
readonly id: TaskId;
readonly name: string; readonly name: string;
readonly args: Args; readonly args: Args;
} }
@ -48,7 +49,7 @@ export interface TaskProvider {
} }
export interface TaskMatcher { export interface TaskMatcher {
(task: Task): boolean; (task: TaskCore): boolean;
} }
export interface TaskTransformer { export interface TaskTransformer {

View File

@ -4,10 +4,10 @@ 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 } from './Core/ProductionQueue'; import { OrderedProductionQueues, ProductionQueue } from './Core/ProductionQueue';
import { Task, TaskId } from './Queue/TaskProvider'; import { isInQueue, TaskCore, TaskId } from './Queue/TaskProvider';
import { timestamp } from './utils'; import { timestamp } from './utils';
import { QueueTasks, VillageTaskCollection } from './VillageTaskCollection'; import { VillageTaskCollection } from './VillageTaskCollection';
import { TrainTroopTask } from './Task/TrainTroopTask'; import { TrainTroopTask } from './Task/TrainTroopTask';
import { Args } from './Queue/Args'; import { Args } from './Queue/Args';
@ -20,7 +20,13 @@ export interface TaskState {
canBeBuilt: boolean; canBeBuilt: boolean;
} }
interface VillageStorageState { export interface TaskQueueState {
queue: ProductionQueue;
tasks: ReadonlyArray<TaskState>;
finishTs: number;
}
interface VillageWarehouseState {
resources: Resources; resources: Resources;
capacity: Resources; capacity: Resources;
balance: Resources; balance: Resources;
@ -56,7 +62,7 @@ interface ResourceLineState {
interface VillageProductionQueueState { interface VillageProductionQueueState {
queue: ProductionQueue; queue: ProductionQueue;
tasks: Array<TaskState>; tasks: ReadonlyArray<TaskState>;
isActive: boolean; isActive: boolean;
isWaiting: boolean; isWaiting: boolean;
currentTaskFinishTimestamp: number; currentTaskFinishTimestamp: number;
@ -80,7 +86,7 @@ interface VillageOwnState {
*/ */
resources: Resources; resources: Resources;
performance: Resources; performance: Resources;
storage: VillageStorageState; storage: VillageWarehouseState;
queues: Array<VillageProductionQueueState>; queues: Array<VillageProductionQueueState>;
tasks: Array<TaskState>; tasks: Array<TaskState>;
firstReadyTask: TaskState | undefined; firstReadyTask: TaskState | undefined;
@ -120,7 +126,7 @@ function makeStorageState(
resources: Resources, resources: Resources,
storage: Resources, storage: Resources,
performance: Resources performance: Resources
): VillageStorageState { ): VillageWarehouseState {
const optimumFullness = storage.sub(performance.scale(3)); const optimumFullness = storage.sub(performance.scale(3));
const criticalFullness = storage.sub(performance.scale(1)); const criticalFullness = storage.sub(performance.scale(1));
return { return {
@ -158,19 +164,13 @@ function calcIncomingResources(storage: VillageStorage): Resources {
return storage.getIncomingMerchants().reduce((m, i) => m.add(i.resources), Resources.zero()); return storage.getIncomingMerchants().reduce((m, i) => m.add(i.resources), Resources.zero());
} }
function taskResourceReducer(resources: Resources, task: Task) {
return task.args.resources
? resources.add(Resources.fromObject(task.args.resources))
: resources;
}
function createProductionQueueState( function createProductionQueueState(
taskQueueInfo: QueueTasks, taskQueueState: TaskQueueState,
storage: VillageStorageState storage: VillageWarehouseState
): VillageProductionQueueState { ): VillageProductionQueueState {
const queue = taskQueueInfo.queue; const queue = taskQueueState.queue;
const tasks = taskQueueInfo.tasks; const tasks = taskQueueState.tasks;
const taskEndingTimestamp = taskQueueInfo.finishTs; const taskEndingTimestamp = taskQueueState.finishTs;
const resources = storage.resources; const resources = storage.resources;
const performance = storage.performance; const performance = storage.performance;
const firstTaskResources = tasks.slice(0, 1).reduce(taskResourceReducer, Resources.zero()); const firstTaskResources = tasks.slice(0, 1).reduce(taskResourceReducer, Resources.zero());
@ -180,7 +180,7 @@ function createProductionQueueState(
return { return {
queue, queue,
tasks: tasks.map(t => makeTaskState(t, storage.optimumFullness)), tasks,
isActive: tasks.length !== 0 || taskEndingTimestamp > currentTimestamp, isActive: tasks.length !== 0 || taskEndingTimestamp > currentTimestamp,
isWaiting: tasks.length !== 0 && taskEndingTimestamp < currentTimestamp, isWaiting: tasks.length !== 0 && taskEndingTimestamp < currentTimestamp,
currentTaskFinishTimestamp: taskEndingTimestamp, currentTaskFinishTimestamp: taskEndingTimestamp,
@ -194,13 +194,30 @@ function createProductionQueueState(
}; };
} }
function createAllProductionQueueStates( function getGroupedByQueueTasks(
storage: VillageStorageState, tasks: ReadonlyArray<TaskState>,
taskCollection: VillageTaskCollection storage: VillageStorage
): Array<TaskQueueState> {
const result: Array<TaskQueueState> = [];
for (let queue of OrderedProductionQueues) {
result.push({
queue,
tasks: tasks.filter(isInQueue(queue)),
finishTs: storage.getQueueTaskEnding(queue),
});
}
return result;
}
function createTaskQueueStates(
warehouse: VillageWarehouseState,
tasks: ReadonlyArray<TaskState>,
storage: VillageStorage
) { ) {
let result: Array<VillageProductionQueueState> = []; let result: Array<VillageProductionQueueState> = [];
for (let taskQueueInfo of taskCollection.getGroupedByQueueTasks()) { const possibleTasks = tasks.filter(task => task.canBeBuilt);
result.push(createProductionQueueState(taskQueueInfo, storage)); for (let taskQueueInfo of getGroupedByQueueTasks(possibleTasks, storage)) {
result.push(createProductionQueueState(taskQueueInfo, warehouse));
} }
return result; return result;
} }
@ -216,27 +233,27 @@ function getReadyForProductionTask(
return firstReadyQueue.tasks.find(task => task.name === TrainTroopTask.name || task.canBeBuilt); return firstReadyQueue.tasks.find(task => task.name === TrainTroopTask.name || task.canBeBuilt);
} }
function getTaskResources(task: Task | TaskState | undefined): Resources { function getTaskResources(task: TaskCore | undefined): Resources {
if (task && task.args.resources) { if (task && task.args.resources) {
return Resources.fromObject(task.args.resources); return Resources.fromObject(task.args.resources);
} }
return Resources.zero(); return Resources.zero();
} }
function makeTaskState(task: Task, maxResourcesForTask: Resources): TaskState { function taskResourceReducer(resources: Resources, task: TaskCore) {
const taskResources = getTaskResources(task); return task.args.resources
const taskWarehouseRequirements = new Resources( ? resources.add(Resources.fromObject(task.args.resources))
taskResources.lumber, : resources;
taskResources.clay, }
taskResources.iron,
0
);
const isEnoughWarehouseCapacity = maxResourcesForTask.allGreaterOrEqual(
taskWarehouseRequirements
);
const taskGranaryRequirements = new Resources(0, 0, 0, taskResources.crop); function makeTaskState(task: TaskCore, maxResourcesForTask: Resources): TaskState {
const isEnoughGranaryCapacity = maxResourcesForTask.allGreaterOrEqual(taskGranaryRequirements); const taskResources = getTaskResources(task);
const isEnoughWarehouseCapacity = maxResourcesForTask.allGreaterOrEqual(
new Resources(taskResources.lumber, taskResources.clay, taskResources.iron, 0)
);
const isEnoughGranaryCapacity = maxResourcesForTask.allGreaterOrEqual(
new Resources(0, 0, 0, taskResources.crop)
);
const canBeBuilt = isEnoughWarehouseCapacity && isEnoughGranaryCapacity; const canBeBuilt = isEnoughWarehouseCapacity && isEnoughGranaryCapacity;
@ -260,9 +277,11 @@ function createVillageOwnState(
const storageResources = Resources.fromStorage(storage.getResourceStorage()); const storageResources = Resources.fromStorage(storage.getResourceStorage());
const performance = storage.getResourcesPerformance(); const performance = storage.getResourcesPerformance();
const storageState = makeStorageState(resources, storageResources, performance); const storageState = makeStorageState(resources, storageResources, performance);
const queues = createAllProductionQueueStates(storageState, taskCollection); const tasks = taskCollection
.getTasks()
.map(t => makeTaskState(t, storageState.optimumFullness));
const queues = createTaskQueueStates(storageState, tasks, storage);
const firstReadyTask = getReadyForProductionTask(queues); const firstReadyTask = getReadyForProductionTask(queues);
const requiredResources = getTaskResources(firstReadyTask); const requiredResources = getTaskResources(firstReadyTask);
return { return {
id: village.id, id: village.id,
@ -271,8 +290,8 @@ function createVillageOwnState(
performance, performance,
storage: storageState, storage: storageState,
required: makeResourceState(requiredResources, resources, performance), required: makeResourceState(requiredResources, resources, performance),
tasks,
queues, queues,
tasks: taskCollection.getTasks().map(t => makeTaskState(t, storageState.optimumFullness)),
firstReadyTask, firstReadyTask,
incomingResources: calcIncomingResources(storage), incomingResources: calcIncomingResources(storage),
settings, settings,

View File

@ -1,19 +1,13 @@
import { VillageStorage } from './Storage/VillageStorage'; import { VillageStorage } from './Storage/VillageStorage';
import { isInQueue, Task, TaskId, uniqTaskId, withResources, withTime } from './Queue/TaskProvider'; import { Task, TaskId, uniqTaskId, withResources, withTime } from './Queue/TaskProvider';
import { Args } from './Queue/Args'; import { Args } from './Queue/Args';
import { isProductionTask, OrderedProductionQueues, ProductionQueue } from './Core/ProductionQueue'; import { isProductionTask } from './Core/ProductionQueue';
import { timestamp } from './utils'; import { timestamp } from './utils';
import { Resources } from './Core/Resources'; import { Resources } from './Core/Resources';
import { ContractAttributes, ContractType } from './Core/Contract'; 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';
export interface QueueTasks {
queue: ProductionQueue;
tasks: Array<Task>;
finishTs: number;
}
export class VillageTaskCollection { export class VillageTaskCollection {
private readonly storage: VillageStorage; private readonly storage: VillageStorage;
private readonly villageId: number; private readonly villageId: number;
@ -104,17 +98,4 @@ export class VillageTaskCollection {
this.modifyTasks(predicate, withResources(resources)); this.modifyTasks(predicate, withResources(resources));
} }
} }
getGroupedByQueueTasks(): Array<QueueTasks> {
const tasks = this.storage.getTasks();
const result: Array<QueueTasks> = [];
for (let queue of OrderedProductionQueues) {
result.push({
queue,
tasks: tasks.filter(isInQueue(queue)),
finishTs: this.storage.getQueueTaskEnding(queue),
});
}
return result;
}
} }