@civ-clone/core-strategy 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,10 +1,11 @@
1
1
  # core-strategy
2
2
 
3
- A framework for building modular AI. The idea being that `Strategy`s are built of many `Routine`s for specific
4
- `PlayerAction`s and it should be easy enough to register new `Strategy`s to handle newly added `PlayerAction`s.
3
+ A framework for building modular AI. The idea being that `Strategy`s can handle one of many `PlayerAction`s and it
4
+ should be easy enough to register new `Strategy`s to handle newly added `PlayerAction`s or specific custom `Unit`s and
5
+ their actions (`Caravan`, `Diplomat`, etc).
5
6
 
6
- The consumer `AIClient`, `SimpleAIStrategyClient`, is available at
7
- [civ-clone/simple-ai-strategy-client](https://github.com/civ-clone/simple-ai-strategy-client).
7
+ The consumer `AIClient`, `StrategyAIClient`, is available at
8
+ [civ-clone/core-strategy-ai-client](https://github.com/civ-clone/core-strategy-ai-client).
8
9
 
9
10
  Another aim for this set of classes is to be able to automate simple tasks (explore, improve terrain, go-to, etc.).
10
11
 
@@ -12,27 +13,13 @@ Lastly, there's the possibility for primitive Barbarian behaviour, without havin
12
13
 
13
14
  ## Current state
14
15
 
16
+ This is purely illustrative and might change quite substantially until I've got a reasonable working implementation.
17
+
15
18
  ```ts
16
19
  import Strategy from '@civ-clone/core-strategy/Strategy';
17
20
 
18
21
  // Export your base `Strategy`:
19
22
  export class MyStrategy extends Strategy {
20
- constructor(
21
- dependencyForRoutine: SpecificThing = defaultInstanceOfSpecificThing
22
- ) {
23
- super(
24
- new MyRoutine(dependencyForRoutine),
25
- new AnotherRoutine(dependencyForRoutine)
26
- );
27
- }
28
- }
29
-
30
- import PlayerAction from '@civ-clone/core-player/PlayerAction';
31
- import Routine from '@civ-clone/core-strategy/Strategy';
32
- import { instance as strategyNoteInstance } from '@civ-clone/core-strategy/StrategyNoteRegistry';
33
-
34
- // which is comprised of `Routine`s like the following:
35
- export class MyRoutine extends Routine {
36
23
  // Inject dependencies (e.g. `Registry`s) into the `constructor` as usual
37
24
 
38
25
  attempt(action: PlayerAction<SpecificItemClass>): boolean {
@@ -69,7 +56,7 @@ export class MyRoutine extends Routine {
69
56
  import { generateKey } from '@civ-clone/core-strategy/StrategyNote';
70
57
 
71
58
  export const myCustomKeyGenerator = (item: SpecificItemClass) =>
72
- generateKey(item, MyRoutine.name);
59
+ generateKey(item, MyStrategy.name);
73
60
 
74
61
  // To control the priority of your `Routine`s you need to use `Priority` `Rule`s and you can even take the `Leader`s
75
62
  // `Trait`s into consideration if you wish:
@@ -89,7 +76,7 @@ export const getRules = (
89
76
  ): Priority[] => [
90
77
  new Priority(
91
78
  new Criterion(
92
- (player: Player, routine: Routine) => routine instanceof MyRoutine
79
+ (player: Player, strategy: Strategy) => routine instanceof MyRoutine
93
80
  ),
94
81
  new Effect((player: Player) => {
95
82
  const civilization = player.civilization(),
@@ -1,6 +1,9 @@
1
- import Player from '@civ-clone/core-player/Player';
1
+ import PlayerAction from '@civ-clone/core-player/PlayerAction';
2
2
  import PriorityValue from '@civ-clone/core-rule/Priority';
3
- import Routine from '../Routine';
4
3
  import Rule from '@civ-clone/core-rule/Rule';
5
- export declare class Priority extends Rule<[Player, Routine], PriorityValue> {}
4
+ import Strategy from '../Strategy';
5
+ export declare class Priority extends Rule<
6
+ [PlayerAction, Strategy],
7
+ PriorityValue
8
+ > {}
6
9
  export default Priority;
@@ -1 +1 @@
1
- {"version":3,"file":"Priority.js","sourceRoot":"","sources":["Priority.ts"],"names":[],"mappings":";;;AAGA,oDAA6C;AAE7C,MAAa,QAAS,SAAQ,cAAsC;CAAG;AAAvE,4BAAuE;AAEvE,kBAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"Priority.js","sourceRoot":"","sources":["Priority.ts"],"names":[],"mappings":";;;AAEA,oDAA6C;AAG7C,MAAa,QAAS,SAAQ,cAA6C;CAAG;AAA9E,4BAA8E;AAE9E,kBAAe,QAAQ,CAAC"}
package/Rules/Priority.ts CHANGED
@@ -1,8 +1,8 @@
1
- import Player from '@civ-clone/core-player/Player';
1
+ import PlayerAction from '@civ-clone/core-player/PlayerAction';
2
2
  import PriorityValue from '@civ-clone/core-rule/Priority';
3
- import Routine from '../Routine';
4
3
  import Rule from '@civ-clone/core-rule/Rule';
4
+ import Strategy from '../Strategy';
5
5
 
6
- export class Priority extends Rule<[Player, Routine], PriorityValue> {}
6
+ export class Priority extends Rule<[PlayerAction, Strategy], PriorityValue> {}
7
7
 
8
8
  export default Priority;
package/Strategy.d.ts CHANGED
@@ -1,18 +1,18 @@
1
- import Player from '@civ-clone/core-player/Player';
1
+ import { RuleRegistry } from '@civ-clone/core-rule/RuleRegistry';
2
2
  import PlayerAction from '@civ-clone/core-player/PlayerAction';
3
3
  import Priority from '@civ-clone/core-rule/Priority';
4
- import Routine from './Routine';
5
4
  export interface IStrategy {
6
5
  attempt(action: PlayerAction): boolean;
7
- priority(player: Player): Priority;
6
+ priority(action: PlayerAction): Priority;
8
7
  }
9
8
  export declare class Strategy implements IStrategy {
10
- #private;
11
- constructor(...items: Routine[]);
9
+ private _ruleRegistry;
10
+ constructor(ruleRegistry?: RuleRegistry);
12
11
  /**
13
12
  * Checks to see if the `action` can be handled, returns `true` if it is, `false` otherwise.
14
13
  */
15
14
  attempt(action: PlayerAction): boolean;
16
- priority(player: Player): Priority;
15
+ priority(action: PlayerAction): Priority;
16
+ protected ruleRegistry(): RuleRegistry;
17
17
  }
18
18
  export default Strategy;
package/Strategy.js CHANGED
@@ -1,32 +1,30 @@
1
1
  "use strict";
2
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
- };
7
- var _Strategy_routines;
8
2
  Object.defineProperty(exports, "__esModule", { value: true });
9
3
  exports.Strategy = void 0;
4
+ const RuleRegistry_1 = require("@civ-clone/core-rule/RuleRegistry");
10
5
  const Priority_1 = require("@civ-clone/core-rule/Priority");
6
+ const Priority_2 = require("./Rules/Priority");
11
7
  class Strategy {
12
- constructor(...items) {
13
- _Strategy_routines.set(this, []);
14
- items.forEach((item) => __classPrivateFieldGet(this, _Strategy_routines, "f").push(item));
8
+ constructor(ruleRegistry = RuleRegistry_1.instance) {
9
+ this._ruleRegistry = ruleRegistry;
15
10
  }
16
11
  /**
17
12
  * Checks to see if the `action` can be handled, returns `true` if it is, `false` otherwise.
18
13
  */
19
14
  attempt(action) {
20
- return __classPrivateFieldGet(this, _Strategy_routines, "f")
21
- .sort((a, b) => a.priority(action.player()).value() -
22
- b.priority(action.player()).value())
23
- .some((routine) => routine.attempt(action));
15
+ throw new Error('This must be overwritten in the implementor.');
24
16
  }
25
- priority(player) {
26
- return new Priority_1.default(Math.min(...__classPrivateFieldGet(this, _Strategy_routines, "f").map((routine) => routine.priority(player).value()), Infinity));
17
+ priority(action) {
18
+ return new Priority_1.default(
19
+ // This takes the highest priority (lowest value) from all the applicable `PriorityRule`s
20
+ Math.min(...this._ruleRegistry
21
+ .process(Priority_2.default, action, this)
22
+ .map((priority) => priority.value()), Infinity));
23
+ }
24
+ ruleRegistry() {
25
+ return this._ruleRegistry;
27
26
  }
28
27
  }
29
28
  exports.Strategy = Strategy;
30
- _Strategy_routines = new WeakMap();
31
29
  exports.default = Strategy;
32
30
  //# sourceMappingURL=Strategy.js.map
package/Strategy.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Strategy.js","sourceRoot":"","sources":["Strategy.ts"],"names":[],"mappings":";;;;;;;;;AAEA,4DAAqD;AAQrD,MAAa,QAAQ;IAGnB,YAAY,GAAG,KAAgB;QAF/B,6BAAuB,EAAE,EAAC;QAGxB,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,uBAAA,IAAI,0BAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACrD,CAAC;IAED;;OAEG;IACH,OAAO,CAAC,MAAoB;QAC1B,OAAO,uBAAA,IAAI,0BAAU;aAClB,IAAI,CACH,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE;YACnC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,CACtC;aACA,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAChD,CAAC;IAED,QAAQ,CAAC,MAAc;QACrB,OAAO,IAAI,kBAAQ,CACjB,IAAI,CAAC,GAAG,CACN,GAAG,uBAAA,IAAI,0BAAU,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC,EACpE,QAAQ,CACT,CACF,CAAC;IACJ,CAAC;CACF;AA5BD,4BA4BC;;AAED,kBAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"Strategy.js","sourceRoot":"","sources":["Strategy.ts"],"names":[],"mappings":";;;AAAA,oEAG2C;AAE3C,4DAAqD;AACrD,+CAA4C;AAO5C,MAAa,QAAQ;IAGnB,YAAY,eAA6B,uBAAoB;QAC3D,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC;IACpC,CAAC;IAED;;OAEG;IACH,OAAO,CAAC,MAAoB;QAC1B,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IAED,QAAQ,CAAC,MAAoB;QAC3B,OAAO,IAAI,kBAAQ;QACjB,yFAAyF;QACzF,IAAI,CAAC,GAAG,CACN,GAAG,IAAI,CAAC,aAAa;aAClB,OAAO,CAAC,kBAAY,EAAE,MAAM,EAAE,IAAI,CAAC;aACnC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,EACtC,QAAQ,CACT,CACF,CAAC;IACJ,CAAC;IAES,YAAY;QACpB,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;CACF;AA7BD,4BA6BC;AAED,kBAAe,QAAQ,CAAC"}
package/Strategy.ts CHANGED
@@ -1,41 +1,45 @@
1
- import Player from '@civ-clone/core-player/Player';
1
+ import {
2
+ RuleRegistry,
3
+ instance as ruleRegistryInstance,
4
+ } from '@civ-clone/core-rule/RuleRegistry';
2
5
  import PlayerAction from '@civ-clone/core-player/PlayerAction';
3
6
  import Priority from '@civ-clone/core-rule/Priority';
4
- import Routine from './Routine';
7
+ import PriorityRule from './Rules/Priority';
5
8
 
6
9
  export interface IStrategy {
7
10
  attempt(action: PlayerAction): boolean;
8
- priority(player: Player): Priority;
11
+ priority(action: PlayerAction): Priority;
9
12
  }
10
13
 
11
14
  export class Strategy implements IStrategy {
12
- #routines: Routine[] = [];
15
+ private _ruleRegistry: RuleRegistry;
13
16
 
14
- constructor(...items: Routine[]) {
15
- items.forEach((item) => this.#routines.push(item));
17
+ constructor(ruleRegistry: RuleRegistry = ruleRegistryInstance) {
18
+ this._ruleRegistry = ruleRegistry;
16
19
  }
17
20
 
18
21
  /**
19
22
  * Checks to see if the `action` can be handled, returns `true` if it is, `false` otherwise.
20
23
  */
21
24
  attempt(action: PlayerAction): boolean {
22
- return this.#routines
23
- .sort(
24
- (a, b) =>
25
- a.priority(action.player()).value() -
26
- b.priority(action.player()).value()
27
- )
28
- .some((routine) => routine.attempt(action));
25
+ throw new Error('This must be overwritten in the implementor.');
29
26
  }
30
27
 
31
- priority(player: Player): Priority {
28
+ priority(action: PlayerAction): Priority {
32
29
  return new Priority(
30
+ // This takes the highest priority (lowest value) from all the applicable `PriorityRule`s
33
31
  Math.min(
34
- ...this.#routines.map((routine) => routine.priority(player).value()),
32
+ ...this._ruleRegistry
33
+ .process(PriorityRule, action, this)
34
+ .map((priority) => priority.value()),
35
35
  Infinity
36
36
  )
37
37
  );
38
38
  }
39
+
40
+ protected ruleRegistry(): RuleRegistry {
41
+ return this._ruleRegistry;
42
+ }
39
43
  }
40
44
 
41
45
  export default Strategy;
package/StrategyNote.d.ts CHANGED
@@ -1,17 +1,16 @@
1
- declare type IDataObject = {
2
- id(): string;
3
- };
1
+ import { IDataObject } from '@civ-clone/core-data-object/DataObject';
4
2
  export interface IStrategyNote<Value = any> {
5
3
  key(): string;
6
4
  value(): Value;
7
5
  }
8
6
  export declare class StrategyNote<Value = any> implements IStrategyNote<Value> {
9
- #private;
7
+ private _key;
8
+ private _value;
10
9
  constructor(key: string, value: Value);
11
10
  key(): string;
12
11
  value(): Value;
13
12
  }
14
13
  export declare const generateKey: (
15
- ...items: (IDataObject | string)[]
14
+ ...items: (Pick<IDataObject, 'id'> | string)[]
16
15
  ) => string;
17
16
  export default StrategyNote;
package/StrategyNote.js CHANGED
@@ -1,37 +1,22 @@
1
1
  "use strict";
2
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
- if (kind === "m") throw new TypeError("Private method is not writable");
4
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
- };
8
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
- };
13
- var _StrategyNote_key, _StrategyNote_value;
14
2
  Object.defineProperty(exports, "__esModule", { value: true });
15
3
  exports.generateKey = exports.StrategyNote = void 0;
16
4
  const DataObject_1 = require("@civ-clone/core-data-object/DataObject");
17
5
  class StrategyNote {
18
6
  constructor(key, value) {
19
- _StrategyNote_key.set(this, void 0);
20
- _StrategyNote_value.set(this, void 0);
21
- __classPrivateFieldSet(this, _StrategyNote_key, key, "f");
22
- __classPrivateFieldSet(this, _StrategyNote_value, value, "f");
7
+ this._key = key;
8
+ this._value = value;
23
9
  }
24
10
  key() {
25
- return __classPrivateFieldGet(this, _StrategyNote_key, "f");
11
+ return this._key;
26
12
  }
27
13
  value() {
28
- return __classPrivateFieldGet(this, _StrategyNote_value, "f");
14
+ return this._value;
29
15
  }
30
16
  }
31
17
  exports.StrategyNote = StrategyNote;
32
- _StrategyNote_key = new WeakMap(), _StrategyNote_value = new WeakMap();
33
18
  const generateKey = (...items) => items
34
- .map((item) => item instanceof DataObject_1.default
19
+ .map((item) => item instanceof DataObject_1.DataObject
35
20
  ? item.id()
36
21
  : typeof item === 'string'
37
22
  ? item
@@ -1 +1 @@
1
- {"version":3,"file":"StrategyNote.js","sourceRoot":"","sources":["StrategyNote.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,uEAAgE;AAWhE,MAAa,YAAY;IAIvB,YAAY,GAAW,EAAE,KAAY;QAHrC,oCAAa;QACb,sCAAc;QAGZ,uBAAA,IAAI,qBAAQ,GAAG,MAAA,CAAC;QAChB,uBAAA,IAAI,uBAAU,KAAK,MAAA,CAAC;IACtB,CAAC;IAEM,GAAG;QACR,OAAO,uBAAA,IAAI,yBAAK,CAAC;IACnB,CAAC;IAEM,KAAK;QACV,OAAO,uBAAA,IAAI,2BAAO,CAAC;IACrB,CAAC;CACF;AAhBD,oCAgBC;;AAEM,MAAM,WAAW,GAAmD,CACzE,GAAG,KAA+B,EAClC,EAAE,CACF,KAAK;KACF,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACZ,IAAI,YAAY,oBAAU;IACxB,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE;IACX,CAAC,CAAC,OAAO,IAAI,KAAK,QAAQ;QAC1B,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CACpB;KACA,IAAI,CAAC,GAAG,CAAC,CAAC;AAXF,QAAA,WAAW,eAWT;AAEf,kBAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"StrategyNote.js","sourceRoot":"","sources":["StrategyNote.ts"],"names":[],"mappings":";;;AAAA,uEAGgD;AAOhD,MAAa,YAAY;IAIvB,YAAY,GAAW,EAAE,KAAY;QACnC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;QAChB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAEM,GAAG;QACR,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAEM,KAAK;QACV,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CACF;AAhBD,oCAgBC;AAEM,MAAM,WAAW,GAEV,CAAC,GAAG,KAA2C,EAAE,EAAE,CAC/D,KAAK;KACF,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACZ,IAAI,YAAY,uBAAU;IACxB,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE;IACX,CAAC,CAAC,OAAO,IAAI,KAAK,QAAQ;QAC1B,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CACpB;KACA,IAAI,CAAC,GAAG,CAAC,CAAC;AAXF,QAAA,WAAW,eAWT;AAEf,kBAAe,YAAY,CAAC"}
package/StrategyNote.ts CHANGED
@@ -1,8 +1,7 @@
1
- import DataObject from '@civ-clone/core-data-object/DataObject';
2
-
3
- type IDataObject = {
4
- id(): string;
5
- };
1
+ import {
2
+ DataObject,
3
+ IDataObject,
4
+ } from '@civ-clone/core-data-object/DataObject';
6
5
 
7
6
  export interface IStrategyNote<Value = any> {
8
7
  key(): string;
@@ -10,26 +9,26 @@ export interface IStrategyNote<Value = any> {
10
9
  }
11
10
 
12
11
  export class StrategyNote<Value = any> implements IStrategyNote<Value> {
13
- #key: string;
14
- #value: Value;
12
+ private _key: string;
13
+ private _value: Value;
15
14
 
16
15
  constructor(key: string, value: Value) {
17
- this.#key = key;
18
- this.#value = value;
16
+ this._key = key;
17
+ this._value = value;
19
18
  }
20
19
 
21
20
  public key(): string {
22
- return this.#key;
21
+ return this._key;
23
22
  }
24
23
 
25
24
  public value(): Value {
26
- return this.#value;
25
+ return this._value;
27
26
  }
28
27
  }
29
28
 
30
- export const generateKey: (...items: (IDataObject | string)[]) => string = (
31
- ...items: (IDataObject | string)[]
32
- ) =>
29
+ export const generateKey: (
30
+ ...items: (Pick<IDataObject, 'id'> | string)[]
31
+ ) => string = (...items: (Pick<IDataObject, 'id'> | string)[]) =>
33
32
  items
34
33
  .map((item) =>
35
34
  item instanceof DataObject
@@ -12,6 +12,7 @@ export declare class StrategyNoteRegistry
12
12
  extends EntityRegistry<StrategyNote>
13
13
  implements IStrategyNoteRegistry
14
14
  {
15
+ constructor();
15
16
  getByKey<Value = any>(key: string): StrategyNote<Value> | undefined;
16
17
  getOrCreateByKey<Value>(key: string, value: Value): StrategyNote<Value>;
17
18
  register(...entities: StrategyNote[]): void;
@@ -4,6 +4,9 @@ exports.instance = exports.StrategyNoteRegistry = void 0;
4
4
  const EntityRegistry_1 = require("@civ-clone/core-registry/EntityRegistry");
5
5
  const StrategyNote_1 = require("./StrategyNote");
6
6
  class StrategyNoteRegistry extends EntityRegistry_1.EntityRegistry {
7
+ constructor() {
8
+ super(StrategyNote_1.default);
9
+ }
7
10
  getByKey(key) {
8
11
  return this.getBy('key', key)[0];
9
12
  }
@@ -1 +1 @@
1
- {"version":3,"file":"StrategyNoteRegistry.js","sourceRoot":"","sources":["StrategyNoteRegistry.ts"],"names":[],"mappings":";;;AAAA,4EAGiD;AACjD,iDAA0C;AAQ1C,MAAa,oBACX,SAAQ,+BAA4B;IAGpC,QAAQ,CAAc,GAAW;QAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACnC,CAAC;IAED,gBAAgB,CAAQ,GAAW,EAAE,KAAY;QAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAEpC,IAAI,QAAQ,EAAE;YACZ,OAAO,QAAQ,CAAC;SACjB;QAED,MAAM,IAAI,GAAG,IAAI,sBAAY,CAAQ,GAAG,EAAE,KAAK,CAAC,CAAC;QAEjD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEpB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,QAAQ,CAAC,GAAG,QAAwB;QAClC,QAAQ,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;YAC1B,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE;gBAC/B,MAAM,IAAI,SAAS,CACjB,oBAAoB,MAAM,CAAC,GAAG,EAAE,mBAAmB,CACpD,CAAC;aACH;YAED,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,CAAC,GAAG,QAAwB;QACjC,QAAQ,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;YAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;YAE7C,IAAI,QAAQ,EAAE;gBACZ,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;aAC3B;YAED,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AA7CD,oDA6CC;AAEY,QAAA,QAAQ,GAAyB,IAAI,oBAAoB,EAAE,CAAC;AAEzE,kBAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"StrategyNoteRegistry.js","sourceRoot":"","sources":["StrategyNoteRegistry.ts"],"names":[],"mappings":";;;AAAA,4EAGiD;AACjD,iDAA0C;AAQ1C,MAAa,oBACX,SAAQ,+BAA4B;IAGpC;QACE,KAAK,CAAC,sBAAY,CAAC,CAAC;IACtB,CAAC;IAED,QAAQ,CAAc,GAAW;QAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACnC,CAAC;IAED,gBAAgB,CAAQ,GAAW,EAAE,KAAY;QAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAEpC,IAAI,QAAQ,EAAE;YACZ,OAAO,QAAQ,CAAC;SACjB;QAED,MAAM,IAAI,GAAG,IAAI,sBAAY,CAAQ,GAAG,EAAE,KAAK,CAAC,CAAC;QAEjD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEpB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,QAAQ,CAAC,GAAG,QAAwB;QAClC,QAAQ,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;YAC1B,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE;gBAC/B,MAAM,IAAI,SAAS,CACjB,oBAAoB,MAAM,CAAC,GAAG,EAAE,mBAAmB,CACpD,CAAC;aACH;YAED,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,CAAC,GAAG,QAAwB;QACjC,QAAQ,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;YAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;YAE7C,IAAI,QAAQ,EAAE;gBACZ,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;aAC3B;YAED,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAjDD,oDAiDC;AAEY,QAAA,QAAQ,GAAyB,IAAI,oBAAoB,EAAE,CAAC;AAEzE,kBAAe,oBAAoB,CAAC"}
@@ -14,6 +14,10 @@ export class StrategyNoteRegistry
14
14
  extends EntityRegistry<StrategyNote>
15
15
  implements IStrategyNoteRegistry
16
16
  {
17
+ constructor() {
18
+ super(StrategyNote);
19
+ }
20
+
17
21
  getByKey<Value = any>(key: string): StrategyNote<Value> | undefined {
18
22
  return this.getBy('key', key)[0];
19
23
  }
@@ -1,6 +1,6 @@
1
1
  import EntityRegistry from '@civ-clone/core-registry/EntityRegistry';
2
- import Strategy from './Strategy';
3
2
  import PlayerAction from '@civ-clone/core-player/PlayerAction';
3
+ import Strategy from './Strategy';
4
4
  export declare class StrategyRegistry extends EntityRegistry<Strategy> {
5
5
  constructor();
6
6
  /**
@@ -13,8 +13,7 @@ class StrategyRegistry extends EntityRegistry_1.default {
13
13
  */
14
14
  attempt(action) {
15
15
  return this.entries()
16
- .sort((a, b) => a.priority(action.player()).value() -
17
- b.priority(action.player()).value() ||
16
+ .sort((a, b) => a.priority(action).value() - b.priority(action).value() ||
18
17
  Math.floor(Math.random() * 3 - 1))
19
18
  .some((strategy) => strategy.attempt(action));
20
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"StrategyRegistry.js","sourceRoot":"","sources":["StrategyRegistry.ts"],"names":[],"mappings":";;;AAAA,4EAAqE;AACrE,yCAAkC;AAGlC,MAAa,gBAAiB,SAAQ,wBAAwB;IAC5D;QACE,KAAK,CAAC,kBAAQ,CAAC,CAAC;IAClB,CAAC;IAED;;;OAGG;IACH,OAAO,CAAC,MAAoB;QAC1B,OAAO,IAAI,CAAC,OAAO,EAAE;aAClB,IAAI,CACH,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE;YACjC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE;YACrC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CACpC;aACA,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAClD,CAAC;CACF;AAnBD,4CAmBC;AAEY,QAAA,QAAQ,GAAG,IAAI,gBAAgB,EAAE,CAAC;AAE/C,kBAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"StrategyRegistry.js","sourceRoot":"","sources":["StrategyRegistry.ts"],"names":[],"mappings":";;;AAAA,4EAAqE;AAErE,yCAAkC;AAElC,MAAa,gBAAiB,SAAQ,wBAAwB;IAC5D;QACE,KAAK,CAAC,kBAAQ,CAAC,CAAC;IAClB,CAAC;IAED;;;OAGG;IACH,OAAO,CAAC,MAAoB;QAC1B,OAAO,IAAI,CAAC,OAAO,EAAE;aAClB,IAAI,CACH,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE;YACvD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CACpC;aACA,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAClD,CAAC;CACF;AAlBD,4CAkBC;AAEY,QAAA,QAAQ,GAAG,IAAI,gBAAgB,EAAE,CAAC;AAE/C,kBAAe,gBAAgB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import EntityRegistry from '@civ-clone/core-registry/EntityRegistry';
2
- import Strategy from './Strategy';
3
2
  import PlayerAction from '@civ-clone/core-player/PlayerAction';
3
+ import Strategy from './Strategy';
4
4
 
5
5
  export class StrategyRegistry extends EntityRegistry<Strategy> {
6
6
  constructor() {
@@ -15,8 +15,7 @@ export class StrategyRegistry extends EntityRegistry<Strategy> {
15
15
  return this.entries()
16
16
  .sort(
17
17
  (a, b) =>
18
- a.priority(action.player()).value() -
19
- b.priority(action.player()).value() ||
18
+ a.priority(action).value() - b.priority(action).value() ||
20
19
  Math.floor(Math.random() * 3 - 1)
21
20
  )
22
21
  .some((strategy) => strategy.attempt(action));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@civ-clone/core-strategy",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "repository": "git@github.com:civ-clone/core-strategy.git",
5
5
  "keywords": [
6
6
  "typescript",
@@ -1,80 +1,142 @@
1
- import { High, Normal } from '@civ-clone/core-rule/Priorities';
2
- import { RoutineA, RoutineB, RoutineFalse, RoutineTrue } from './lib/Routines';
1
+ import { High, Low, Normal } from '@civ-clone/core-rule/Priorities';
2
+ import { StrategyA, StrategyB, StrategyFalse } from './lib/Strategies';
3
3
  import { expect, spy } from 'chai';
4
4
  import Criterion from '@civ-clone/core-rule/Criterion';
5
5
  import Effect from '@civ-clone/core-rule/Effect';
6
6
  import Player from '@civ-clone/core-player/Player';
7
- import { PlayerAction } from './lib/PlayerActions';
8
7
  import Priority from '@civ-clone/core-rule/Priority';
9
8
  import PriorityRule from '../Rules/Priority';
10
- import Routine from '../Routine';
11
9
  import RuleRegistry from '@civ-clone/core-rule/RuleRegistry';
12
10
  import Strategy from '../Strategy';
11
+ import PlayerActionBase from '@civ-clone/core-player/PlayerAction';
12
+ import StrategyRegistry from '../StrategyRegistry';
13
+ import TraitRegistry from '@civ-clone/core-civilization/TraitRegistry';
14
+ import Civilization from '@civ-clone/core-civilization/Civilization';
15
+ import { TraitFull, TraitHalf, TraitNone } from './lib/Traits';
16
+ import Leader from '@civ-clone/core-civilization/Leader';
17
+ import Trait from '@civ-clone/core-civilization/Trait';
13
18
 
14
19
  describe('Strategy', () => {
15
- const testPlayer = new Player();
20
+ const action = new PlayerActionBase(new Player(), null);
16
21
 
17
22
  it('should default to `Priority(Infinity)`', () =>
18
- expect(new Strategy().priority(testPlayer).value()).eq(Infinity));
19
-
20
- it('should stop calling `Routine`s after the first successful `attempt()`', async () => {
21
- const routineA = new RoutineFalse(),
22
- routineB = new RoutineTrue(),
23
- routineC = new RoutineTrue(),
24
- strategy = new Strategy(routineA, routineB, routineC),
25
- spyA = spy.on(routineA, 'attempt'),
26
- spyB = spy.on(routineB, 'attempt'),
27
- spyC = spy.on(routineC, 'attempt');
28
-
29
- expect(await strategy.attempt(new PlayerAction(testPlayer, null))).true;
30
- expect(spyA).called();
31
- expect(spyB).called();
32
- expect(spyC).not.called();
33
- });
23
+ expect(new Strategy().priority(action).value()).eq(Infinity));
34
24
 
35
- it('should respect `Routine` `Priority`s', async () => {
25
+ it('should respect `Strategy` `Priority`s', async () => {
36
26
  const ruleRegistry = new RuleRegistry(),
37
- routineA = new RoutineA(ruleRegistry),
38
- routineB = new RoutineB(ruleRegistry),
39
- strategy = new Strategy(routineA, routineB),
40
- spyA = spy.on(routineA, 'attempt'),
41
- spyB = spy.on(routineB, 'attempt');
27
+ strategyRegistry = new StrategyRegistry(),
28
+ strategyA = new StrategyA(ruleRegistry),
29
+ strategyB = new StrategyB(ruleRegistry),
30
+ spyA = spy.on(strategyA, 'attempt'),
31
+ spyB = spy.on(strategyB, 'attempt');
32
+
33
+ strategyRegistry.register(strategyA, strategyB);
42
34
 
43
35
  ruleRegistry.register(
44
36
  ...(
45
37
  [
46
- [RoutineA, High],
47
- [RoutineB, Normal],
48
- ] as [typeof Routine, typeof Priority][]
38
+ [StrategyA, High],
39
+ [StrategyB, Normal],
40
+ ] as [typeof Strategy, typeof Priority][]
49
41
  ).map(
50
- ([RoutineType, PriorityType]) =>
42
+ ([StrategyType, PriorityType]) =>
51
43
  new PriorityRule(
52
44
  new Criterion(
53
- (player: Player, routine: Routine) =>
54
- routine instanceof RoutineType
45
+ (action: PlayerActionBase, strategy: Strategy) =>
46
+ strategy instanceof StrategyType
55
47
  ),
56
48
  new Effect(() => new PriorityType())
57
49
  )
58
50
  )
59
51
  );
60
52
 
61
- expect(await strategy.attempt(new PlayerAction(testPlayer, null))).true;
53
+ expect(await strategyRegistry.attempt(action)).true;
62
54
  expect(spyA).called();
63
55
  expect(spyB).not.called();
64
56
  });
65
57
 
66
- it('should return false if there are no successfully executed `Routine`s', async () => {
67
- const routineA = new RoutineFalse(),
68
- routineB = new RoutineFalse(),
69
- routineC = new RoutineFalse(),
70
- strategy = new Strategy(routineA, routineB, routineC),
71
- spyA = spy.on(routineA, 'attempt'),
72
- spyB = spy.on(routineB, 'attempt'),
73
- spyC = spy.on(routineC, 'attempt');
58
+ it('should return false if there are no successfully executed `Strategy`s', async () => {
59
+ const strategyA = new StrategyFalse(),
60
+ strategyB = new StrategyFalse(),
61
+ strategyC = new StrategyFalse(),
62
+ strategyRegistry = new StrategyRegistry(),
63
+ spyA = spy.on(strategyA, 'attempt'),
64
+ spyB = spy.on(strategyB, 'attempt'),
65
+ spyC = spy.on(strategyC, 'attempt');
74
66
 
75
- expect(await strategy.attempt(new PlayerAction(testPlayer, null))).false;
67
+ strategyRegistry.register(strategyA, strategyB, strategyC);
68
+
69
+ expect(await strategyRegistry.attempt(action)).false;
76
70
  expect(spyA).called();
77
71
  expect(spyB).called();
78
72
  expect(spyC).called();
79
73
  });
74
+
75
+ it('should be possible to prioritise based on `Priority` `Rule`s', async () => {
76
+ const traitRegistry = new TraitRegistry(),
77
+ ruleRegistry = new RuleRegistry(),
78
+ civilization = new Civilization(),
79
+ traitNone = new TraitNone(Leader),
80
+ traitHalf = new TraitHalf(Leader),
81
+ traitFull = new TraitFull(Leader),
82
+ testPlayer = action.player(),
83
+ strategyA = new StrategyA(ruleRegistry),
84
+ strategyB = new StrategyB(ruleRegistry);
85
+
86
+ ruleRegistry.register(
87
+ ...(
88
+ [
89
+ [StrategyA, TraitFull, High],
90
+ [StrategyA, TraitHalf, Normal],
91
+ [StrategyA, TraitNone, Low],
92
+ [StrategyB, TraitFull, Low],
93
+ [StrategyB, TraitHalf, Normal],
94
+ [StrategyB, TraitNone, High],
95
+ ] as [typeof Strategy, typeof Trait, typeof Priority][]
96
+ ).map(
97
+ ([RoutineType, TraitType, PriorityType]) =>
98
+ new PriorityRule(
99
+ new Criterion(
100
+ (action: PlayerActionBase, strategy: Strategy) =>
101
+ strategy instanceof RoutineType
102
+ ),
103
+ new Criterion(
104
+ (action: PlayerActionBase) =>
105
+ action.player().civilization().leader() !== null
106
+ ),
107
+ new Criterion((action: PlayerActionBase) =>
108
+ traitRegistry
109
+ .getByLeader(
110
+ action
111
+ .player()
112
+ .civilization()
113
+ .leader()!
114
+ .sourceClass() as typeof Leader
115
+ )
116
+ .some((trait) => trait instanceof TraitType)
117
+ ),
118
+ new Effect(() => new PriorityType())
119
+ )
120
+ )
121
+ );
122
+
123
+ testPlayer.setCivilization(civilization);
124
+ civilization.setLeader(new Leader());
125
+ traitRegistry.register(traitFull);
126
+
127
+ expect(strategyA.priority(action).value()).equal(new High().value());
128
+ expect(strategyB.priority(action).value()).equal(new Low().value());
129
+
130
+ traitRegistry.unregister(traitFull);
131
+ traitRegistry.register(traitHalf);
132
+
133
+ expect(strategyA.priority(action).value()).equal(new Normal().value());
134
+ expect(strategyB.priority(action).value()).equal(new Normal().value());
135
+
136
+ traitRegistry.unregister(traitHalf);
137
+ traitRegistry.register(traitNone);
138
+
139
+ expect(strategyA.priority(action).value()).equal(new Low().value());
140
+ expect(strategyB.priority(action).value()).equal(new High().value());
141
+ });
80
142
  });
@@ -1,4 +1,4 @@
1
- import { RoutineFalse, RoutineTrue } from './lib/Routines';
1
+ import { StrategyFalse, StrategyTrue } from './lib/Strategies';
2
2
  import { expect, spy, use } from 'chai';
3
3
  import Player from '@civ-clone/core-player/Player';
4
4
  import { PlayerAction } from './lib/PlayerActions';
@@ -12,8 +12,8 @@ describe('StrategyRegistry', () => {
12
12
  const testPlayer = new Player();
13
13
 
14
14
  it('should filter inactive `Strategy`s', async () => {
15
- const strategyA = new Strategy(new RoutineTrue()),
16
- strategyB = new Strategy(new RoutineTrue()),
15
+ const strategyA = new StrategyTrue(),
16
+ strategyB = new Strategy(),
17
17
  strategyRegistry = new StrategyRegistry(),
18
18
  spyA = spy.on(strategyA, 'attempt'),
19
19
  spyB = spy.on(strategyB, 'attempt');
@@ -27,8 +27,8 @@ describe('StrategyRegistry', () => {
27
27
  });
28
28
 
29
29
  it('should stop calling `Strategy`s after the first successful `attempt()`', async () => {
30
- const strategyA = new Strategy(new RoutineTrue()),
31
- strategyB = new Strategy(new RoutineFalse()),
30
+ const strategyA = new StrategyTrue(),
31
+ strategyB = new StrategyFalse(),
32
32
  strategyRegistry = new StrategyRegistry(),
33
33
  spyA = spy.on(strategyA, 'attempt'),
34
34
  spyB = spy.on(strategyB, 'attempt');
@@ -42,9 +42,8 @@ describe('StrategyRegistry', () => {
42
42
  });
43
43
 
44
44
  it('should respect `Strategy` `Priority`s', async () => {
45
- const routine = new RoutineTrue(),
46
- strategyA = new Strategy(routine),
47
- strategyB = new Strategy(routine),
45
+ const strategyA = new StrategyTrue(),
46
+ strategyB = new StrategyTrue(),
48
47
  strategyRegistry = new StrategyRegistry(),
49
48
  spyA = spy.on(strategyA, 'attempt'),
50
49
  spyB = spy.on(strategyB, 'attempt');
@@ -58,9 +57,9 @@ describe('StrategyRegistry', () => {
58
57
  });
59
58
 
60
59
  it('should return false if there are no successfully executed `Strategy`s', async () => {
61
- const strategyA = new Strategy(new RoutineFalse()),
62
- strategyB = new Strategy(new RoutineFalse()),
63
- strategyC = new Strategy(new RoutineFalse()),
60
+ const strategyA = new StrategyFalse(),
61
+ strategyB = new StrategyFalse(),
62
+ strategyC = new StrategyFalse(),
64
63
  strategyRegistry = new StrategyRegistry(),
65
64
  spyA = spy.on(strategyA, 'attempt'),
66
65
  spyB = spy.on(strategyB, 'attempt'),
@@ -0,0 +1,9 @@
1
+ import Strategy from '../../Strategy';
2
+ export declare class StrategyTrue extends Strategy {
3
+ attempt(): boolean;
4
+ }
5
+ export declare class StrategyFalse extends Strategy {
6
+ attempt(): boolean;
7
+ }
8
+ export declare class StrategyA extends StrategyTrue {}
9
+ export declare class StrategyB extends StrategyTrue {}
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StrategyB = exports.StrategyA = exports.StrategyFalse = exports.StrategyTrue = void 0;
4
+ const Strategy_1 = require("../../Strategy");
5
+ class StrategyTrue extends Strategy_1.default {
6
+ attempt() {
7
+ return true;
8
+ }
9
+ }
10
+ exports.StrategyTrue = StrategyTrue;
11
+ class StrategyFalse extends Strategy_1.default {
12
+ attempt() {
13
+ return false;
14
+ }
15
+ }
16
+ exports.StrategyFalse = StrategyFalse;
17
+ class StrategyA extends StrategyTrue {
18
+ }
19
+ exports.StrategyA = StrategyA;
20
+ class StrategyB extends StrategyTrue {
21
+ }
22
+ exports.StrategyB = StrategyB;
23
+ //# sourceMappingURL=Strategies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Strategies.js","sourceRoot":"","sources":["Strategies.ts"],"names":[],"mappings":";;;AAAA,6CAAsC;AAEtC,MAAa,YAAa,SAAQ,kBAAQ;IACjC,OAAO;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAJD,oCAIC;AAED,MAAa,aAAc,SAAQ,kBAAQ;IAClC,OAAO;QACZ,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAJD,sCAIC;AAED,MAAa,SAAU,SAAQ,YAAY;CAAG;AAA9C,8BAA8C;AAE9C,MAAa,SAAU,SAAQ,YAAY;CAAG;AAA9C,8BAA8C"}
@@ -0,0 +1,17 @@
1
+ import Strategy from '../../Strategy';
2
+
3
+ export class StrategyTrue extends Strategy {
4
+ public attempt(): boolean {
5
+ return true;
6
+ }
7
+ }
8
+
9
+ export class StrategyFalse extends Strategy {
10
+ public attempt(): boolean {
11
+ return false;
12
+ }
13
+ }
14
+
15
+ export class StrategyA extends StrategyTrue {}
16
+
17
+ export class StrategyB extends StrategyTrue {}
package/tsconfig.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "compilerOptions": {
3
3
  "declaration": true,
4
4
  "lib": [
5
- "es2019"
5
+ "es2020"
6
6
  ],
7
7
  "module": "commonjs",
8
8
  "sourceMap": true,
package/Routine.d.ts DELETED
@@ -1,15 +0,0 @@
1
- import { RuleRegistry } from '@civ-clone/core-rule/RuleRegistry';
2
- import Player from '@civ-clone/core-player/Player';
3
- import PlayerAction from '@civ-clone/core-player/PlayerAction';
4
- import Priority from '@civ-clone/core-rule/Priority';
5
- export interface IRoutine {
6
- attempt(action: PlayerAction): boolean;
7
- priority(player: Player): Priority;
8
- }
9
- export declare class Routine implements IRoutine {
10
- #private;
11
- constructor(ruleRegistry?: RuleRegistry);
12
- attempt(action: PlayerAction): boolean;
13
- priority(player: Player): Priority;
14
- }
15
- export default Routine;
package/Routine.js DELETED
@@ -1,38 +0,0 @@
1
- "use strict";
2
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
- if (kind === "m") throw new TypeError("Private method is not writable");
4
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
- };
8
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
- };
13
- var _Routine_ruleRegistry;
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.Routine = void 0;
16
- const RuleRegistry_1 = require("@civ-clone/core-rule/RuleRegistry");
17
- const Priority_1 = require("@civ-clone/core-rule/Priority");
18
- const Priority_2 = require("./Rules/Priority");
19
- class Routine {
20
- constructor(ruleRegistry = RuleRegistry_1.instance) {
21
- _Routine_ruleRegistry.set(this, void 0);
22
- __classPrivateFieldSet(this, _Routine_ruleRegistry, ruleRegistry, "f");
23
- }
24
- attempt(action) {
25
- throw new TypeError('`attempt` must be overridden.');
26
- }
27
- priority(player) {
28
- return new Priority_1.default(
29
- // This takes the highest priority (lowest value) from all the applicable `PriorityRule`s
30
- Math.min(...__classPrivateFieldGet(this, _Routine_ruleRegistry, "f")
31
- .process(Priority_2.default, player, this)
32
- .map((priority) => priority.value()), Infinity));
33
- }
34
- }
35
- exports.Routine = Routine;
36
- _Routine_ruleRegistry = new WeakMap();
37
- exports.default = Routine;
38
- //# sourceMappingURL=Routine.js.map
package/Routine.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"Routine.js","sourceRoot":"","sources":["Routine.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,oEAG2C;AAG3C,4DAAqD;AACrD,+CAA4C;AAO5C,MAAa,OAAO;IAGlB,YAAY,eAA6B,uBAAoB;QAF7D,wCAA4B;QAG1B,uBAAA,IAAI,yBAAiB,YAAY,MAAA,CAAC;IACpC,CAAC;IAED,OAAO,CAAC,MAAoB;QAC1B,MAAM,IAAI,SAAS,CAAC,+BAA+B,CAAC,CAAC;IACvD,CAAC;IAED,QAAQ,CAAC,MAAc;QACrB,OAAO,IAAI,kBAAQ;QACjB,yFAAyF;QACzF,IAAI,CAAC,GAAG,CACN,GAAG,uBAAA,IAAI,6BAAc;aAClB,OAAO,CAAC,kBAAY,EAAE,MAAM,EAAE,IAAI,CAAC;aACnC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,EACtC,QAAQ,CACT,CACF,CAAC;IACJ,CAAC;CACF;AAtBD,0BAsBC;;AAED,kBAAe,OAAO,CAAC"}
package/Routine.ts DELETED
@@ -1,39 +0,0 @@
1
- import {
2
- RuleRegistry,
3
- instance as ruleRegistryInstance,
4
- } from '@civ-clone/core-rule/RuleRegistry';
5
- import Player from '@civ-clone/core-player/Player';
6
- import PlayerAction from '@civ-clone/core-player/PlayerAction';
7
- import Priority from '@civ-clone/core-rule/Priority';
8
- import PriorityRule from './Rules/Priority';
9
-
10
- export interface IRoutine {
11
- attempt(action: PlayerAction): boolean;
12
- priority(player: Player): Priority;
13
- }
14
-
15
- export class Routine implements IRoutine {
16
- #ruleRegistry: RuleRegistry;
17
-
18
- constructor(ruleRegistry: RuleRegistry = ruleRegistryInstance) {
19
- this.#ruleRegistry = ruleRegistry;
20
- }
21
-
22
- attempt(action: PlayerAction): boolean {
23
- throw new TypeError('`attempt` must be overridden.');
24
- }
25
-
26
- priority(player: Player): Priority {
27
- return new Priority(
28
- // This takes the highest priority (lowest value) from all the applicable `PriorityRule`s
29
- Math.min(
30
- ...this.#ruleRegistry
31
- .process(PriorityRule, player, this)
32
- .map((priority) => priority.value()),
33
- Infinity
34
- )
35
- );
36
- }
37
- }
38
-
39
- export default Routine;
@@ -1,93 +0,0 @@
1
- import { High, Low, Normal } from '@civ-clone/core-rule/Priorities';
2
- import { RoutineA, RoutineB } from './lib/Routines';
3
- import { TraitFull, TraitHalf, TraitNone } from './lib/Traits';
4
- import Civilization from '@civ-clone/core-civilization/Civilization';
5
- import Criterion from '@civ-clone/core-rule/Criterion';
6
- import Effect from '@civ-clone/core-rule/Effect';
7
- import Leader from '@civ-clone/core-civilization/Leader';
8
- import Player from '@civ-clone/core-player/Player';
9
- import Priority from '@civ-clone/core-rule/Priority';
10
- import PriorityRule from '../Rules/Priority';
11
- import Routine from '../Routine';
12
- import RuleRegistry from '@civ-clone/core-rule/RuleRegistry';
13
- import Trait from '@civ-clone/core-civilization/Trait';
14
- import TraitRegistry from '@civ-clone/core-civilization/TraitRegistry';
15
- import { expect } from 'chai';
16
-
17
- describe('Routine', () => {
18
- const testPlayer = new Player();
19
-
20
- it('should default to `Normal` `Priority`', () => {
21
- const routine = new Routine();
22
-
23
- expect(routine.priority(testPlayer).value()).equal(Infinity);
24
- });
25
-
26
- it('should be possible to prioritise based on `Priority` `Rule`s', async () => {
27
- const traitRegistry = new TraitRegistry(),
28
- ruleRegistry = new RuleRegistry(),
29
- civilization = new Civilization(),
30
- traitNone = new TraitNone(Leader),
31
- traitHalf = new TraitHalf(Leader),
32
- traitFull = new TraitFull(Leader),
33
- routine = new RoutineA(ruleRegistry),
34
- inverseRoutine = new RoutineB(ruleRegistry);
35
-
36
- ruleRegistry.register(
37
- ...(
38
- [
39
- [RoutineA, TraitFull, High],
40
- [RoutineA, TraitHalf, Normal],
41
- [RoutineA, TraitNone, Low],
42
- [RoutineB, TraitFull, Low],
43
- [RoutineB, TraitHalf, Normal],
44
- [RoutineB, TraitNone, High],
45
- ] as [typeof Routine, typeof Trait, typeof Priority][]
46
- ).map(
47
- ([RoutineType, TraitType, PriorityType]) =>
48
- new PriorityRule(
49
- new Criterion(
50
- (player: Player, routine: Routine) =>
51
- routine instanceof RoutineType
52
- ),
53
- new Criterion(
54
- (player: Player) => player.civilization().leader() !== null
55
- ),
56
- new Criterion((player: Player) =>
57
- traitRegistry
58
- .getByLeader(
59
- player.civilization().leader()!.sourceClass() as typeof Leader
60
- )
61
- .some((trait) => trait instanceof TraitType)
62
- ),
63
- new Effect(() => new PriorityType())
64
- )
65
- )
66
- );
67
-
68
- testPlayer.setCivilization(civilization);
69
- civilization.setLeader(new Leader());
70
- traitRegistry.register(traitFull);
71
-
72
- expect(routine.priority(testPlayer).value()).equal(new High().value());
73
- expect(inverseRoutine.priority(testPlayer).value()).equal(
74
- new Low().value()
75
- );
76
-
77
- traitRegistry.unregister(traitFull);
78
- traitRegistry.register(traitHalf);
79
-
80
- expect(routine.priority(testPlayer).value()).equal(new Normal().value());
81
- expect(inverseRoutine.priority(testPlayer).value()).equal(
82
- new Normal().value()
83
- );
84
-
85
- traitRegistry.unregister(traitHalf);
86
- traitRegistry.register(traitNone);
87
-
88
- expect(routine.priority(testPlayer).value()).equal(new Low().value());
89
- expect(inverseRoutine.priority(testPlayer).value()).equal(
90
- new High().value()
91
- );
92
- });
93
- });
@@ -1,9 +0,0 @@
1
- import Routine from '../../Routine';
2
- export declare class RoutineTrue extends Routine {
3
- attempt(): boolean;
4
- }
5
- export declare class RoutineFalse extends Routine {
6
- attempt(): boolean;
7
- }
8
- export declare class RoutineA extends RoutineTrue {}
9
- export declare class RoutineB extends RoutineTrue {}
@@ -1,23 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RoutineB = exports.RoutineA = exports.RoutineFalse = exports.RoutineTrue = void 0;
4
- const Routine_1 = require("../../Routine");
5
- class RoutineTrue extends Routine_1.default {
6
- attempt() {
7
- return true;
8
- }
9
- }
10
- exports.RoutineTrue = RoutineTrue;
11
- class RoutineFalse extends Routine_1.default {
12
- attempt() {
13
- return false;
14
- }
15
- }
16
- exports.RoutineFalse = RoutineFalse;
17
- class RoutineA extends RoutineTrue {
18
- }
19
- exports.RoutineA = RoutineA;
20
- class RoutineB extends RoutineTrue {
21
- }
22
- exports.RoutineB = RoutineB;
23
- //# sourceMappingURL=Routines.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Routines.js","sourceRoot":"","sources":["Routines.ts"],"names":[],"mappings":";;;AAAA,2CAAoC;AAEpC,MAAa,WAAY,SAAQ,iBAAO;IAC/B,OAAO;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAJD,kCAIC;AAED,MAAa,YAAa,SAAQ,iBAAO;IAChC,OAAO;QACZ,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAJD,oCAIC;AAED,MAAa,QAAS,SAAQ,WAAW;CAAG;AAA5C,4BAA4C;AAE5C,MAAa,QAAS,SAAQ,WAAW;CAAG;AAA5C,4BAA4C"}
@@ -1,17 +0,0 @@
1
- import Routine from '../../Routine';
2
-
3
- export class RoutineTrue extends Routine {
4
- public attempt(): boolean {
5
- return true;
6
- }
7
- }
8
-
9
- export class RoutineFalse extends Routine {
10
- public attempt(): boolean {
11
- return false;
12
- }
13
- }
14
-
15
- export class RoutineA extends RoutineTrue {}
16
-
17
- export class RoutineB extends RoutineTrue {}