add converters

This commit is contained in:
stryan 2022-05-19 17:09:46 -04:00
parent ab12a9b26a
commit 7e8e241164
13 changed files with 231 additions and 44 deletions

View File

@ -99,9 +99,11 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case "g": case "g":
m.s.Input("get") m.s.Input("get")
case "p": case "p":
var res []string var res []sim.ItemEntry
for k := range m.s.Player.Resources { for _, k := range sim.GlobalItemList {
res = append(res, strconv.Itoa(k)) if m.s.Player.Resources[k] != 0 {
res = append(res, sim.Lookup(k))
}
} }
return newPlaceModel(res, nil), nil return newPlaceModel(res, nil), nil
} }
@ -116,7 +118,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
func (m model) View() string { func (m model) View() string {
var render string var render string
display := lipgloss.JoinHorizontal(0, style.Render(m.s.Place.String()), style.Render(fmt.Sprintf("Player\n%v", m.s.Player.String()))) display := lipgloss.JoinHorizontal(0, style.Render(m.s.Place.String()), style.Render(fmt.Sprintf("%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())) 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 return render
} }

View File

@ -1,16 +1,21 @@
package main package main
import ( import (
sim "git.saintnet.tech/stryan/spacetea/simulator"
"github.com/charmbracelet/bubbles/list" "github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
) )
var docStyle = lipgloss.NewStyle().Margin(1, 2)
type item struct { type item struct {
title, desc string title, desc, id string
} }
func (i item) Title() string { return i.title } func (i item) Title() string { return i.title }
func (i item) Description() string { return i.desc } func (i item) Description() string { return i.desc }
func (i item) ID() string { return i.id }
func (i item) FilterValue() string { return i.title } func (i item) FilterValue() string { return i.title }
type placeModel struct { type placeModel struct {
@ -21,17 +26,17 @@ type placeMsg string
func (p placeModel) buildPlaceMsg() tea.Msg { func (p placeModel) buildPlaceMsg() tea.Msg {
i := p.list.SelectedItem().(item) i := p.list.SelectedItem().(item)
return placeMsg(i.Title()) return placeMsg(i.ID())
} }
func newPlaceModel(entries []string, m tea.Model) placeModel { func newPlaceModel(entries []sim.ItemEntry, m tea.Model) placeModel {
var p placeModel var p placeModel
items := []list.Item{} items := []list.Item{}
for _, v := range entries { for _, v := range entries {
items = append(items, item{v, v}) items = append(items, item{v.Name(), "no description", v.ID()})
} }
//w,h //w,h
p.list = list.New(items, list.NewDefaultDelegate(), 0, 0) p.list = list.New(items, list.NewDefaultDelegate(), 32, 32)
p.list.Title = "What do you want to place?" p.list.Title = "What do you want to place?"
p.list.DisableQuitKeybindings() p.list.DisableQuitKeybindings()
return p return p
@ -48,16 +53,17 @@ func (p placeModel) Init() tea.Cmd {
func (p placeModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { func (p placeModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) { switch msg := msg.(type) {
case tea.WindowSizeMsg: case tea.WindowSizeMsg:
p.list.SetWidth(msg.Width) h, v := docStyle.GetFrameSize()
p.list.SetSize(msg.Width-h, msg.Height-v)
return p, nil return p, nil
case tea.KeyMsg: case tea.KeyMsg:
switch keypress := msg.String(); keypress { switch keypress := msg.String(); keypress {
case "ctrl-c": case "ctrl-c":
return p, tea.Quit return p, tea.Quit
case "esc": case "esc":
return initMainscreen(), nil return initMainscreen(), heartbeat()
case "enter": case "enter":
return initMainscreen(), p.buildPlaceMsg return initMainscreen(), tea.Batch(p.buildPlaceMsg, heartbeat())
} }
} }

7
simulator/consumer.go Normal file
View File

@ -0,0 +1,7 @@
package simulator
//Consumer is a game object that consumes resources
type Consumer interface {
Object
Tick()
}

71
simulator/converter.go Normal file
View File

@ -0,0 +1,71 @@
package simulator
import (
"fmt"
)
//Converter is a object that converts one item into another per tick
type Converter struct {
kind itemType
rate int
source itemType
output itemType
owner *Player
}
func newConverter(k itemType, o *Player) *Converter {
return &Converter{
kind: k,
rate: getConverter(k).rate,
source: getConverter(k).source,
output: getConverter(k).output,
owner: o,
}
}
//Tick one iteration
func (c *Converter) Tick() {
if c.owner.Resources[c.source] > c.rate {
c.owner.Resources[c.source] = c.owner.Resources[c.source] - c.rate
c.owner.Resources[c.output] = c.owner.Resources[c.output] + 1
}
}
func (c *Converter) String() string {
return Lookup(c.kind).Render()
}
//Describe returns human useful string
func (c *Converter) Describe() string {
output := getConverter(c.kind).output
return fmt.Sprintf("a %v converter that outputs %v", Lookup(c.kind).Name(), Lookup(output).Name())
}
//Type returns consumer
func (c *Converter) Type() ObjectType {
return consumerObject
}
func getConverter(k itemType) converterEntry {
return Lookup(k).(converterEntry)
}
type converterEntry struct {
id itemType
rate int
name string
source itemType
output itemType
}
func (c converterEntry) Name() string {
return c.name
}
func (c converterEntry) Render() string {
return "m"
}
func (c converterEntry) ID() string {
return c.id.String()
}

View File

@ -3,18 +3,23 @@ package simulator
//Factory is a game object that can hold resources and produce something //Factory is a game object that can hold resources and produce something
type Factory struct { type Factory struct {
Resources map[int]int Resources map[int]int
value int
outputType int
Description string Description string
Formula string formula string
} }
//Tick a beat
func (f *Factory) Tick() { func (f *Factory) Tick() {
panic("not implemented") // TODO: Implement panic("not implemented") // TODO: Implement
} }
//Get produce
func (f *Factory) Get() Produce { func (f *Factory) Get() Produce {
panic("not implemented") // TODO: Implement panic("not implemented") // TODO: Implement
} }
//String
func (f *Factory) String() string { func (f *Factory) String() string {
panic("not implemented") // TODO: Implement panic("not implemented") // TODO: Implement
} }

39
simulator/item_table.go Normal file
View File

@ -0,0 +1,39 @@
package simulator
import "strconv"
//ItemEntry is a human/ui friendly item description
type ItemEntry interface {
Name() string
Render() string
ID() string
}
type itemType int
func (i itemType) String() string {
return strconv.Itoa(int(i))
}
const (
itemPlantTea itemType = iota + 1
itemPlantWood
convertPulper
)
//GlobalItemList of all items
var GlobalItemList = []itemType{itemPlantTea, itemPlantWood, convertPulper}
//Lookup returns a human friendly item entry
func Lookup(id itemType) ItemEntry {
switch id {
case itemPlantTea:
return plantEntry{itemPlantTea, 3, "tea"}
case itemPlantWood:
return plantEntry{itemPlantWood, 10, "wood"}
case convertPulper:
return converterEntry{convertPulper, 5, "teaConverter", itemPlantTea, itemPlantWood}
}
return nil
}

17
simulator/object.go Normal file
View File

@ -0,0 +1,17 @@
package simulator
//Object is anything that can be placed in a pod
type Object interface {
Type() ObjectType
Tick()
String() string
Describe() string
}
//ObjectType is what kind of game object it is
type ObjectType int
const (
producerObject ObjectType = iota
consumerObject
)

View File

@ -7,23 +7,29 @@ import (
//Plant is a plant that grows per tick //Plant is a plant that grows per tick
type Plant struct { type Plant struct {
kind int kind itemType
value int value int
growth int growth int
rate int
} }
func newPlant(k int) *Plant { func getPlant(k itemType) plantEntry {
return Lookup(k).(plantEntry)
}
func newPlant(k itemType) *Plant {
return &Plant{ return &Plant{
kind: k, kind: k,
value: 0, value: 0,
growth: 0, growth: 0,
rate: getPlant(k).rate,
} }
} }
//Tick one iteration //Tick one iteration
func (p *Plant) Tick() { func (p *Plant) Tick() {
p.growth++ p.growth++
if p.growth > 10 { if p.growth > p.rate {
p.value++ p.value++
p.growth = 0 p.growth = 0
} }
@ -39,10 +45,33 @@ func (p *Plant) Get() Produce {
} }
func (p *Plant) String() string { func (p *Plant) String() string {
return strconv.Itoa(p.kind) return Lookup(p.kind).Render()
} }
//Describe returns a human useful string //Describe returns a human useful string
func (p *Plant) Describe() string { func (p *Plant) Describe() string {
return fmt.Sprintf("A %v plant with %v value", strconv.Itoa(p.kind), strconv.Itoa(p.value)) return fmt.Sprintf("a %v plant with %v value", Lookup(p.kind).Name(), strconv.Itoa(p.value))
}
//Type returns producer
func (p *Plant) Type() ObjectType {
return producerObject
}
type plantEntry struct {
id itemType
rate int
name string
}
func (p plantEntry) Render() string {
return "w"
}
func (p plantEntry) Name() string {
return p.name
}
func (p plantEntry) ID() string {
return p.id.String()
} }

View File

@ -6,20 +6,22 @@ import (
//Player is a player controlled mob //Player is a player controlled mob
type Player struct { type Player struct {
Resources map[int]int Resources map[itemType]int
CurrentTile *Tile CurrentTile *Tile
} }
//NewPlayer initializes a player //NewPlayer initializes a player
func NewPlayer() *Player { func NewPlayer() *Player {
return &Player{Resources: make(map[int]int)} return &Player{Resources: make(map[itemType]int)}
} }
func (p *Player) String() string { func (p *Player) String() string {
var res string var res string
res += "Resources: \n" res += "Resources: \n"
for i := range p.Resources { for _, i := range GlobalItemList {
res += fmt.Sprintf("%v: %v", i, p.Resources[i]) if p.Resources[i] != 0 {
res += fmt.Sprintf("%v: %v\n", Lookup(i).Name(), p.Resources[i])
}
} }
res += "\nLocation: \n" res += "\nLocation: \n"
if p.CurrentTile != nil { if p.CurrentTile != nil {

View File

@ -15,17 +15,17 @@ func newPod() *Pod {
func (p *Pod) Tick() { func (p *Pod) Tick() {
for i := range p.Tiles { for i := range p.Tiles {
for _, v := range p.Tiles[i] { for _, v := range p.Tiles[i] {
if v.Maker != nil { if v.Building != nil {
v.Maker.Tick() v.Building.Tick()
} }
} }
} }
} }
//Place an item on a tile //Place an item on a tile
func (p *Pod) Place(item Producer, x, y int) bool { func (p *Pod) Place(item Object, x, y int) bool {
if p.Tiles[x][y].Maker == nil { if p.Tiles[x][y].Building == nil {
p.Tiles[x][y].Maker = item p.Tiles[x][y].Building = item
return true return true
} }
return false return false
@ -52,8 +52,8 @@ func (p *Pod) String() string {
for _, v := range p.Tiles[i] { for _, v := range p.Tiles[i] {
if v.User != nil { if v.User != nil {
res += "@" res += "@"
} else if v.Maker != nil { } else if v.Building != nil {
res += v.Maker.String() res += v.Building.String()
} else { } else {
res += "." res += "."
} }

View File

@ -2,6 +2,7 @@ package simulator
//Producer is a game object that producers a material //Producer is a game object that producers a material
type Producer interface { type Producer interface {
Object
Tick() Tick()
Get() Produce Get() Produce
String() string String() string
@ -10,6 +11,6 @@ type Producer interface {
//Produce is the result of a producer //Produce is the result of a producer
type Produce struct { type Produce struct {
Kind int Kind itemType
Value int Value int
} }

View File

@ -1,7 +1,6 @@
package simulator package simulator
import ( import (
"strconv"
"strings" "strings"
"time" "time"
) )
@ -19,9 +18,10 @@ type Simulator struct {
func NewSimulator() *Simulator { func NewSimulator() *Simulator {
pod := newPod() pod := newPod()
player := NewPlayer() player := NewPlayer()
pod.Place(newPlant(1), 4, 4) pod.Place(newPlant(itemPlantTea), 4, 4)
pod.Tiles[0][0].User = player pod.Tiles[0][0].User = player
return &Simulator{pod, NewPlayer(), 0, 0, 0, make(chan bool)} player.Resources[convertPulper] = 1
return &Simulator{pod, player, 0, 0, 0, make(chan bool)}
} }
//Start begins the simulation, non blocking //Start begins the simulation, non blocking
@ -40,21 +40,29 @@ func (s *Simulator) Input(cmd string) {
cmdS := strings.Split(cmd, " ") cmdS := strings.Split(cmd, " ")
switch cmdS[0] { switch cmdS[0] {
case "get": case "get":
if cur.Maker != nil { if cur.Building != nil {
prod := cur.Maker.Get() if cur.Building.Type() == producerObject {
build := cur.Building.(Producer)
prod := build.Get()
if prod.Kind != 0 && prod.Value > 0 { if prod.Kind != 0 && prod.Value > 0 {
s.Player.Resources[prod.Kind] = s.Player.Resources[prod.Kind] + prod.Value s.Player.Resources[prod.Kind] = s.Player.Resources[prod.Kind] + prod.Value
} }
} }
}
case "place": case "place":
if len(cmdS) < 2 { if len(cmdS) < 2 {
return return
} }
item := cmdS[1] item := cmdS[1]
if item == strconv.Itoa(1) { if item == itemPlantTea.String() {
res := s.Place.Place(newPlant(1), s.Px, s.Py) res := s.Place.Place(newPlant(itemPlantTea), s.Px, s.Py)
if res { if res {
s.Player.Resources[1] = s.Player.Resources[1] - 1 s.Player.Resources[itemPlantTea] = s.Player.Resources[itemPlantTea] - 1
}
} else if item == convertPulper.String() {
res := s.Place.Place(newConverter(convertPulper, s.Player), s.Px, s.Py)
if res {
s.Player.Resources[convertPulper] = s.Player.Resources[convertPulper] - 1
} }
} }

View File

@ -6,14 +6,14 @@ import (
//Tile is a tile //Tile is a tile
type Tile struct { type Tile struct {
Maker Producer Building Object
User *Player User *Player
} }
func (t *Tile) String() string { func (t *Tile) String() string {
var res string var res string
if t.Maker != nil { if t.Building != nil {
res += fmt.Sprintf("There is a %v here\n", t.Maker.Describe()) res += fmt.Sprintf("There is a %v here\n", t.Building.Describe())
} else { } else {
res += "Nothing here" res += "Nothing here"
} }