mana-scribe 1.0.2 → 1.1.0

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
@@ -14,6 +14,7 @@ Supports both brace `{3}{R/U}` and shortform `3R/U` notation.
14
14
  - Converted mana cost
15
15
  - Color identity
16
16
  - Devotion
17
+ - Compare mana costs to evaluate if they are equal, greater than, or less than each other.
17
18
  - Extensible design — add new symbol types by subclassing
18
19
 
19
20
  Note: When the parser encounters an unrecognized symbol it stops parsing and returns the symbols it parsed so far. You can access the unparsed string component through the property `remainingStr`.
@@ -44,8 +45,24 @@ console.log(cost.cmc); // 3
44
45
  console.log(cost.colors); // ['W','U','B']
45
46
  ```
46
47
 
48
+ ### Comparison example
49
+ The `ManaCost` class supports equality and comparison operators under superset semantics:
50
+
51
+ - `equals(other)` → true if the costs are exactly the same
52
+ - `greaterThan(other)` → true if this cost includes all symbols of other plus additional ones, or generic mana cost is higher.
53
+ - `lessThan(other)` → true if this cost is a strict subset of other, or generic mana cost is lower.
54
+
55
+ ```js
56
+ const a = ManaCost.parse('{3}{B}{B}{B}');
57
+ const b = ManaCost.parse('{1}{B}{B}{B}');
58
+
59
+ console.log(a.equals(b)); // false
60
+ console.log(a.greaterThan(b)); // true
61
+ console.log(b.lessThan(a)); // true
62
+ ```
63
+
47
64
  ## Activation costs
48
- `ActivationCost` offers the same functionality as the `ManaCost` class, but supports additional symbols such as Tap, Untap, and Energy.
65
+ `ActivationCost` offers the same functionality as the `ManaCost` class, but supports additional symbols such as Tap, Untap, and Energy. It does not have comparison functions.
49
66
 
50
67
  ```js
51
68
  import { ActivationCost } from 'mana-scribe';
@@ -72,6 +89,7 @@ This is an early but complete implementation.
72
89
  Current priorities:
73
90
  - [x] Support core MTG symbols
74
91
  - [x] Add test coverage
92
+ - [x] Add cost comparison
75
93
  - [ ] Other improvements? TBD
76
94
 
77
95
  ## License
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mana-scribe",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "Library for parsing and querying Magic: The Gathering mana costs — with support for CMC, devotion, and color identity.",
5
5
  "keywords": [
6
6
  "mtg",
@@ -0,0 +1,50 @@
1
+ function toFrequencyMap(arr) {
2
+ const map = new Map();
3
+ for (const el of arr) {
4
+ if (el.type === 'genericMana' || el.type === 'infiniteMana') {
5
+ map.set('generic', (map.get('generic') || 0) + el.cmcValue());
6
+ } else {
7
+ const key = el.toString();
8
+ map.set(key, (map.get(key) || 0) + 1);
9
+ }
10
+ }
11
+ return map;
12
+ }
13
+
14
+ export function arrayEquals(arr1, arr2) {
15
+ const m1 = toFrequencyMap(arr1);
16
+ const m2 = toFrequencyMap(arr2);
17
+
18
+ if (m1.size !== m2.size) return false;
19
+ for (const [key, count] of m1.entries()) {
20
+ if ((m2.get(key) || 0) !== count) return false;
21
+ }
22
+ return true;
23
+ }
24
+
25
+ export function arrayGreaterThan(arr1, arr2) {
26
+ const m1 = toFrequencyMap(arr1);
27
+ const m2 = toFrequencyMap(arr2);
28
+
29
+ let larger = false;
30
+ for (const [key, count] of m2.entries()) {
31
+ if ((m1.get(key) || 0) < count) return false;
32
+ larger = larger || m1.get(key) > count;
33
+ }
34
+
35
+ return larger || m1.size > m2.size;
36
+ }
37
+
38
+ export function arrayLessThan(arr1, arr2) {
39
+ const m1 = toFrequencyMap(arr1);
40
+ const m2 = toFrequencyMap(arr2);
41
+
42
+ let smaller = false;
43
+ for (const [key, count] of m1.entries()) {
44
+ if ((m2.get(key) || 0) < count) return false;
45
+ smaller = smaller || (count < (m2.get(key) || 0));
46
+ }
47
+
48
+ return smaller || m1.size < m2.size;
49
+ }
50
+
@@ -13,6 +13,7 @@ import SnowManaSymbol from '../symbols/SnowManaSymbol.js';
13
13
  import ThreeColorHybridManaSymbol from '../symbols/ThreeColorHybridManaSymbol.js';
14
14
  import TwoColorHybridManaSymbol from '../symbols/TwoColorHybridManaSymbol.js';
15
15
  import VariableManaSymbol from '../symbols/VariableManaSymbol.js';
16
+ import {arrayEquals, arrayGreaterThan, arrayLessThan} from '../arrayComparison.js';
16
17
 
17
18
  export default class ManaCost extends Cost {
18
19
  static get allowedSymbols() {
@@ -35,4 +36,16 @@ export default class ManaCost extends Cost {
35
36
  return devotion + (sym.colors.includes(color) ? 1 : 0);
36
37
  }, 0);
37
38
  }
39
+
40
+ equals(other) {
41
+ return arrayEquals(this.symbols, other.symbols);
42
+ }
43
+
44
+ greaterThan(other) {
45
+ return arrayGreaterThan(this.symbols, other.symbols);
46
+ }
47
+
48
+ lessThan(other) {
49
+ return arrayLessThan(this.symbols, other.symbols);
50
+ }
38
51
  }