[golang] finished implementing procument contracts
This commit is contained in:
parent
40c4a8df15
commit
e887213aff
15 changed files with 252 additions and 56 deletions
|
@ -72,7 +72,7 @@ func (a *agent) runProcurement(contract *model.Contract, ship *model.Ship) error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// deliver the goods
|
// deliver the goods
|
||||||
if err := a.client.Navigate(ship, deliver.DestinationSymbol); err != nil {
|
if err := a.navigate(ship, deliver.DestinationSymbol); err != nil {
|
||||||
return fmt.Errorf("failed to navigate to %s: %w", deliver.DestinationSymbol, err)
|
return fmt.Errorf("failed to navigate to %s: %w", deliver.DestinationSymbol, err)
|
||||||
}
|
}
|
||||||
if err := a.client.Deliver(contract, ship); err != nil {
|
if err := a.client.Deliver(contract, ship); err != nil {
|
||||||
|
|
167
golang/pkg/agent/navigate.go
Normal file
167
golang/pkg/agent/navigate.go
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
package agent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/heap"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"math"
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
"git.adyxax.org/adyxax/spacetraders/golang/pkg/api"
|
||||||
|
"git.adyxax.org/adyxax/spacetraders/golang/pkg/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *agent) navigate(ship *model.Ship, waypointSymbol string) error {
|
||||||
|
if ship.Nav.WaypointSymbol == waypointSymbol {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if ship.Fuel.Capacity == 0 {
|
||||||
|
if err := a.client.Navigate(ship, waypointSymbol); err != nil {
|
||||||
|
return fmt.Errorf("failed to navigate to %s: %w", waypointSymbol, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
path, cost, err := a.shortestPath(ship.Nav.WaypointSymbol, waypointSymbol, ship.Fuel.Capacity)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to compute shortest path: %w", err)
|
||||||
|
}
|
||||||
|
slog.Debug("shortest path", "origin", ship.Nav.WaypointSymbol, "destination", waypointSymbol, "path", path, "cost", cost)
|
||||||
|
for _, next := range path {
|
||||||
|
if err := a.client.Refuel(ship); err != nil {
|
||||||
|
return fmt.Errorf("failed to refuel: %w", err)
|
||||||
|
}
|
||||||
|
if err := a.client.Navigate(ship, next); err != nil {
|
||||||
|
return fmt.Errorf("failed to navigate to %s: %w", next, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *agent) shortestPath(origin string, destination string, fuelCapacity int) ([]string, int, error) {
|
||||||
|
if fuelCapacity == 0 { // Probes
|
||||||
|
fuelCapacity = math.MaxInt
|
||||||
|
}
|
||||||
|
systemSymbol := api.WaypointSymbolToSystemSymbol(origin)
|
||||||
|
waypoints, err := a.client.ListWaypointsInSystem(systemSymbol)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("failed to list waypoints in system %s: %w", systemSymbol, err)
|
||||||
|
}
|
||||||
|
backtrace := make(map[string]string) // backtrace map with the shortest path from one point to another
|
||||||
|
costs := make(map[string]int) // cost to reach each waypoint from the origin. cost = distance + 1
|
||||||
|
costs[origin] = 0
|
||||||
|
unvisited := make(map[string]*model.Waypoint)
|
||||||
|
for i := range waypoints {
|
||||||
|
symbol := waypoints[i].Symbol
|
||||||
|
costs[symbol] = math.MaxInt
|
||||||
|
unvisited[waypoints[i].Symbol] = &waypoints[i]
|
||||||
|
// We need to know which waypoints allow refueling
|
||||||
|
waypoints[i].Traits = slices.DeleteFunc(waypoints[i].Traits, func(trait model.Common) bool {
|
||||||
|
if trait.Symbol == "MARKETPLACE" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
if len(waypoints[i].Traits) > 0 {
|
||||||
|
market, err := a.client.GetMarket(symbol, a.ships)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("failed to get market %s: %w", symbol, err)
|
||||||
|
}
|
||||||
|
market.Exchange = slices.DeleteFunc(market.Exchange, func(item model.Common) bool {
|
||||||
|
if item.Symbol == "FUEL" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
market.Exports = slices.DeleteFunc(market.Exports, func(item model.Common) bool {
|
||||||
|
if item.Symbol == "FUEL" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
if len(market.Exchange) == 0 && len(market.Exports) == 0 {
|
||||||
|
waypoints[i].Traits = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
costs[origin] = 0
|
||||||
|
pq := make(PriorityQueue, 1)
|
||||||
|
pq[0] = &Node{
|
||||||
|
waypointSymbol: origin,
|
||||||
|
}
|
||||||
|
heap.Init(&pq)
|
||||||
|
outer:
|
||||||
|
for pq.Len() > 0 {
|
||||||
|
node := heap.Pop(&pq).(*Node)
|
||||||
|
waypoint, ok := unvisited[node.waypointSymbol]
|
||||||
|
if !ok { // already visited
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
delete(unvisited, node.waypointSymbol)
|
||||||
|
for _, candidate := range unvisited {
|
||||||
|
fuel := int(math.Floor(math.Sqrt(float64(distance2(waypoint, candidate))))) + 1
|
||||||
|
if fuel > fuelCapacity {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cost := node.cost + fuel
|
||||||
|
if cost < costs[candidate.Symbol] {
|
||||||
|
backtrace[candidate.Symbol] = node.waypointSymbol
|
||||||
|
costs[candidate.Symbol] = cost
|
||||||
|
if candidate.Symbol == destination {
|
||||||
|
break outer
|
||||||
|
}
|
||||||
|
if len(candidate.Traits) > 0 {
|
||||||
|
heap.Push(&pq, &Node{
|
||||||
|
cost: cost,
|
||||||
|
waypointSymbol: candidate.Symbol,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
path := []string{destination}
|
||||||
|
step, ok := backtrace[destination]
|
||||||
|
if !ok {
|
||||||
|
slog.Debug("shortest path failure", "backtraces", backtrace, "costs", costs)
|
||||||
|
return nil, 0, fmt.Errorf("no path exists between origin and destination with the given fuel capacity")
|
||||||
|
}
|
||||||
|
for step != origin {
|
||||||
|
path = append([]string{step}, path...)
|
||||||
|
step = backtrace[step]
|
||||||
|
}
|
||||||
|
return path, costs[destination], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Priority queue implementation with container/heap
|
||||||
|
type Node struct {
|
||||||
|
cost int
|
||||||
|
waypointSymbol string
|
||||||
|
index int // needed by the heap.Interface methods
|
||||||
|
}
|
||||||
|
|
||||||
|
type PriorityQueue []*Node
|
||||||
|
|
||||||
|
func (pq PriorityQueue) Len() int { return len(pq) }
|
||||||
|
func (pq PriorityQueue) Less(i, j int) bool { return pq[i].cost < pq[j].cost }
|
||||||
|
func (pq PriorityQueue) Swap(i, j int) {
|
||||||
|
pq[i], pq[j] = pq[j], pq[i]
|
||||||
|
pq[i].index = i
|
||||||
|
pq[j].index = j
|
||||||
|
}
|
||||||
|
func (pq *PriorityQueue) Push(x any) {
|
||||||
|
n := len(*pq)
|
||||||
|
item := x.(*Node)
|
||||||
|
item.index = n
|
||||||
|
*pq = append(*pq, item)
|
||||||
|
}
|
||||||
|
func (pq *PriorityQueue) Pop() any {
|
||||||
|
old := *pq
|
||||||
|
n := len(old)
|
||||||
|
item := old[n-1]
|
||||||
|
old[n-1] = nil // don't stop the GC from reclaiming the item eventually
|
||||||
|
item.index = -1 // for safety
|
||||||
|
*pq = old[0 : n-1]
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
func (pq *PriorityQueue) Update(n *Node, cost int) {
|
||||||
|
n.cost = cost
|
||||||
|
heap.Fix(pq, n.index)
|
||||||
|
}
|
|
@ -36,7 +36,7 @@ func (a *agent) buyTradeGood(ship *model.Ship, tradeGoodToBuy string) error {
|
||||||
// find the closest place to buy TODO
|
// find the closest place to buy TODO
|
||||||
waypoint, err := a.client.GetWaypoint(ship.Nav.WaypointSymbol)
|
waypoint, err := a.client.GetWaypoint(ship.Nav.WaypointSymbol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get nav waypoint %s: %w", ship.Nav.WaypointSymbol, err)
|
return fmt.Errorf("failed to get waypoint %s: %w", ship.Nav.WaypointSymbol, err)
|
||||||
}
|
}
|
||||||
waypoints := make([]model.Waypoint, 0)
|
waypoints := make([]model.Waypoint, 0)
|
||||||
for i := range markets {
|
for i := range markets {
|
||||||
|
@ -48,10 +48,13 @@ func (a *agent) buyTradeGood(ship *model.Ship, tradeGoodToBuy string) error {
|
||||||
}
|
}
|
||||||
sortByDistanceFrom(waypoint, waypoints)
|
sortByDistanceFrom(waypoint, waypoints)
|
||||||
// Go there and refresh our market data
|
// Go there and refresh our market data
|
||||||
if err := a.client.Navigate(ship, waypoints[0].Symbol); err != nil {
|
if err := a.navigate(ship, waypoints[0].Symbol); err != nil {
|
||||||
return fmt.Errorf("failed to navigate to %s: %w", waypoints[0].Symbol, err)
|
return fmt.Errorf("failed to navigate to %s: %w", waypoints[0].Symbol, err)
|
||||||
}
|
}
|
||||||
market, err := a.client.GetMarket(waypoints[0].Symbol)
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get market %s: %w", waypoints[0].Symbol, err)
|
return fmt.Errorf("failed to get market %s: %w", waypoints[0].Symbol, err)
|
||||||
}
|
}
|
||||||
|
@ -72,11 +75,13 @@ func (a *agent) buyTradeGood(ship *model.Ship, tradeGoodToBuy string) error {
|
||||||
|
|
||||||
func (a *agent) sellEverythingExcept(ship *model.Ship, keep string) error {
|
func (a *agent) sellEverythingExcept(ship *model.Ship, keep string) error {
|
||||||
// First lets see what we need to sell
|
// First lets see what we need to sell
|
||||||
cargo := ship.Cargo.Inventory
|
var inventoryItems []model.InventoryItem
|
||||||
cargo = slices.DeleteFunc(cargo, func(inventory model.Inventory) bool {
|
for _, item := range ship.Cargo.Inventory {
|
||||||
return inventory.Symbol == keep
|
if item.Symbol != keep {
|
||||||
})
|
inventoryItems = append(inventoryItems, item)
|
||||||
if len(cargo) == 0 {
|
}
|
||||||
|
}
|
||||||
|
if len(inventoryItems) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// list markets would buy our goods
|
// list markets would buy our goods
|
||||||
|
@ -85,9 +90,9 @@ func (a *agent) sellEverythingExcept(ship *model.Ship, keep string) error {
|
||||||
return fmt.Errorf("failed to list markets in system %s: %w", ship.Nav.SystemSymbol, err)
|
return fmt.Errorf("failed to list markets in system %s: %w", ship.Nav.SystemSymbol, err)
|
||||||
}
|
}
|
||||||
markets = slices.DeleteFunc(markets, func(market model.Market) bool {
|
markets = slices.DeleteFunc(markets, func(market model.Market) bool {
|
||||||
for _, item := range market.Imports {
|
for _, marketItem := range market.Imports {
|
||||||
for _, cargoItem := range cargo {
|
for _, inventoryItem := range inventoryItems {
|
||||||
if item.Symbol == cargoItem.Symbol {
|
if marketItem.Symbol == inventoryItem.Symbol {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,15 +117,18 @@ func (a *agent) sellEverythingExcept(ship *model.Ship, keep string) error {
|
||||||
}
|
}
|
||||||
sortByDistanceFrom(waypoint, waypoints)
|
sortByDistanceFrom(waypoint, waypoints)
|
||||||
// Go there and refresh our market data
|
// Go there and refresh our market data
|
||||||
if err := a.client.Navigate(ship, waypoints[0].Symbol); err != nil {
|
if err := a.navigate(ship, waypoints[0].Symbol); err != nil {
|
||||||
return fmt.Errorf("failed to navigate to %s: %w", waypoints[0].Symbol, err)
|
return fmt.Errorf("failed to navigate to %s: %w", waypoints[0].Symbol, err)
|
||||||
}
|
}
|
||||||
market, err := a.client.GetMarket(waypoints[0].Symbol)
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get market %s: %w", waypoints[0].Symbol, err)
|
return fmt.Errorf("failed to get market %s: %w", waypoints[0].Symbol, err)
|
||||||
}
|
}
|
||||||
// sell everything we can
|
// sell everything we can
|
||||||
for _, cargoItem := range cargo {
|
for _, cargoItem := range inventoryItems {
|
||||||
units := cargoItem.Units
|
units := cargoItem.Units
|
||||||
for _, tradeGood := range market.TradeGoods {
|
for _, tradeGood := range market.TradeGoods {
|
||||||
if tradeGood.Type == "IMPORT" && tradeGood.Symbol == cargoItem.Symbol {
|
if tradeGood.Type == "IMPORT" && tradeGood.Symbol == cargoItem.Symbol {
|
||||||
|
|
|
@ -47,7 +47,7 @@ func (a *agent) listMarketsInSystem(systemSymbol string) ([]model.Market, error)
|
||||||
}
|
}
|
||||||
var markets []model.Market
|
var markets []model.Market
|
||||||
for i := range waypoints {
|
for i := range waypoints {
|
||||||
market, err := a.client.GetMarket(waypoints[i].Symbol)
|
market, err := a.client.GetMarket(waypoints[i].Symbol, a.ships)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get market %s: %w", waypoints[i].Symbol, err)
|
return nil, fmt.Errorf("failed to get market %s: %w", waypoints[i].Symbol, err)
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ func (a *agent) listShipyardsInSystem(systemSymbol string) ([]model.Shipyard, er
|
||||||
}
|
}
|
||||||
var shipyards []model.Shipyard
|
var shipyards []model.Shipyard
|
||||||
for i := range waypoints {
|
for i := range waypoints {
|
||||||
shipyard, err := a.client.GetShipyard(waypoints[i].Symbol)
|
shipyard, err := a.client.GetShipyard(waypoints[i].Symbol, a.ships)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get shipyard %s: %w", waypoints[i].Symbol, err)
|
return nil, fmt.Errorf("failed to get shipyard %s: %w", waypoints[i].Symbol, err)
|
||||||
}
|
}
|
||||||
|
@ -86,6 +86,9 @@ func (a *agent) sendShipToShipyardThatSells(ship *model.Ship, shipType string) e
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
if len(shipyards) == 0 {
|
||||||
|
return fmt.Errorf("no shipyards sells that ship type")
|
||||||
|
}
|
||||||
// sort by cheapest
|
// sort by cheapest
|
||||||
slices.SortFunc(shipyards, func(a, b model.Shipyard) int {
|
slices.SortFunc(shipyards, func(a, b model.Shipyard) int {
|
||||||
aPrice := math.MaxInt
|
aPrice := math.MaxInt
|
||||||
|
@ -104,7 +107,7 @@ func (a *agent) sendShipToShipyardThatSells(ship *model.Ship, shipType string) e
|
||||||
}
|
}
|
||||||
return cmp.Compare(aPrice, bPrice)
|
return cmp.Compare(aPrice, bPrice)
|
||||||
})
|
})
|
||||||
if err := a.client.Navigate(ship, shipyards[0].Symbol); err != nil {
|
if err := a.navigate(ship, shipyards[0].Symbol); err != nil {
|
||||||
return fmt.Errorf("failed to navigate to %s: %w", shipyards[0].Symbol, err)
|
return fmt.Errorf("failed to navigate to %s: %w", shipyards[0].Symbol, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -14,7 +14,7 @@ func (a *agent) visitAllShipyards(ship *model.Ship) error {
|
||||||
}
|
}
|
||||||
shipyards = slices.DeleteFunc(shipyards, func(shipyard model.Shipyard) bool {
|
shipyards = slices.DeleteFunc(shipyards, func(shipyard model.Shipyard) bool {
|
||||||
// filter out shipyards for which we already have ships prices
|
// filter out shipyards for which we already have ships prices
|
||||||
if shipyard.Ships != nil {
|
if len(shipyard.Ships) > 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// filter out shipyards for which a ship is either present or inbound
|
// filter out shipyards for which a ship is either present or inbound
|
||||||
|
@ -36,16 +36,16 @@ func (a *agent) visitAllShipyards(ship *model.Ship) error {
|
||||||
waypoints = append(waypoints, *waypoint)
|
waypoints = append(waypoints, *waypoint)
|
||||||
}
|
}
|
||||||
sortByDistanceFrom(waypoint, waypoints)
|
sortByDistanceFrom(waypoint, waypoints)
|
||||||
if err := a.client.Navigate(ship, waypoints[0].Symbol); err != nil {
|
if err := a.navigate(ship, waypoints[0].Symbol); err != nil {
|
||||||
return fmt.Errorf("failed to navigate to %s: %w", waypoints[0].Symbol, err)
|
return fmt.Errorf("failed to navigate to %s: %w", waypoints[0].Symbol, err)
|
||||||
}
|
}
|
||||||
if _, err := a.client.GetShipyard(waypoints[0].Symbol); err != nil {
|
if _, err := a.client.GetShipyard(waypoints[0].Symbol, a.ships); err != nil {
|
||||||
return fmt.Errorf("failed to get shipyard %s: %w", waypoints[0].Symbol, err)
|
return fmt.Errorf("failed to get shipyard %s: %w", waypoints[0].Symbol, err)
|
||||||
}
|
}
|
||||||
// If this waypoint is also a marketplace, get its data
|
// If this waypoint is also a marketplace, get its data
|
||||||
for _, trait := range waypoints[0].Traits {
|
for _, trait := range waypoints[0].Traits {
|
||||||
if trait.Symbol == "MARKETPLACE" {
|
if trait.Symbol == "MARKETPLACE" {
|
||||||
if _, err := a.client.GetMarket(waypoints[0].Symbol); err != nil {
|
if _, err := a.client.GetMarket(waypoints[0].Symbol, a.ships); err != nil {
|
||||||
return fmt.Errorf("failed to get market %s: %w", waypoints[0].Symbol, err)
|
return fmt.Errorf("failed to get market %s: %w", waypoints[0].Symbol, err)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
|
|
@ -30,6 +30,9 @@ func (c *Client) Accept(contract *model.Contract) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Deliver(contract *model.Contract, ship *model.Ship) error {
|
func (c *Client) Deliver(contract *model.Contract, ship *model.Ship) error {
|
||||||
|
if err := c.Dock(ship); err != nil {
|
||||||
|
return fmt.Errorf("failed to dock: %w", err)
|
||||||
|
}
|
||||||
deliver := contract.Terms.Deliver[0]
|
deliver := contract.Terms.Deliver[0]
|
||||||
var units int
|
var units int
|
||||||
for _, cargoItem := range ship.Cargo.Inventory {
|
for _, cargoItem := range ship.Cargo.Inventory {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"git.adyxax.org/adyxax/spacetraders/golang/pkg/model"
|
"git.adyxax.org/adyxax/spacetraders/golang/pkg/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Client) dock(s *model.Ship) error {
|
func (c *Client) Dock(s *model.Ship) error {
|
||||||
if s.Nav.Status == "DOCKED" {
|
if s.Nav.Status == "DOCKED" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -41,8 +41,6 @@ func (c *Client) Navigate(s *model.Ship, waypointSymbol string) error {
|
||||||
if err := c.orbit(s); err != nil {
|
if err := c.orbit(s); err != nil {
|
||||||
return fmt.Errorf("failed to orbit: %w", err)
|
return fmt.Errorf("failed to orbit: %w", err)
|
||||||
}
|
}
|
||||||
// TODO shortest path
|
|
||||||
// TODO go refuel if necessary
|
|
||||||
uriRef := url.URL{Path: path.Join("my/ships", s.Symbol, "navigate")}
|
uriRef := url.URL{Path: path.Join("my/ships", s.Symbol, "navigate")}
|
||||||
type navigateRequest struct {
|
type navigateRequest struct {
|
||||||
WaypointSymbol string `json:"waypointSymbol"`
|
WaypointSymbol string `json:"waypointSymbol"`
|
||||||
|
@ -96,7 +94,7 @@ func (c *Client) orbit(s *model.Ship) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Purchase(s *model.Ship, cargoItem string, units int) error {
|
func (c *Client) Purchase(s *model.Ship, cargoItem string, units int) error {
|
||||||
if err := c.dock(s); err != nil {
|
if err := c.Dock(s); err != nil {
|
||||||
return fmt.Errorf("failed to dock: %w", err)
|
return fmt.Errorf("failed to dock: %w", err)
|
||||||
}
|
}
|
||||||
uriRef := url.URL{Path: path.Join("my/ships", s.Symbol, "purchase")}
|
uriRef := url.URL{Path: path.Join("my/ships", s.Symbol, "purchase")}
|
||||||
|
@ -123,11 +121,11 @@ func (c *Client) Purchase(s *model.Ship, cargoItem string, units int) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) refuel(s *model.Ship, db *database.DB) error {
|
func (c *Client) Refuel(s *model.Ship) error {
|
||||||
if s.Fuel.Current == s.Fuel.Capacity {
|
if s.Fuel.Current == s.Fuel.Capacity {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err := c.dock(s); err != nil {
|
if err := c.Dock(s); err != nil {
|
||||||
return fmt.Errorf("failed to dock: %w", err)
|
return fmt.Errorf("failed to dock: %w", err)
|
||||||
}
|
}
|
||||||
uriRef := url.URL{Path: path.Join("my/ships", s.Symbol, "refuel")}
|
uriRef := url.URL{Path: path.Join("my/ships", s.Symbol, "refuel")}
|
||||||
|
@ -151,7 +149,7 @@ func (c *Client) refuel(s *model.Ship, db *database.DB) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Sell(s *model.Ship, cargoItem string, units int) error {
|
func (c *Client) Sell(s *model.Ship, cargoItem string, units int) error {
|
||||||
if err := c.dock(s); err != nil {
|
if err := c.Dock(s); err != nil {
|
||||||
return fmt.Errorf("failed to dock: %w", err)
|
return fmt.Errorf("failed to dock: %w", err)
|
||||||
}
|
}
|
||||||
uriRef := url.URL{Path: path.Join("my/ships", s.Symbol, "sell")}
|
uriRef := url.URL{Path: path.Join("my/ships", s.Symbol, "sell")}
|
||||||
|
|
|
@ -8,10 +8,12 @@ import (
|
||||||
"git.adyxax.org/adyxax/spacetraders/golang/pkg/model"
|
"git.adyxax.org/adyxax/spacetraders/golang/pkg/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Client) GetMarket(waypointSymbol string) (*model.Market, error) {
|
func (c *Client) GetMarket(waypointSymbol string, ships []model.Ship) (*model.Market, error) {
|
||||||
if market, err := c.db.LoadMarket(waypointSymbol); err == nil && market != nil {
|
if !isThereAShipDockerAtWaypoint(waypointSymbol, ships) {
|
||||||
// TODO check last updated time
|
if market, err := c.db.LoadMarket(waypointSymbol); err == nil && market != nil {
|
||||||
return market, nil
|
// TODO check last updated time
|
||||||
|
return market, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
systemSymbol := WaypointSymbolToSystemSymbol(waypointSymbol)
|
systemSymbol := WaypointSymbolToSystemSymbol(waypointSymbol)
|
||||||
uriRef := url.URL{Path: path.Join("systems", systemSymbol, "waypoints", waypointSymbol, "market")}
|
uriRef := url.URL{Path: path.Join("systems", systemSymbol, "waypoints", waypointSymbol, "market")}
|
||||||
|
@ -25,11 +27,12 @@ func (c *Client) GetMarket(waypointSymbol string) (*model.Market, error) {
|
||||||
return &market, nil
|
return &market, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) GetShipyard(waypointSymbol string) (*model.Shipyard, error) {
|
func (c *Client) GetShipyard(waypointSymbol string, ships []model.Ship) (*model.Shipyard, error) {
|
||||||
if shipyard, err := c.db.LoadShipyard(waypointSymbol); err == nil && shipyard != nil &&
|
if !isThereAShipDockerAtWaypoint(waypointSymbol, ships) {
|
||||||
(shipyard.Ships != nil) { // TODO || !IsThereAShipAtWaypoint(waypoint)) {
|
if shipyard, err := c.db.LoadShipyard(waypointSymbol); err == nil && shipyard != nil {
|
||||||
// TODO check last updated time
|
// TODO check last updated time
|
||||||
return shipyard, nil
|
return shipyard, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
systemSymbol := WaypointSymbolToSystemSymbol(waypointSymbol)
|
systemSymbol := WaypointSymbolToSystemSymbol(waypointSymbol)
|
||||||
uriRef := url.URL{Path: path.Join("systems", systemSymbol, "waypoints", waypointSymbol, "shipyard")}
|
uriRef := url.URL{Path: path.Join("systems", systemSymbol, "waypoints", waypointSymbol, "shipyard")}
|
||||||
|
@ -76,7 +79,7 @@ func (c *Client) GetWaypoint(waypointSymbol string) (*model.Waypoint, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) ListWaypointsInSystem(systemSymbol string) ([]model.Waypoint, error) {
|
func (c *Client) ListWaypointsInSystem(systemSymbol string) ([]model.Waypoint, error) {
|
||||||
if waypoints, err := c.db.LoadWaypointsInSystem(systemSymbol); err == nil && waypoints != nil {
|
if waypoints, err := c.db.LoadWaypointsInSystem(systemSymbol); err == nil && len(waypoints) > 0 {
|
||||||
// TODO check last updated time
|
// TODO check last updated time
|
||||||
return waypoints, nil
|
return waypoints, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,19 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.adyxax.org/adyxax/spacetraders/golang/pkg/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func isThereAShipDockerAtWaypoint(symbol string, ships []model.Ship) bool {
|
||||||
|
for _, ship := range ships {
|
||||||
|
if ship.Nav.WaypointSymbol == symbol && ship.Nav.Status == "DOCKED" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func WaypointSymbolToSystemSymbol(symbol string) string {
|
func WaypointSymbolToSystemSymbol(symbol string) string {
|
||||||
return strings.Join(strings.Split(symbol, "-")[:2], "-")
|
return strings.Join(strings.Split(symbol, "-")[:2], "-")
|
||||||
|
|
|
@ -12,7 +12,7 @@ func (db *DB) SaveAgent(agent *model.Agent) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to marshal agent: %w", err)
|
return fmt.Errorf("failed to marshal agent: %w", err)
|
||||||
}
|
}
|
||||||
if _, err := db.Exec(`INSERT INTO agents VALUES data = (json(?));`, data); err != nil {
|
if _, err := db.Exec(`INSERT INTO agents(data) VALUES (json(?));`, data); err != nil {
|
||||||
return fmt.Errorf("failed to insert agent data: %w", err)
|
return fmt.Errorf("failed to insert agent data: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -95,6 +95,7 @@ func (db *DB) Reset() error {
|
||||||
_, err := db.Exec(strings.Join([]string{
|
_, err := db.Exec(strings.Join([]string{
|
||||||
"DELETE FROM agents;",
|
"DELETE FROM agents;",
|
||||||
"DELETE FROM markets;",
|
"DELETE FROM markets;",
|
||||||
|
"DELETE FROM shipyards;",
|
||||||
"DELETE FROM systems;",
|
"DELETE FROM systems;",
|
||||||
"DELETE FROM tokens;",
|
"DELETE FROM tokens;",
|
||||||
"DELETE FROM transactions;",
|
"DELETE FROM transactions;",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
type Cargo struct {
|
type Cargo struct {
|
||||||
Capacity int `json:"capacity"`
|
Capacity int `json:"capacity"`
|
||||||
Inventory []Inventory `json:"inventory"`
|
Inventory []InventoryItem `json:"inventory"`
|
||||||
Units int `json:"units"`
|
Units int `json:"units"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
type Inventory struct {
|
type InventoryItem struct {
|
||||||
//Description string `json:"description"`
|
//Description string `json:"description"`
|
||||||
Units int `json:"units"`
|
Units int `json:"units"`
|
||||||
//Name string `json:"name"`
|
//Name string `json:"name"`
|
||||||
|
|
|
@ -3,14 +3,14 @@ package model
|
||||||
type Ship struct {
|
type Ship struct {
|
||||||
Cargo *Cargo `json:"cargo"`
|
Cargo *Cargo `json:"cargo"`
|
||||||
Cooldown *Cooldown `json:"cooldown"`
|
Cooldown *Cooldown `json:"cooldown"`
|
||||||
//// crew
|
// crew
|
||||||
//// engine
|
// engine
|
||||||
//// frame
|
// frame
|
||||||
Fuel *Fuel `json:"fuel"`
|
Fuel *Fuel `json:"fuel"`
|
||||||
//// modules
|
// modules
|
||||||
//// mounts
|
// mounts
|
||||||
Nav *Nav `json:"nav"`
|
Nav *Nav `json:"nav"`
|
||||||
//// reactor
|
// reactor
|
||||||
//registration: Registration;
|
//registration: Registration;
|
||||||
Symbol string `json:"symbol"`
|
Symbol string `json:"symbol"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,11 @@ package model
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type Shipyard struct {
|
type Shipyard struct {
|
||||||
ModificationFee int `json:"modificationFee"`
|
ModificationFee int `json:"modificationFee"`
|
||||||
Symbol string `json:"symbol"`
|
Symbol string `json:"symbol"`
|
||||||
ShipTypes []CommonType `json:"shipTypes"`
|
ShipTypes []CommonType `json:"shipTypes"`
|
||||||
Transactions []ShipyardTransaction `json:"transactions"`
|
//Transactions []ShipyardTransaction `json:"transactions"`
|
||||||
Ships []ShipyardShip `json:"ships"`
|
Ships []ShipyardShip `json:"ships"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ShipyardShip struct {
|
type ShipyardShip struct {
|
||||||
|
|
Loading…
Add table
Reference in a new issue