seed.go raw
1 package strategy
2
3 import (
4 "fmt"
5 "strings"
6
7 "git.mleku.dev/mleku/dendrite/pkg/axiom"
8 "git.mleku.dev/mleku/dendrite/pkg/lattice"
9 )
10
11 // Seed injects The Art of War into a lattice. Creates strategy-constrained
12 // sites and bonds strategy elements to them. Returns the number of elements
13 // bonded.
14 func Seed(l *lattice.Lattice) int {
15 // Sites per level per category.
16 sitesPerLevel := map[Level]int{
17 LevelChapter: 2, // 13×2 = 26 coarse sites
18 LevelPrinciple: 4, // 13×4 = 52 principle sites
19 LevelMaxim: 8, // 13×8 = 104 maxim sites
20 LevelTactic: 6, // 13×6 = 78 tactic sites
21 }
22 // Total: 260 strategy sites.
23
24 // Create strategy region: sites grouped by category.
25 type catNodes struct {
26 cat Category
27 nodes []*lattice.Node
28 }
29 var regions []catNodes
30
31 for cat := CatAssessment; cat <= CatIntelligence; cat++ {
32 cn := catNodes{cat: cat}
33 for lvl := LevelChapter; lvl <= LevelTactic; lvl++ {
34 count := sitesPerLevel[lvl]
35 for range count {
36 n := l.AddNode([]axiom.Constraint{
37 StrategyConstraint{Cat: cat, MinLevel: lvl},
38 })
39 n.SetEnergy(true)
40 cn.nodes = append(cn.nodes, n)
41 }
42 }
43 regions = append(regions, cn)
44 }
45
46 // Ring topology within each category.
47 for _, cn := range regions {
48 for i := range cn.nodes {
49 l.Connect(cn.nodes[i], cn.nodes[(i+1)%len(cn.nodes)])
50 }
51 }
52
53 // Cross-category bridges: connect every 5th node between adjacent categories.
54 for i := 0; i < len(regions)-1; i++ {
55 a := regions[i].nodes
56 b := regions[i+1].nodes
57 step := max(1, min(len(a), len(b))/4)
58 for k := 0; k < min(len(a), len(b)); k += step {
59 l.Connect(a[k], b[k])
60 }
61 }
62 // Close the ring: connect last category to first.
63 if len(regions) > 1 {
64 a := regions[len(regions)-1].nodes
65 b := regions[0].nodes
66 step := max(1, min(len(a), len(b))/4)
67 for k := 0; k < min(len(a), len(b)); k += step {
68 l.Connect(a[k], b[k])
69 }
70 }
71
72 // Digest the embedded text and bond elements to strategy sites.
73 elements := DigestEmbedded()
74 bonded := 0
75 for elem := range elements {
76 // Try to bond at a matching site.
77 for _, cn := range regions {
78 found := false
79 for _, n := range cn.nodes {
80 if !n.Occupied() && n.Admits(elem) {
81 if n.Bond(elem) {
82 bonded++
83 found = true
84 break
85 }
86 }
87 }
88 if found {
89 break
90 }
91 }
92 }
93
94 totalSites := 0
95 for _, cn := range regions {
96 totalSites += len(cn.nodes)
97 }
98
99 fmt.Printf("strategy: %d elements bonded to %d sites (13 chapters)\n", bonded, totalSites)
100 return bonded
101 }
102
103 // SeedFromText injects custom strategic text (in the same format as
104 // artofwar.txt) into a lattice.
105 func SeedFromText(l *lattice.Lattice, text string) int {
106 elements := (Enzyme{}).Digest(strings.NewReader(text))
107 bonded := 0
108 for elem := range elements {
109 // Find any strategy-typed vacant node.
110 for _, n := range l.Nodes() {
111 if !n.Occupied() && n.Admits(elem) {
112 if n.Bond(elem) {
113 bonded++
114 break
115 }
116 }
117 }
118 }
119 return bonded
120 }
121