Mark tasks with required warehouse extra capacity

This commit is contained in:
Anton Vakhrushev 2020-06-28 20:29:56 +03:00
parent e2f9840dc8
commit a163d36b93
5 changed files with 68 additions and 51 deletions

View File

@ -29,32 +29,32 @@
<td class="right"> <td class="right">
<filling <filling
:value="villageState.resources.lumber" :value="villageState.resources.lumber"
:warning="villageState.storageOptimumFullness.lumber" :warning="villageState.storage.optimumFullness.lumber"
:critical="villageState.storageCriticalFullness.lumber" :critical="villageState.storage.criticalFullness.lumber"
:full="villageState.storage.capacity.lumber" :full="villageState.storage.capacity.lumber"
></filling> ></filling>
</td> </td>
<td class="right"> <td class="right">
<filling <filling
:value="villageState.resources.clay" :value="villageState.resources.clay"
:warning="villageState.storageOptimumFullness.clay" :warning="villageState.storage.optimumFullness.clay"
:critical="villageState.storageCriticalFullness.clay" :critical="villageState.storage.criticalFullness.clay"
:full="villageState.storage.capacity.clay" :full="villageState.storage.capacity.clay"
></filling> ></filling>
</td> </td>
<td class="right"> <td class="right">
<filling <filling
:value="villageState.resources.iron" :value="villageState.resources.iron"
:warning="villageState.storageOptimumFullness.iron" :warning="villageState.storage.optimumFullness.iron"
:critical="villageState.storageCriticalFullness.iron" :critical="villageState.storage.criticalFullness.iron"
:full="villageState.storage.capacity.iron" :full="villageState.storage.capacity.iron"
></filling> ></filling>
</td> </td>
<td class="right"> <td class="right">
<filling <filling
:value="villageState.resources.crop" :value="villageState.resources.crop"
:warning="villageState.storageOptimumFullness.crop" :warning="villageState.storage.optimumFullness.crop"
:critical="villageState.storageCriticalFullness.crop" :critical="villageState.storage.criticalFullness.crop"
:full="villageState.storage.capacity.crop" :full="villageState.storage.capacity.crop"
></filling> ></filling>
</td> </td>

View File

