/ src / interface / mod.go
mod.go
  1  package interface
  2  
  3  import (
  4  	"errors"
  5  	"fmt"
  6  	"sync"
  7  	"time"
  8  
  9  	"github.com/gdamore/tcell/v2"
 10  	"github.com/google/uuid"
 11  )
 12  
 13  // NEON_CYAN represents the neon cyan color.
 14  var NEON_CYAN = tcell.NewRGBColor(0, 255, 255)
 15  
 16  // DARK_CYAN represents the dark cyan color.
 17  var DARK_CYAN = tcell.NewRGBColor(0, 128, 128)
 18  
 19  // SYSTEM_BLUE represents the system blue color.
 20  var SYSTEM_BLUE = tcell.NewRGBColor(41, 171, 226)
 21  
 22  // NEON_YELLOW represents the neon yellow color.
 23  var NEON_YELLOW = tcell.NewRGBColor(255, 255, 0)
 24  
 25  // STARK_BLUE represents the stark blue color.
 26  var STARK_BLUE = tcell.NewRGBColor(0, 255, 255)
 27  
 28  // STARK_ACCENT represents the stark accent color.
 29  var STARK_ACCENT = tcell.NewRGBColor(0, 200, 255)
 30  
 31  // STARK_HIGHLIGHT represents the stark highlight color.
 32  var STARK_HIGHLIGHT = tcell.NewRGBColor(255, 200, 0)
 33  
 34  // ENERGY_COLOR represents the energy color.
 35  var ENERGY_COLOR = tcell.NewRGBColor(0, 255, 200)
 36  
 37  // WARNING_COLOR represents the warning color.
 38  var WARNING_COLOR = tcell.NewRGBColor(255, 100, 0)
 39  
 40  // SUCCESS_COLOR represents the success color.
 41  var SUCCESS_COLOR = tcell.NewRGBColor(0, 255, 150)
 42  
 43  // SimulationStats holds statistics about the simulation.
 44  type SimulationStats struct {
 45  	ActiveCells      int
 46  	Clusters         int
 47  	Generation       uint64
 48  	GridDepth        int
 49  	EnergyLevel      float64
 50  	ThoughtCount     int
 51  	PlanCount        int
 52  	MutationRate     float64
 53  	BandwidthUsage   float64
 54  	UpdatesPerSecond float64
 55  	TotalAPICalls    int
 56  	RuntimeSeconds   float64
 57  	CurrentBatch     int
 58  	TotalBatches     int
 59  	ProcessingPhase  ProcessingPhase
 60  	LatestThoughts   []string
 61  	PerformanceMetrics map[string]float64
 62  	StartTime        time.Time
 63  	LastUpdate       time.Time
 64  }
 65  
 66  // ProcessingPhase represents the current phase of the simulation.
 67  type ProcessingPhase int
 68  
 69  const (
 70  	ProcessingPhaseThoughtGeneration ProcessingPhase = iota
 71  	ProcessingPhasePlanCreation
 72  	ProcessingPhaseEvolution
 73  	ProcessingPhaseMemoryCompression
 74  	ProcessingPhaseActive
 75  )
 76  
 77  // CellGrid represents a grid of cells.
 78  type CellGrid struct {
 79  	Cells         [][]bool
 80  	EnergyLevels  [][]float64
 81  	GridID        uuid.UUID
 82  }
 83  
 84  // Interface represents the terminal interface for the simulation.
 85  type Interface struct {
 86  	screen       tcell.Screen
 87  	stats        SimulationStats
 88  	cellGrids    []CellGrid
 89  	quitChan     chan struct{}
 90  	statsMutex   sync.Mutex
 91  	gridsMutex   sync.Mutex
 92  }
 93  
 94  // NewInterface creates a new Interface.
 95  func NewInterface() (*Interface, error) {
 96  	screen, err := tcell.NewScreen()
 97  	if err != nil {
 98  		return nil, fmt.Errorf("failed to create screen: %v", err)
 99  	}
100  
101  	if err := screen.Init(); err != nil {
102  		return nil, fmt.Errorf("failed to initialize screen: %v", err)
103  	}
104  
105  	return &Interface{
106  		screen:       screen,
107  		stats:        SimulationStats{},
108  		cellGrids:    make([]CellGrid, 0),
109  		quitChan:     make(chan struct{}),
110  		statsMutex:   sync.Mutex{},
111  		gridsMutex:   sync.Mutex{},
112  	}, nil
113  }
114  
115  // ShouldQuit checks if the user has requested to quit.
116  func (i *Interface) ShouldQuit() (bool, error) {
117  	select {
118  	case <-i.quitChan:
119  		return true, nil
120  	default:
121  		ev := i.screen.PollEvent()
122  		switch ev := ev.(type) {
123  		case *tcell.EventKey:
124  			if ev.Key() == tcell.KeyCtrlC || ev.Rune() == 'q' {
125  				return true, nil
126  			}
127  		}
128  	}
129  	return false, nil
130  }
131  
132  // UpdateStats updates the simulation statistics.
133  func (i *Interface) UpdateStats(stats SimulationStats) {
134  	i.statsMutex.Lock()
135  	defer i.statsMutex.Unlock()
136  	i.stats = stats
137  }
138  
139  // UpdateGrids updates the cell grids.
140  func (i *Interface) UpdateGrids(grids []CellGrid) {
141  	i.gridsMutex.Lock()
142  	defer i.gridsMutex.Unlock()
143  	i.cellGrids = grids
144  }
145  
146  // Draw renders the interface.
147  func (i *Interface) Draw() error {
148  	i.screen.Clear()
149  
150  	// Draw the main layout
151  	width, height := i.screen.Size()
152  	mainLayout := []struct {
153  		x, y, w, h int
154  	}{
155  		{1, 1, width / 4, height - 2},
156  		{width / 4, 1, width / 4, height - 2},
157  		{width / 2, 1, width / 4, height - 2},
158  		{3 * width / 4, 1, width / 4, height - 2},
159  	}
160  
161  	// Draw view panels
162  	i.drawViewPanel("◢ TOP VIEW ◣", i.cellGrids[0], mainLayout[0])
163  	i.drawViewPanel("◢ FRONT VIEW ◣", i.cellGrids[1], mainLayout[1])
164  	i.drawViewPanel("◢ SIDE VIEW ◣", i.cellGrids[2], mainLayout[2])
165  
166  	// Draw system logs
167  	i.drawSystemLogs(i.stats.LatestThoughts, mainLayout[3])
168  
169  	// Draw status bar
170  	i.drawStatusBar()
171  
172  	i.screen.Show()
173  	return nil
174  }
175  
176  // drawViewPanel draws a view panel.
177  func (i *Interface) drawViewPanel(title string, grid CellGrid, area struct{ x, y, w, h int }) {
178  	style := tcell.StyleDefault.Foreground(NEON_CYAN).Bold(true)
179  	i.screen.SetContent(area.x, area.y, '◢', nil, style)
180  	i.screen.SetContent(area.x+1, area.y, ' ', nil, style)
181  	i.screen.SetContent(area.x+2, area.y, 'T', nil, style)
182  	i.screen.SetContent(area.x+3, area.y, 'O', nil, style)
183  	i.screen.SetContent(area.x+4, area.y, 'P', nil, style)
184  	i.screen.SetContent(area.x+5, area.y, ' ', nil, style)
185  	i.screen.SetContent(area.x+6, area.y, 'V', nil, style)
186  	i.screen.SetContent(area.x+7, area.y, 'I', nil, style)
187  	i.screen.SetContent(area.x+8, area.y, 'E', nil, style)
188  	i.screen.SetContent(area.x+9, area.y, 'W', nil, style)
189  	i.screen.SetContent(area.x+10, area.y, ' ', nil, style)
190  	i.screen.SetContent(area.x+11, area.y, '◣', nil, style)
191  
192  	// Draw the grid
193  	for y := 0; y < len(grid.Cells); y++ {
194  		for x := 0; x < len(grid.Cells[y]); x++ {
195  			if grid.Cells[y][x] {
196  				i.screen.SetContent(area.x+x, area.y+y+1, '■', nil, tcell.StyleDefault.Foreground(ENERGY_COLOR))
197  			}
198  		}
199  	}
200  }
201  
202  // drawSystemLogs draws the system logs.
203  func (i *Interface) drawSystemLogs(thoughts []string, area struct{ x, y, w, h int }) {
204  	style := tcell.StyleDefault.Foreground(NEON_CYAN).Bold(true)
205  	i.screen.SetContent(area.x, area.y, '◢', nil, style)
206  	i.screen.SetContent(area.x+1, area.y, ' ', nil, style)
207  	i.screen.SetContent(area.x+2, area.y, 'S', nil, style)
208  	i.screen.SetContent(area.x+3, area.y, 'Y', nil, style)
209  	i.screen.SetContent(area.x+4, area.y, 'S', nil, style)
210  	i.screen.SetContent(area.x+5, area.y, 'T', nil, style)
211  	i.screen.SetContent(area.x+6, area.y, 'E', nil, style)
212  	i.screen.SetContent(area.x+7, area.y, 'M', nil, style)
213  	i.screen.SetContent(area.x+8, area.y, ' ', nil, style)
214  	i.screen.SetContent(area.x+9, area.y, 'L', nil, style)
215  	i.screen.SetContent(area.x+10, area.y, 'O', nil, style)
216  	i.screen.SetContent(area.x+11, area.y, 'G', nil, style)
217  	i.screen.SetContent(area.x+12, area.y, 'S', nil, style)
218  	i.screen.SetContent(area.x+13, area.y, ' ', nil, style)
219  	i.screen.SetContent(area.x+14, area.y, '◣', nil, style)
220  
221  	for idx, thought := range thoughts {
222  		if idx >= area.h-1 {
223  			break
224  		}
225  		i.screen.SetContent(area.x, area.y+idx+1, '►', nil, tcell.StyleDefault.Foreground(NEON_YELLOW))
226  		i.screen.SetContent(area.x+1, area.y+idx+1, ' ', nil, style)
227  		for i, ch := range thought {
228  			if i >= area.w-2 {
229  				break
230  			}
231  			i.screen.SetContent(area.x+2+i, area.y+idx+1, ch, nil, tcell.StyleDefault.Foreground(SYSTEM_BLUE))
232  		}
233  	}
234  }
235  
236  // drawStatusBar draws the status bar.
237  func (i *Interface) drawStatusBar() {
238  	width, height := i.screen.Size()
239  	style := tcell.StyleDefault.Foreground(NEON_CYAN).Bold(true)
240  
241  	statusText := fmt.Sprintf(
242  		"CELLS: %d | GEN: %d | UPS: %.1f | %s",
243  		i.stats.ActiveCells,
244  		i.stats.Generation,
245  		i.stats.UpdatesPerSecond,
246  		i.getProcessingPhaseText(),
247  	)
248  
249  	for x, ch := range statusText {
250  		i.screen.SetContent(x, height-1, ch, nil, style)
251  	}
252  }
253  
254  // getProcessingPhaseText returns the text representation of the current processing phase.
255  func (i *Interface) getProcessingPhaseText() string {
256  	switch i.stats.ProcessingPhase {
257  	case ProcessingPhaseThoughtGeneration:
258  		return "◢ THINKING ◣"
259  	case ProcessingPhasePlanCreation:
260  		return "◢ PLANNING ◣"
261  	case ProcessingPhaseEvolution:
262  		return "◢ EVOLVING ◣"
263  	case ProcessingPhaseMemoryCompression:
264  		return "◢ COMPRESSING ◣"
265  	case ProcessingPhaseActive:
266  		return "◢ ACTIVE ◣"
267  	default:
268  		return "◢ UNKNOWN ◣"
269  	}
270  }
271  
272  // Cleanup cleans up the terminal interface.
273  func (i *Interface) Cleanup() error {
274  	i.screen.Fini()
275  	return nil
276  }