From 5a4f1a68a8f9fe74fdfa1efac646cdd050931866 Mon Sep 17 00:00:00 2001 From: Steve Date: Tue, 17 May 2022 23:29:59 -0400 Subject: [PATCH] initial --- go.mod | 20 +++++++ go.sum | 52 +++++++++++++++++ main.go | 123 +++++++++++++++++++++++++++++++++++++++++ simulator/factory.go | 20 +++++++ simulator/plant.go | 29 ++++++++++ simulator/player.go | 22 ++++++++ simulator/pod.go | 69 +++++++++++++++++++++++ simulator/producer.go | 14 +++++ simulator/simulator.go | 82 +++++++++++++++++++++++++++ simulator/tile.go | 7 +++ 10 files changed, 438 insertions(+) create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go create mode 100644 simulator/factory.go create mode 100644 simulator/plant.go create mode 100644 simulator/player.go create mode 100644 simulator/pod.go create mode 100644 simulator/producer.go create mode 100644 simulator/simulator.go create mode 100644 simulator/tile.go diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d3119d6 --- /dev/null +++ b/go.mod @@ -0,0 +1,20 @@ +module git.saintnet.tech/stryan/spacetea + +go 1.17 + +require ( + github.com/atotto/clipboard v0.1.4 // indirect + github.com/charmbracelet/bubbles v0.10.3 // indirect + github.com/charmbracelet/bubbletea v0.20.0 // indirect + github.com/charmbracelet/lipgloss v0.5.0 // indirect + github.com/containerd/console v1.0.3 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 // indirect + github.com/muesli/reflow v0.3.0 // indirect + github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e // indirect + golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..cc70fa9 --- /dev/null +++ b/go.sum @@ -0,0 +1,52 @@ +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/charmbracelet/bubbles v0.10.3 h1:fKarbRaObLn/DCsZO4Y3vKCwRUzynQD9L+gGev1E/ho= +github.com/charmbracelet/bubbles v0.10.3/go.mod h1:jOA+DUF1rjZm7gZHcNyIVW+YrBPALKfpGVdJu8UiJsA= +github.com/charmbracelet/bubbletea v0.19.3/go.mod h1:VuXF2pToRxDUHcBUcPmCRUHRvFATM4Ckb/ql1rBl3KA= +github.com/charmbracelet/bubbletea v0.20.0 h1:/b8LEPgCbNr7WWZ2LuE/BV1/r4t5PyYJtDb+J3vpwxc= +github.com/charmbracelet/bubbletea v0.20.0/go.mod h1:zpkze1Rioo4rJELjRyGlm9T2YNou1Fm4LIJQSa5QMEM= +github.com/charmbracelet/harmonica v0.1.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= +github.com/charmbracelet/lipgloss v0.4.0/go.mod h1:vmdkHvce7UzX6xkyf4cca8WlwdQ5RQr8fzta+xl7BOM= +github.com/charmbracelet/lipgloss v0.5.0 h1:lulQHuVeodSgDez+3rGiuxlPVXSnhth442DATR2/8t8= +github.com/charmbracelet/lipgloss v0.5.0/go.mod h1:EZLha/HbzEt7cYqdFPovlqy5FZPj0xFhg5SaqxScmgs= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34= +github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= +github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 h1:kMlmsLSbjkikxQJ1IPwaM+7LJ9ltFu/fi8CRzvSnQmA= +github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= +github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/termenv v0.9.0/go.mod h1:R/LzAKf+suGs4IsO95y7+7DpFHO0KABgnZqtlyx2mBw= +github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= +github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739 h1:QANkGiGr39l1EESqrE0gZw0/AJNYzIvoGLhIoVYtluI= +github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e h1:w36l2Uw3dRan1K3TyXriXvY+6T56GNmlKGcqiQUJDfM= +golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20210422114643-f5beecf764ed h1:Ei4bQjjpYUsS4efOUz+5Nz++IVkHk87n2zBA0NxBWc0= +golang.org/x/term v0.0.0-20210422114643-f5beecf764ed/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 h1:EH1Deb8WZJ0xc0WK//leUHXcX9aLE5SymusoTmMZye8= +golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/main.go b/main.go new file mode 100644 index 0000000..0339bf4 --- /dev/null +++ b/main.go @@ -0,0 +1,123 @@ +package main + +import ( + "fmt" + "os" + "strconv" + "time" + + sim "git.saintnet.tech/stryan/spacetea/simulator" + "github.com/charmbracelet/bubbles/textinput" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" +) + +var style = lipgloss.NewStyle(). + Width(24). + Align(lipgloss.Center). + BorderStyle(lipgloss.NormalBorder()). + BorderForeground(lipgloss.Color("63")) + +type model struct { + s *sim.Simulator + input textinput.Model + window int +} +type beat struct{} + +func heartbeat() tea.Cmd { + return tea.Tick(time.Second, func(time.Time) tea.Msg { + return beat{} + }) +} +func initialModel() model { + ti := textinput.New() + ti.Placeholder = "input command" + ti.CharLimit = 156 + ti.Width = 20 + + return model{ + s: sim.NewSimulator(), + input: ti, + window: 1, + } +} +func (m model) Init() tea.Cmd { + m.s.Start() + return tea.Batch(textinput.Blink, heartbeat()) +} + +func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + var cmd tea.Cmd + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.Type { + case tea.KeyCtrlC: + m.s.Stop() + return m, tea.Quit + case tea.KeyEnter: + if m.window == 1 && m.input.Focused() { + m.s.Input(m.input.Value()) + m.input.Reset() + return m, nil + } else if m.window == 2 { + //place item + return m, nil + } + case tea.KeyRight: + m.s.Input("right") + return m, nil + case tea.KeyLeft: + m.s.Input("left") + return m, nil + case tea.KeyUp: + m.s.Input("up") + return m, nil + case tea.KeyDown: + m.s.Input("down") + return m, nil + case tea.KeyCtrlF: + if m.input.Focused() { + m.input.Blur() + } else { + m.input.Focus() + } + return m, nil + case tea.KeyRunes: + if !m.input.Focused() { + switch msg.String() { + case "g": + m.s.Input("get") + case "p": + if m.window == 1 { + m.window = 2 + } + return m, nil + } + return m, nil + } + } + case beat: + //heartbeat + return m, heartbeat() + } + m.input, cmd = m.input.Update(msg) + return m, cmd + +} + +func (m model) View() string { + var render string + if m.window == 1 { + display := lipgloss.JoinHorizontal(0, style.Render(m.s.Place.String()), style.Render(fmt.Sprintf("Player\n%v", m.s.Player.String()))) + render = fmt.Sprintf("%v\n%v\n%v\n", style.Render(fmt.Sprintf("Current Time: %v", strconv.Itoa(m.s.Time))), display, style.Render(m.input.View())) + } + return render +} + +func main() { + if err := tea.NewProgram(initialModel(), tea.WithAltScreen()).Start(); err != nil { + fmt.Printf("Uh oh, there was an error: %v\n", err) + os.Exit(1) + } +} diff --git a/simulator/factory.go b/simulator/factory.go new file mode 100644 index 0000000..b1929bf --- /dev/null +++ b/simulator/factory.go @@ -0,0 +1,20 @@ +package simulator + +//Factory is a game object that can hold resources and produce something +type Factory struct { + Resources map[int]int + Description string + Formula string +} + +func (f *Factory) Tick() { + panic("not implemented") // TODO: Implement +} + +func (f *Factory) Get() Produce { + panic("not implemented") // TODO: Implement +} + +func (f *Factory) String() string { + panic("not implemented") // TODO: Implement +} diff --git a/simulator/plant.go b/simulator/plant.go new file mode 100644 index 0000000..c6d7c42 --- /dev/null +++ b/simulator/plant.go @@ -0,0 +1,29 @@ +package simulator + +import ( + "strconv" +) + +//Plant is a plant that grows per tick +type Plant struct { + kind int + value int +} + +//Tick one iteration +func (p *Plant) Tick() { + p.value++ +} + +//Get produced plant +func (p *Plant) Get() Produce { + var pro Produce + pro.Value = p.value + pro.Kind = p.kind + p.value = 0 + return pro +} + +func (p *Plant) String() string { + return strconv.Itoa(p.kind) +} diff --git a/simulator/player.go b/simulator/player.go new file mode 100644 index 0000000..14ad3a2 --- /dev/null +++ b/simulator/player.go @@ -0,0 +1,22 @@ +package simulator + +import "fmt" + +//Player is a player controlled mob +type Player struct { + Resources map[int]int +} + +//NewPlayer initializes a player +func NewPlayer() *Player { + return &Player{Resources: make(map[int]int)} +} + +func (p *Player) String() string { + var res string + res += "Resources: \n" + for i := range p.Resources { + res += fmt.Sprintf("%v: %v", i, p.Resources[i]) + } + return res +} diff --git a/simulator/pod.go b/simulator/pod.go new file mode 100644 index 0000000..21cc994 --- /dev/null +++ b/simulator/pod.go @@ -0,0 +1,69 @@ +package simulator + +//Pod is a "location" where a player can move +type Pod struct { + Tiles [8][8]Tile +} + +func newPod() *Pod { + return &Pod{ + Tiles: [8][8]Tile{}, + } +} + +//Tick one iteration +func (p *Pod) Tick() { + for i := range p.Tiles { + for _, v := range p.Tiles[i] { + if v.Maker != nil { + v.Maker.Tick() + } + } + } +} + +//Place an item on a tile +func (p *Pod) Place(item Producer, x, y int) bool { + if p.Tiles[x][y].Maker == nil { + p.Tiles[x][y].Maker = item + return true + } + return false +} + +//MovePlayer swaps player tiles +func (p *Pod) MovePlayer(x, y, s, t int) bool { + if oob(x) || oob(y) || oob(s) || oob(t) { + return false + } + if p.Tiles[x][y].User == nil || p.Tiles[s][t].User != nil { + return false + } + p.Tiles[s][t].User = p.Tiles[x][y].User + p.Tiles[x][y].User = nil + return true +} + +func (p *Pod) String() string { + var res string + res += "##########\n" + for i := range p.Tiles { + res += "#" + for _, v := range p.Tiles[i] { + if v.User != nil { + res += "@" + } else if v.Maker != nil { + res += v.Maker.String() + } else { + res += "." + } + } + res += "#\n" + } + res += "##########" + return res +} + +func oob(i int) bool { + return (i >= 8 || i < 0) +} diff --git a/simulator/producer.go b/simulator/producer.go new file mode 100644 index 0000000..5dd453d --- /dev/null +++ b/simulator/producer.go @@ -0,0 +1,14 @@ +package simulator + +//Producer is a game object that producers a material +type Producer interface { + Tick() + Get() Produce + String() string +} + +//Produce is the result of a producer +type Produce struct { + Kind int + Value int +} diff --git a/simulator/simulator.go b/simulator/simulator.go new file mode 100644 index 0000000..620682b --- /dev/null +++ b/simulator/simulator.go @@ -0,0 +1,82 @@ +package simulator + +import ( + "time" +) + +//Simulator contains the main game state +type Simulator struct { + Place *Pod + Player *Player + Px, Py int + Time int + stop chan bool +} + +//NewSimulator creates a new simulator instance +func NewSimulator() *Simulator { + pod := newPod() + player := NewPlayer() + pod.Place(&Plant{1, 0}, 4, 4) + pod.Tiles[0][0].User = player + return &Simulator{pod, NewPlayer(), 0, 0, 0, make(chan bool)} +} + +//Start begins the simulation, non blocking +func (s *Simulator) Start() { + go s.main() +} + +//Stop ends the simulation +func (s *Simulator) Stop() { + s.stop <- true +} + +//Input sends a command to the simulator +func (s *Simulator) Input(cmd string) { + cur := s.Place.Tiles[s.Px][s.Py] + switch cmd { + case "get": + if cur.Maker != nil { + prod := cur.Maker.Get() + if prod.Kind != 0 && prod.Value > 0 { + s.Player.Resources[prod.Kind] = s.Player.Resources[prod.Kind] + prod.Value + } + } + case "left": + res := s.Place.MovePlayer(s.Px, s.Py, s.Px, s.Py-1) + if res { + s.Py = s.Py - 1 + } + case "right": + res := s.Place.MovePlayer(s.Px, s.Py, s.Px, s.Py+1) + if res { + s.Py = s.Py + 1 + } + case "up": + res := s.Place.MovePlayer(s.Px, s.Py, s.Px-1, s.Py) + if res { + s.Px = s.Px - 1 + } + case "down": + res := s.Place.MovePlayer(s.Px, s.Py, s.Px+1, s.Py) + if res { + s.Px = s.Px + 1 + } + case "quit": + s.Stop() + } +} + +func (s *Simulator) main() { + ticker := time.NewTicker(1 * time.Second) + for { + select { + case <-s.stop: + return + case <-ticker.C: + s.Time = s.Time + 1 + s.Place.Tick() + } + } +} diff --git a/simulator/tile.go b/simulator/tile.go new file mode 100644 index 0000000..9290157 --- /dev/null +++ b/simulator/tile.go @@ -0,0 +1,7 @@ +package simulator + +//Tile is a tile +type Tile struct { + Maker Producer + User *Player +}