variants_test.go raw
1 package hexagram
2
3 import (
4 "testing"
5
6 "git.mleku.dev/mleku/dendrite/pkg/permutation"
7 "git.mleku.dev/mleku/dendrite/pkg/state"
8 )
9
10 func TestVariantIdentityMatchesCanonical(t *testing.T) {
11 for h := range uint8(64) {
12 got := LookupVariant(state.Hexagram(h), permutation.Identity)
13 want := Lookup(state.Hexagram(h))
14 if got != want {
15 t.Errorf("LookupVariant(%d, Identity) = %v, want %v", h, got, want)
16 }
17 }
18 }
19
20 func TestVariantTablesOperationDistribution(t *testing.T) {
21 // Each variant table should have the same multiset of operations
22 // as the canonical table, since permutation is a bijection on
23 // the 64 hexagrams.
24 canonicalDist := opDistribution(table)
25 for _, p := range permutation.All() {
26 dist := opDistribution(variantTables[p])
27 for op, count := range canonicalDist {
28 if dist[op] != count {
29 t.Errorf("variant %v: Op %d appears %d times, want %d",
30 p, op, dist[op], count)
31 }
32 }
33 }
34 }
35
36 func TestVariantTablesPriorityDistribution(t *testing.T) {
37 // Same check for priority distribution.
38 canonicalDist := priorityDistribution(table)
39 for _, p := range permutation.All() {
40 dist := priorityDistribution(variantTables[p])
41 for pri, count := range canonicalDist {
42 if dist[pri] != count {
43 t.Errorf("variant %v: Priority %d appears %d times, want %d",
44 p, pri, dist[pri], count)
45 }
46 }
47 }
48 }
49
50 func TestVariantHeavenAccretes(t *testing.T) {
51 // Heaven (101) is ideal growth under Identity. Under any permutation,
52 // the permuted Heaven should still map to OpAccrete because the
53 // variant table compensates.
54 for _, p := range permutation.All() {
55 permutedHeaven := p.ApplyTrigram(state.Heaven)
56 h := state.Hex(permutedHeaven, state.Earth)
57 rule := LookupVariant(h, p)
58 if rule.Op != OpAccrete {
59 t.Errorf("variant %v: permuted Heaven (%03b) / Earth should accrete, got Op %d",
60 p, uint8(permutedHeaven), rule.Op)
61 }
62 }
63 }
64
65 func opDistribution(tbl [64]Rule) map[Op]int {
66 dist := map[Op]int{}
67 for _, r := range tbl {
68 dist[r.Op]++
69 }
70 return dist
71 }
72
73 func priorityDistribution(tbl [64]Rule) map[Priority]int {
74 dist := map[Priority]int{}
75 for _, r := range tbl {
76 dist[r.Priority]++
77 }
78 return dist
79 }
80