diff --git a/src/Core/GatheringTimings.ts b/src/Core/GatheringTimings.ts index 4426ca9..d7d5885 100644 --- a/src/Core/GatheringTimings.ts +++ b/src/Core/GatheringTimings.ts @@ -1,7 +1,40 @@ import { Resources } from './Resources'; -type GatheringNever = 'never'; -type GatheringTime = number | GatheringNever; +type GatheringPlain = number | 'never'; + +enum GatheringType { + Counting, + Never, +} + +export class GatheringTime { + private readonly _type: GatheringType; + private readonly _seconds: number; + + static makeNever(): GatheringTime { + return new GatheringTime(GatheringType.Never, 0); + } + + static makeCounting(value: number): GatheringTime { + return new GatheringTime(GatheringType.Counting, value); + } + + constructor(type: GatheringType, seconds: number) { + this._type = type; + this._seconds = seconds; + } + + get never(): boolean { + return this._type === GatheringType.Never; + } + + get seconds(): number { + if (this.never) { + throw new Error('Never'); + } + return this._seconds; + } +} export class GatheringTimings { readonly lumber: GatheringTime; @@ -9,6 +42,17 @@ export class GatheringTimings { readonly iron: GatheringTime; readonly crop: GatheringTime; + static create( + lumber: GatheringPlain, + clay: GatheringPlain, + iron: GatheringPlain, + crop: GatheringPlain + ): GatheringTimings { + const factory = (p: GatheringPlain) => + p === 'never' ? GatheringTime.makeNever() : GatheringTime.makeCounting(p); + return new GatheringTimings(factory(lumber), factory(clay), factory(iron), factory(crop)); + } + constructor(lumber: GatheringTime, clay: GatheringTime, iron: GatheringTime, crop: GatheringTime) { this.lumber = lumber; this.clay = clay; @@ -16,34 +60,41 @@ export class GatheringTimings { this.crop = crop; } - private get common(): GatheringTime { + get slowest(): GatheringTime { const xs = [this.lumber, this.clay, this.iron, this.crop]; - return xs.reduce((m, t) => (m === 'never' || t === 'never' ? 'never' : Math.max(m, t)), 0); + const init = new GatheringTime(GatheringType.Counting, 0); + return xs.reduce( + (m, t) => + m.never || t.never + ? GatheringTime.makeNever() + : GatheringTime.makeCounting(Math.max(m.seconds, t.seconds)), + init + ); } - get hours(): number { - const common = this.common; - if (common === 'never') { - throw Error('Never'); - } - return common; - } - - get never(): boolean { - return this.common === 'never'; + get fastest(): GatheringTime { + const xs = [this.lumber, this.clay, this.iron, this.crop]; + const init = new GatheringTime(GatheringType.Counting, Number.MAX_SAFE_INTEGER); + return xs.reduce( + (m, t) => + m.never || t.never + ? GatheringTime.makeNever() + : GatheringTime.makeCounting(Math.min(m.seconds, t.seconds)), + init + ); } } function calcGatheringTime(val: number, desired: number, speed: number): GatheringTime { const diff = desired - val; if (diff > 0 && speed <= 0) { - return 'never'; + return GatheringTime.makeNever(); } if (diff <= 0) { - return 0; + return GatheringTime.makeCounting(0); } - return diff / speed; + return GatheringTime.makeCounting((diff / speed) * 3600); } export function calcGatheringTimings(resources: Resources, desired: Resources, speed: Resources): GatheringTimings { diff --git a/src/DashboardView/VillageStateList.vue b/src/DashboardView/VillageStateList.vue index 7bc0e73..8862cd5 100644 --- a/src/DashboardView/VillageStateList.vue +++ b/src/DashboardView/VillageStateList.vue @@ -8,8 +8,7 @@ Глина Железо Зерно - Склад - Амбар + Время @@ -46,10 +45,7 @@ :speed="villageState.performance.crop" > - - - - + Прирост: @@ -66,7 +62,6 @@ - След. задача: @@ -102,8 +97,7 @@ :sign="false" > - - + Баланс задачи: @@ -119,8 +113,7 @@ - - + Баланс очереди: @@ -136,8 +129,7 @@ - - + Обязательства: @@ -154,7 +146,6 @@ - Торговцы: @@ -171,11 +162,10 @@ - - + import ResourceBalance from './ResourceBalance'; import VillageResource from './VillageResource'; -import { COLLECTION_POINT_ID, HORSE_STABLE_ID, MARKET_ID, QUARTERS_ID, WAREHOUSE_ID } from '../Core/Buildings'; +import { COLLECTION_POINT_ID, HORSE_STABLE_ID, MARKET_ID, QUARTERS_ID } from '../Core/Buildings'; import { path } from '../Helpers/Path'; +function secondsToTime(value) { + if (value === 0) { + return ''; + } + const hours = Math.floor(value / 3600); + const minutes = Math.floor((value % 3600) / 60); + const seconds = Math.floor(value % 60); + return `${hours}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`; +} + export default { components: { resource: ResourceBalance, @@ -217,6 +217,11 @@ export default { path(name, args) { return path(name, args); }, + storageTime(villageState) { + const toZero = villageState.storageBalance.timeToZero; + const toFull = villageState.storageBalance.timeToFull; + return this.renderGatheringTime(toFull.never ? toZero : toFull); + }, marketPath(fromVillage, toVillage) { return path('/build.php', { newdid: fromVillage.id, @@ -226,9 +231,6 @@ export default { y: toVillage.crd.y, }); }, - warehousePath(village) { - return path('/build.php', { newdid: village.id, gid: WAREHOUSE_ID }); - }, collectionPointPath(village) { return path('/build.php', { newdid: village.id, gid: COLLECTION_POINT_ID, tt: 1 }); }, @@ -238,20 +240,18 @@ export default { horseStablePath(village) { return path('/build.php', { newdid: village.id, gid: HORSE_STABLE_ID }); }, - secondsToTime(value) { - if (value === 0) { - return ''; - } - const hours = Math.floor(value / 3600); - const minutes = Math.floor((value % 3600) / 60); - const seconds = Math.floor(value % 60); - return `${hours}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`; + renderTimeInSeconds(value) { + return secondsToTime(value); }, - secondsToRequiredTime(value) { - if (value === -1) { + /** + * @param {GatheringTime} value + * @returns {string} + */ + renderGatheringTime(value) { + if (value.never) { return 'never'; } - return this.secondsToTime(value); + return secondsToTime(value.seconds); }, }, }; diff --git a/src/VillageState.ts b/src/VillageState.ts index c9fa108..e99b65f 100644 --- a/src/VillageState.ts +++ b/src/VillageState.ts @@ -2,12 +2,21 @@ import { Village } from './Core/Village'; import { Scheduler } from './Scheduler'; import { Resources } from './Core/Resources'; import { VillageStorage } from './Storage/VillageStorage'; -import { calcGatheringTimings } from './Core/GatheringTimings'; +import { calcGatheringTimings, GatheringTime } from './Core/GatheringTimings'; + +interface StorageBalance { + resources: Resources; + storage: Resources; + balance: Resources; + performance: Resources; + timeToZero: GatheringTime; + timeToFull: GatheringTime; +} interface RequiredResources { resources: Resources; balance: Resources; - time: number; + time: GatheringTime; } interface VillageOwnState { @@ -15,10 +24,11 @@ interface VillageOwnState { village: Village; resources: Resources; performance: Resources; + storage: Resources; + storageBalance: StorageBalance; required: RequiredResources; totalRequired: RequiredResources; incomingResources: Resources; - storage: Resources; buildRemainingSeconds: number; } @@ -39,19 +49,31 @@ export interface VillageState extends VillageOwnState { function calcResourceBalance(resources: Resources, current: Resources, performance: Resources): RequiredResources { return { - resources: resources, + resources, balance: current.sub(resources), - time: timeToResources(current, resources, performance), + time: timeToAllResources(current, resources, performance), }; } -function timeToResources(current: Resources, desired: Resources, performance: Resources): number { - const timings = calcGatheringTimings(current, desired, performance); - if (timings.never) { - return -1; - } +function calcStorageBalance(resources: Resources, storage: Resources, performance: Resources): StorageBalance { + return { + resources, + storage, + performance, + balance: storage.sub(resources), + timeToZero: timeToFastestResource(resources, Resources.zero(), performance), + timeToFull: timeToFastestResource(resources, storage, performance), + }; +} - return timings.hours * 3600; +function timeToAllResources(current: Resources, desired: Resources, performance: Resources): GatheringTime { + const timings = calcGatheringTimings(current, desired, performance); + return timings.slowest; +} + +function timeToFastestResource(current: Resources, desired: Resources, performance: Resources): GatheringTime { + const timings = calcGatheringTimings(current, desired, performance); + return timings.fastest; } function calcIncomingResources(storage: VillageStorage): Resources { @@ -72,9 +94,10 @@ function createVillageOwnState(village: Village, scheduler: Scheduler): VillageO village, resources, performance, + storage: Resources.fromStorage(resourceStorage), + storageBalance: calcStorageBalance(resources, Resources.fromStorage(resourceStorage), performance), required: calcResourceBalance(requiredResources, resources, performance), totalRequired: calcResourceBalance(totalRequiredResources, resources, performance), - storage: Resources.fromStorage(resourceStorage), buildRemainingSeconds: buildQueueInfo.seconds, incomingResources: calcIncomingResources(storage), }; diff --git a/tests/Core/GatheringTimingsTest.ts b/tests/Core/GatheringTimingsTest.ts index 1e66c17..dca998b 100644 --- a/tests/Core/GatheringTimingsTest.ts +++ b/tests/Core/GatheringTimingsTest.ts @@ -6,18 +6,18 @@ import { calcGatheringTimings, GatheringTimings } from '../../src/Core/Gathering describe('Gathering timings', function() { it('Can calc common from numbers', function() { - const timings = new GatheringTimings(10, 20, 15, 5); - expect(20).to.equals(timings.hours); + const timings = GatheringTimings.create(10, 20, 15, 5); + expect(20).to.equals(timings.slowest.seconds); }); it('Can calc common with never', function() { - const timings = new GatheringTimings(10, 20, 'never', 5); - expect(true).to.equals(timings.never); + const timings = GatheringTimings.create(10, 20, 'never', 5); + expect(true).to.equals(timings.slowest.never); }); it('Can calc common with all never', function() { - const timings = new GatheringTimings('never', 'never', 'never', 'never'); - expect(true).to.equals(timings.never); + const timings = GatheringTimings.create('never', 'never', 'never', 'never'); + expect(true).to.equals(timings.slowest.never); }); it('Can calc timings', function() { @@ -25,7 +25,7 @@ describe('Gathering timings', function() { const desired = new Resources(60, 60, 60, 60); const speed = new Resources(5, 5, 5, 5); const timings = calcGatheringTimings(resources, desired, speed); - expect(10).to.equals(timings.hours); + expect(10 * 3600).to.equals(timings.slowest.seconds); }); it('Can calc timings with different speed', function() { @@ -33,11 +33,11 @@ describe('Gathering timings', function() { const desired = new Resources(60, 60, 60, 60); const speed = new Resources(5, 10, 25, 5); const timings = calcGatheringTimings(resources, desired, speed); - expect(10).to.equals(timings.lumber); - expect(5).to.equals(timings.clay); - expect(2).to.equals(timings.iron); - expect(10).to.equals(timings.crop); - expect(10).to.equals(timings.hours); + expect(10 * 3600).to.equals(timings.lumber.seconds); + expect(5 * 3600).to.equals(timings.clay.seconds); + expect(2 * 3600).to.equals(timings.iron.seconds); + expect(10 * 3600).to.equals(timings.crop.seconds); + expect(10 * 3600).to.equals(timings.slowest.seconds); }); it('Can calc timings with negative speed', function() { @@ -45,10 +45,10 @@ describe('Gathering timings', function() { const desired = new Resources(60, 60, 60, 60); const speed = new Resources(5, 10, 25, -5); const timings = calcGatheringTimings(resources, desired, speed); - expect(10).to.equals(timings.lumber); - expect(5).to.equals(timings.clay); - expect(2).to.equals(timings.iron); - expect('never').to.equals(timings.crop); - expect(true).to.equals(timings.never); + expect(10 * 3600).to.equals(timings.lumber.seconds); + expect(5 * 3600).to.equals(timings.clay.seconds); + expect(2 * 3600).to.equals(timings.iron.seconds); + expect(true).to.equals(timings.crop.never); + expect(true).to.equals(timings.slowest.never); }); });