Extremely simple sand cellular automata written in Go
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 136 lines 2.2 kB view raw
1package main 2 3import ( 4 "fmt" 5 "math/rand/v2" 6 "os" 7 "time" 8 9 tea "github.com/charmbracelet/bubbletea" 10 "golang.org/x/term" 11) 12 13type state struct { 14 board [][]CellType 15 rows int 16 cols int 17} 18 19type tickMsg time.Time 20 21type CellType int 22 23const ( 24 CellAir CellType = iota 25 CellSolid 26) 27 28func NewState(rows int, cols int) state { 29 matrix := make([][]CellType, rows) 30 31 for y := range matrix { 32 matrix[y] = make([]CellType, cols) 33 } 34 35 for y := range matrix { 36 for x := range matrix { 37 if rand.IntN(2) == 0 { 38 matrix[y][x] = CellAir 39 } else { 40 matrix[y][x] = CellSolid 41 } 42 } 43 } 44 45 return state{ 46 board: matrix, 47 rows: rows, 48 cols: cols, 49 } 50} 51 52func (s state) Init() tea.Cmd { 53 return tea.Batch( 54 tick(), 55 tea.EnterAltScreen, 56 ) 57} 58 59func tick() tea.Cmd { 60 return tea.Tick(35*time.Millisecond, func(t time.Time) tea.Msg { 61 return tickMsg(t) 62 }) 63} 64 65func (s *state) updateBoard() { 66 for y := range s.board { 67 for x := range s.board[y] { 68 if s.board[y][x] == CellSolid { 69 if s.inBoard(x, y+1) && s.board[y+1][x] == CellAir { 70 s.board[y][x] = CellAir 71 s.board[y+1][x] = CellSolid 72 } else if s.inBoard(x+1, y+1) && s.board[y+1][x+1] == CellAir { 73 s.board[y+1][x+1] = 1 74 s.board[y][x] = 0 75 } 76 } 77 } 78 } 79} 80 81func (s state) Update(msg tea.Msg) (tea.Model, tea.Cmd) { 82 switch msg := msg.(type) { 83 case tea.KeyMsg: 84 switch msg.String() { 85 case "ctrl+c", "q": 86 return s, tea.Quit 87 } 88 case tickMsg: 89 s.updateBoard() 90 return s, tick() 91 } 92 93 return s, nil 94} 95 96func (s state) inBoard(x int, y int) bool { 97 if (x >= 0 && x < s.cols) && (y >= 0 && y < s.rows) { 98 return true 99 } 100 101 return false 102} 103 104func (s state) View() string { 105 board := "" 106 for y := range s.board { 107 row := "" 108 109 for x := range s.board[y] { 110 if s.board[y][x] == CellAir { 111 row += "\x1b[0;30m█" 112 } else { 113 row += "\x1b[0;32m█" 114 } 115 } 116 117 row += "\n" 118 board += row 119 } 120 121 return board 122} 123 124func main() { 125 cols, rows, err := term.GetSize(int(os.Stdin.Fd())) 126 if err != nil { 127 panic(fmt.Errorf("Error whilst getting terminal size: %w", err)) 128 } 129 130 p := tea.NewProgram(NewState(rows, cols)) 131 132 if _, err := p.Run(); err != nil { 133 fmt.Printf("Error while running sim: %v", err) 134 os.Exit(1) 135 } 136}