1
0
Fork 0
spacetraders/golang/pkg/agent/trading.go

147 lines
4.6 KiB
Go

package agent
import (
"fmt"
"slices"
"git.adyxax.org/adyxax/spacetraders/golang/pkg/model"
)
type TradeGoodNotFoundError struct{}
func (err *TradeGoodNotFoundError) Error() string {
return "trade good not found"
}
func (a *agent) buyTradeGood(ship *model.Ship, tradeGoodToBuy string) error {
if ship.Cargo.Units == ship.Cargo.Capacity {
return nil
}
// list markets would sell our goods
markets, err := a.listMarketsInSystem(ship.Nav.SystemSymbol)
if err != nil {
return fmt.Errorf("failed to list markets in system %s: %w", ship.Nav.SystemSymbol, err)
}
markets = slices.DeleteFunc(markets, func(market model.Market) bool {
for _, item := range market.Exports {
if item.Symbol == tradeGoodToBuy {
return false
}
}
return true
})
if len(markets) == 0 {
return &TradeGoodNotFoundError{}
}
// find the closest place to buy TODO
waypoint, err := a.client.GetWaypoint(ship.Nav.WaypointSymbol)
if err != nil {
return fmt.Errorf("failed to get waypoint %s: %w", ship.Nav.WaypointSymbol, err)
}
waypoints := make([]model.Waypoint, 0)
for i := range markets {
waypoint, err := a.client.GetWaypoint(markets[i].Symbol)
if err != nil {
return fmt.Errorf("failed to get waypoint %s: %w", markets[i].Symbol, err)
}
waypoints = append(waypoints, *waypoint)
}
sortByDistanceFrom(waypoint, waypoints)
// Go there and refresh our market data
if err := a.navigate(ship, waypoints[0].Symbol); err != nil {
return fmt.Errorf("failed to navigate to %s: %w", waypoints[0].Symbol, err)
}
if err := a.client.Dock(ship); err != nil {
return fmt.Errorf("failed to dock: %w", err)
}
market, err := a.client.GetMarket(waypoints[0].Symbol, a.ships)
if err != nil {
return fmt.Errorf("failed to get market %s: %w", waypoints[0].Symbol, err)
}
// Buy until full
for _, tradeGood := range market.TradeGoods {
if tradeGood.Type == "EXPORT" && tradeGood.Symbol == tradeGoodToBuy {
for ship.Cargo.Units < ship.Cargo.Capacity {
increment := min(ship.Cargo.Capacity-ship.Cargo.Units, tradeGood.TradeVolume)
if err := a.client.Purchase(ship, tradeGoodToBuy, increment); err != nil {
return fmt.Errorf("failed to purchase %d units of %s: %w", increment, tradeGoodToBuy, err)
}
}
break
}
}
return a.buyTradeGood(ship, tradeGoodToBuy)
}
func (a *agent) sellEverythingExcept(ship *model.Ship, keep string) error {
// First lets see what we need to sell
var inventoryItems []model.InventoryItem
for _, item := range ship.Cargo.Inventory {
if item.Symbol != keep {
inventoryItems = append(inventoryItems, item)
}
}
if len(inventoryItems) == 0 {
return nil
}
// list markets would buy our goods
markets, err := a.listMarketsInSystem(ship.Nav.SystemSymbol)
if err != nil {
return fmt.Errorf("failed to list markets in system %s: %w", ship.Nav.SystemSymbol, err)
}
markets = slices.DeleteFunc(markets, func(market model.Market) bool {
for _, marketItem := range market.Imports {
for _, inventoryItem := range inventoryItems {
if marketItem.Symbol == inventoryItem.Symbol {
return false
}
}
}
return true
})
if len(markets) == 0 {
return nil
}
// find the closest place to sell something TODO
waypoint, err := a.client.GetWaypoint(ship.Nav.WaypointSymbol)
if err != nil {
return fmt.Errorf("failed to get nav waypoint %s: %w", ship.Nav.WaypointSymbol, err)
}
waypoints := make([]model.Waypoint, 0)
for i := range markets {
waypoint, err := a.client.GetWaypoint(markets[i].Symbol)
if err != nil {
return fmt.Errorf("failed to get waypoint %s: %w", markets[i].Symbol, err)
}
waypoints = append(waypoints, *waypoint)
}
sortByDistanceFrom(waypoint, waypoints)
// Go there and refresh our market data
if err := a.navigate(ship, waypoints[0].Symbol); err != nil {
return fmt.Errorf("failed to navigate to %s: %w", waypoints[0].Symbol, err)
}
if err := a.client.Dock(ship); err != nil {
return fmt.Errorf("failed to dock: %w", err)
}
market, err := a.client.GetMarket(waypoints[0].Symbol, a.ships)
if err != nil {
return fmt.Errorf("failed to get market %s: %w", waypoints[0].Symbol, err)
}
// sell everything we can
for _, cargoItem := range inventoryItems {
units := cargoItem.Units
for _, tradeGood := range market.TradeGoods {
if tradeGood.Type == "IMPORT" && tradeGood.Symbol == cargoItem.Symbol {
for units > 0 {
increment := min(units, tradeGood.TradeVolume)
if err := a.client.Sell(ship, cargoItem.Symbol, increment); err != nil {
return fmt.Errorf("failed to sell %d units of %s: %w", units, cargoItem.Symbol, err)
}
units = units - increment
}
break
}
}
}
return a.sellEverythingExcept(ship, keep)
}