@ -1,7 +1,11 @@
<template> <template>
<table class="task-list"> <table class="task-list">
<tr v-for="task in tasks"> <tr v-for="task in tasks">
<td class="col-name" v-text="task.name" :title="task.name + ', ' + task.id"></td> <td
class="col-name"
v-text="(task.canBeBuilt ? '' : '(!) ') + task.name"
:title="task.name + ', ' + task.id"
></td>
<td class="col-actions"> <td class="col-actions">
<a href="#" class="action" @click.prevent="upTask(task.id)" title="Поднять задачу">up</a> <a href="#" class="action" @click.prevent="upTask(task.id)" title="Поднять задачу">up</a>
<a href="#" class="action" @click.prevent="downTask(task.id)" title="Опустить задачу">dn</a> <a href="#" class="action" @click.prevent="downTask(task.id)" title="Опустить задачу">dn</a>
@ -46,6 +50,7 @@ export default {
} }
.col-name { .col-name {
width: 20%; width: 20%;
white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }

View File

@ -68,7 +68,7 @@ export class ResourceTransferCalculator {
resources: readyToTransfer, resources: readyToTransfer,
score: { score: {
amount: readyToTransfer.amount(), amount: readyToTransfer.amount(),
overflow: sender.getState().isOverflowing, overflow: sender.getState().storage.isOverflowing,
}, },
}; };
} }
@ -77,7 +77,7 @@ export class ResourceTransferCalculator {
sender: VillageController, sender: VillageController,
recipient: VillageController recipient: VillageController
): [Resources, Resources] { ): [Resources, Resources] {
if (sender.getState().isOverflowing) { if (sender.getState().storage.isOverflowing) {
return [sender.getOverflowResources(), recipient.getAvailableToReceiveResources()]; return [sender.getOverflowResources(), recipient.getAvailableToReceiveResources()];
} }

View File

@ -1,7 +1,7 @@
import { VillageTaskCollection } from './VillageTaskCollection'; import { VillageTaskCollection } from './VillageTaskCollection';
import { Task, TaskId } from './Queue/TaskProvider'; import { TaskId } from './Queue/TaskProvider';
import { Args } from './Queue/Args'; import { Args } from './Queue/Args';
import { VillageState } from './VillageState'; import { TaskState, VillageState } from './VillageState';
import { Resources } from './Core/Resources'; import { Resources } from './Core/Resources';
import { MerchantsInfo } from './Core/Market'; import { MerchantsInfo } from './Core/Market';
import { VillageStorage } from './Storage/VillageStorage'; import { VillageStorage } from './Storage/VillageStorage';
@ -33,7 +33,7 @@ export class VillageController {
return this.state; return this.state;
} }
getReadyProductionTask(): Task | undefined { getReadyProductionTask(): TaskState | undefined {
return this.state.firstReadyTask; return this.state.firstReadyTask;
} }
@ -66,7 +66,7 @@ export class VillageController {
} }
getOverflowResources(): Resources { getOverflowResources(): Resources {
const limit = this.state.storageOptimumFullness; const limit = this.state.storage.optimumFullness;
const currentResources = this.state.resources; const currentResources = this.state.resources;
return currentResources.sub(limit).max(Resources.zero()); return currentResources.sub(limit).max(Resources.zero());
@ -75,7 +75,7 @@ export class VillageController {
getFreeResources(): Resources { getFreeResources(): Resources {
const mode = this.state.settings.receiveResourcesMode; const mode = this.state.settings.receiveResourcesMode;
const requirementResources = this.state.required.resources; const requirementResources = this.state.required.resources;
const optimumToStoreResources = this.state.storageOptimumFullness; const optimumToStoreResources = this.state.storage.optimumFullness;
switch (mode) { switch (mode) {
case ReceiveResourcesMode.Required: case ReceiveResourcesMode.Required:
@ -101,7 +101,7 @@ export class VillageController {
getRequiredResources(): Resources { getRequiredResources(): Resources {
const mode = this.state.settings.receiveResourcesMode; const mode = this.state.settings.receiveResourcesMode;
const optimumToStoreResources = this.state.storageOptimumFullness; const optimumToStoreResources = this.state.storage.optimumFullness;
const requirementResources = this.state.required.resources; const requirementResources = this.state.required.resources;
switch (mode) { switch (mode) {
@ -113,7 +113,7 @@ export class VillageController {
} }
private calcRequiredResources(targetResources: Resources): Resources { private calcRequiredResources(targetResources: Resources): Resources {
const optimumToStoreResources = this.state.storageOptimumFullness; const optimumToStoreResources = this.state.storage.optimumFullness;
const currentResources = this.state.resources; const currentResources = this.state.resources;
const incomingResources = this.state.incomingResources; const incomingResources = this.state.incomingResources;
@ -125,7 +125,7 @@ export class VillageController {
} }
getAvailableToReceiveResources(): Resources { getAvailableToReceiveResources(): Resources {
const optimumToStoreResources = this.state.storageOptimumFullness; const optimumToStoreResources = this.state.storage.optimumFullness;
const currentResources = this.state.resources; const currentResources = this.state.resources;
return optimumToStoreResources.sub(currentResources).max(Resources.zero()); return optimumToStoreResources.sub(currentResources).max(Resources.zero());

View File

@ -5,10 +5,18 @@ 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 { ProductionQueue } from './Core/ProductionQueue';
import { Task } from './Queue/TaskProvider'; import { Task, TaskId } from './Queue/TaskProvider';
import { timestamp } from './utils'; import { timestamp } from './utils';
import { QueueTasks, VillageTaskCollection } from './VillageTaskCollection'; import { QueueTasks, VillageTaskCollection } from './VillageTaskCollection';
import { TrainTroopTask } from './Task/TrainTroopTask'; import { TrainTroopTask } from './Task/TrainTroopTask';
import { Args } from './Queue/Args';
export interface TaskState {
id: TaskId;
name: string;
args: Args;
canBeBuilt: boolean;
}
interface VillageStorageState { interface VillageStorageState {
resources: Resources; resources: Resources;
@ -17,6 +25,9 @@ interface VillageStorageState {
performance: Resources; performance: Resources;
timeToZero: GatheringTime; timeToZero: GatheringTime;
timeToFull: GatheringTime; timeToFull: GatheringTime;
optimumFullness: Resources;
criticalFullness: Resources;
isOverflowing: boolean;
} }
/** /**
@ -43,7 +54,7 @@ interface ResourceLineState {
interface VillageProductionQueueState { interface VillageProductionQueueState {
queue: ProductionQueue; queue: ProductionQueue;
tasks: Array<Task>; tasks: Array<TaskState>;
isActive: boolean; isActive: boolean;
isWaiting: boolean; isWaiting: boolean;
currentTaskFinishTimestamp: number; currentTaskFinishTimestamp: number;
@ -68,12 +79,9 @@ interface VillageOwnState {
resources: Resources; resources: Resources;
performance: Resources; performance: Resources;
storage: VillageStorageState; storage: VillageStorageState;
storageOptimumFullness: Resources;
storageCriticalFullness: Resources;
isOverflowing: boolean;
queues: Array<VillageProductionQueueState>; queues: Array<VillageProductionQueueState>;
tasks: Array<Task>; tasks: Array<TaskState>;
firstReadyTask: Task | undefined; firstReadyTask: TaskState | undefined;
/** /**
* Required resources for nearest task * Required resources for nearest task
*/ */
@ -111,6 +119,8 @@ function makeStorageState(
storage: Resources, storage: Resources,
performance: Resources performance: Resources
): VillageStorageState { ): VillageStorageState {
const optimumFullness = storage.sub(performance.scale(3));
const criticalFullness = storage.sub(performance.scale(1));
return { return {
resources, resources,
capacity: storage, capacity: storage,
@ -118,6 +128,9 @@ function makeStorageState(
balance: storage.sub(resources), balance: storage.sub(resources),
timeToZero: timeToFastestResource(resources, Resources.zero(), performance), timeToZero: timeToFastestResource(resources, Resources.zero(), performance),
timeToFull: timeToFastestResource(resources, storage, performance), timeToFull: timeToFastestResource(resources, storage, performance),
optimumFullness: optimumFullness,
criticalFullness: criticalFullness,
isOverflowing: criticalFullness.anyLower(resources),
}; };
} }
@ -151,13 +164,13 @@ function taskResourceReducer(resources: Resources, task: Task) {
function createProductionQueueState( function createProductionQueueState(
taskQueueInfo: QueueTasks, taskQueueInfo: QueueTasks,
storage: VillageStorage storage: VillageStorageState
): VillageProductionQueueState { ): VillageProductionQueueState {
const queue = taskQueueInfo.queue; const queue = taskQueueInfo.queue;
const tasks = taskQueueInfo.tasks; const tasks = taskQueueInfo.tasks;
const taskEndingTimestamp = taskQueueInfo.finishTs; const taskEndingTimestamp = taskQueueInfo.finishTs;
const resources = storage.getResources(); const resources = storage.resources;
const performance = storage.getResourcesPerformance(); const performance = storage.performance;
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());
@ -165,7 +178,7 @@ function createProductionQueueState(
return { return {
queue, queue,
tasks, tasks: tasks.map(t => makeTaskState(t, storage.optimumFullness)),
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,
@ -180,7 +193,7 @@ function createProductionQueueState(
} }
function createAllProductionQueueStates( function createAllProductionQueueStates(
storage: VillageStorage, storage: VillageStorageState,
taskCollection: VillageTaskCollection taskCollection: VillageTaskCollection
) { ) {
let result: Array<VillageProductionQueueState> = []; let result: Array<VillageProductionQueueState> = [];
@ -191,28 +204,32 @@ function createAllProductionQueueStates(
} }
function getReadyForProductionTask( function getReadyForProductionTask(
queues: ReadonlyArray<VillageProductionQueueState>, queues: ReadonlyArray<VillageProductionQueueState>
maxResourcesForTask: Resources ): TaskState | undefined {
): Task | undefined {
const firstReadyQueue = queues.find(queue => queue.isWaiting); const firstReadyQueue = queues.find(queue => queue.isWaiting);
if (!firstReadyQueue) { if (!firstReadyQueue) {
return undefined; return undefined;
} }
return firstReadyQueue.tasks.find( return firstReadyQueue.tasks.find(task => task.name === TrainTroopTask.name || task.canBeBuilt);
task =>
task.name === TrainTroopTask.name ||
maxResourcesForTask.allGreaterOrEqual(getTaskResources(task))
);
} }
function getTaskResources(task: Task | undefined): Resources { function getTaskResources(task: Task | TaskState | 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 {
return {
id: task.id,
args: task.args,
name: task.name,
canBeBuilt: maxResourcesForTask.allGreaterOrEqual(getTaskResources(task)),
};
}
function createVillageOwnState( function createVillageOwnState(
village: Village, village: Village,
storage: VillageStorage, storage: VillageStorage,
@ -222,25 +239,20 @@ function createVillageOwnState(
const resources = storage.getResources(); const resources = storage.getResources();
const storageResources = Resources.fromStorage(storage.getResourceStorage()); const storageResources = Resources.fromStorage(storage.getResourceStorage());
const performance = storage.getResourcesPerformance(); const performance = storage.getResourcesPerformance();
const storageOptimumFullness = storageResources.sub(performance.scale(3)); const storageState = makeStorageState(resources, storageResources, performance);
const storageCriticalFullness = storageResources.sub(performance.scale(1)); const queues = createAllProductionQueueStates(storageState, taskCollection);
const isOverflowing = storageCriticalFullness.anyLower(resources); const firstReadyTask = getReadyForProductionTask(queues);
const queues = createAllProductionQueueStates(storage, taskCollection);
const firstReadyTask = getReadyForProductionTask(queues, storageOptimumFullness);
const requiredResources = getTaskResources(firstReadyTask);
const requiredResources = getTaskResources(firstReadyTask);
return { return {
id: village.id, id: village.id,
village, village,
resources, resources,
performance, performance,
storage: makeStorageState(resources, storageResources, performance), storage: storageState,
required: makeResourceState(requiredResources, resources, performance), required: makeResourceState(requiredResources, resources, performance),
storageOptimumFullness,
storageCriticalFullness,
isOverflowing,
queues, queues,
tasks: taskCollection.getTasks(), tasks: taskCollection.getTasks().map(t => makeTaskState(t, storageState.optimumFullness)),
firstReadyTask, firstReadyTask,
incomingResources: calcIncomingResources(storage), incomingResources: calcIncomingResources(storage),
settings, settings,