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