slowly getting rid of global index

master
Jordan Orelli 5 years ago
parent 5ce9a530f8
commit dbb2c86f5a

@ -211,15 +211,11 @@ func BroadcastCommand(sys *System) Command {
func NearbyCommand(sys *System) Command {
handler := func(c *Connection, args ...string) {
neighbors, err := sys.Nearby(25)
if err != nil {
log_error("unable to get neighbors: %v", err)
return
}
neighbors := c.game.galaxy.Neighborhood(sys)
c.Printf("--------------------------------------------------------------------------------\n")
c.Printf("%-4s %-20s %-12s %s\n", "id", "name", "distance", "trip time")
c.Printf("--------------------------------------------------------------------------------\n")
for _, neighbor := range neighbors {
for _, neighbor := range neighbors[:25] {
other := index[neighbor.id]
dur := NewTravel(c, sys, other).(*TravelState).tripTime()
c.Printf("%-4d %-20s %-12.6v %v\n", other.id, other.name, neighbor.distance, dur)

@ -5,6 +5,7 @@ import (
"fmt"
"io"
"net"
"runtime"
"sort"
"strings"
"time"
@ -52,9 +53,22 @@ func (c *Connection) Tick(frame int64) {
func (c *Connection) RunCommand(name string, args ...string) {
defer func() {
if r := recover(); r != nil {
c.Printf("something is broken. Log this as a ticket!\n")
c.Printf("recovered: %v\n", r)
c.Printf("(something is broken)")
c.Printf("ERROR: %v\n", r)
callers := make([]uintptr, 40)
n := runtime.Callers(5, callers)
callers = callers[:n]
frames := runtime.CallersFrames(callers)
log_error("recovered: %v", r)
for {
frame, more := frames.Next()
if !more {
break
}
log_error(" %s +%d (%s)\n", frame.File, frame.Line, frame.Function)
}
}
}()
switch name {

@ -0,0 +1,77 @@
package main
import (
"math/rand"
"sort"
"strconv"
)
// Galaxy is a collection of systems
type Galaxy struct {
systems map[int]*System
names map[string]int
}
func NewGalaxy() *Galaxy {
g := &Galaxy{
systems: make(map[int]*System),
names: make(map[string]int),
}
g.indexSystems()
return g
}
func (g *Galaxy) indexSystems() {
rows, err := db.Query(`select * from planets`)
if err != nil {
log_error("unable to select all planets: %v", err)
return
}
defer rows.Close()
for rows.Next() {
s := System{}
if err := rows.Scan(&s.id, &s.name, &s.x, &s.y, &s.z, &s.planets); err != nil {
log_info("unable to scan planet row: %v", err)
continue
}
g.systems[s.id] = &s
g.names[s.name] = s.id
s.money = int64(rand.NormFloat64()*options.moneySigma + options.moneyMean)
}
}
// GetSystem gets a system by either ID or name. If the provided string
// contains an integer, we assume the lookup is intended to be by ID.
func (g *Galaxy) GetSystem(s string) *System {
id, err := strconv.Atoi(s)
if err == nil {
return g.GetSystemByID(id)
}
return g.GetSystemByName(s)
}
func (g *Galaxy) GetSystemByID(id int) *System {
return g.systems[id]
}
func (g *Galaxy) GetSystemByName(name string) *System {
id := g.SystemID(name)
if id == 0 {
return nil
}
return g.GetSystemByID(id)
}
func (g *Galaxy) SystemID(name string) int { return g.names[name] }
// Neighborhood generates the neighborhood for a given system.
func (g *Galaxy) Neighborhood(sys *System) Neighborhood {
neighbors := make(Neighborhood, 0, len(g.systems))
for id, sys2 := range g.systems {
neighbors = append(neighbors, Neighbor{id: id, distance: sys.DistanceTo(sys2)})
}
sort.Sort(neighbors)
return neighbors
}

@ -16,6 +16,7 @@ type Game struct {
connections map[*Connection]bool
frame int64
elems map[GameElement]bool
galaxy *Galaxy
}
func gamesTable() {
@ -49,6 +50,7 @@ func NewGame() *Game {
done: make(chan interface{}),
connections: make(map[*Connection]bool, 32),
elems: make(map[GameElement]bool, 32),
galaxy: NewGalaxy(),
}
if err := game.Create(); err != nil {
log_error("unable to create game: %v", err)

@ -65,9 +65,9 @@ func (i *IdleState) Tick(c *Connection, frame int64) ConnectionState {
}
func (i *IdleState) travelTo(c *Connection, args ...string) {
dest, err := GetSystem(args[0])
if err != nil {
c.Printf("%v\n", err)
dest := c.game.galaxy.GetSystem(args[0])
if dest == nil {
c.Printf("no such system: %s", args[0])
return
}
c.SetState(NewTravel(c, i.System, dest))
@ -83,9 +83,9 @@ func (i *IdleState) bomb(c *Connection, args ...string) {
return
}
target, err := GetSystem(args[0])
if err != nil {
c.Printf("Cannot send bomb: %v\n", err)
target := c.game.galaxy.GetSystem(args[0])
if target == nil {
c.Printf("Cannot send bomb: no such system: %v\n", args[0])
return
}

@ -5,7 +5,6 @@ import (
"fmt"
"math"
"math/rand"
"strconv"
"time"
)
@ -26,22 +25,6 @@ type System struct {
money int64
}
func GetSystem(id string) (*System, error) {
idNum, err := strconv.Atoi(id)
if err == nil {
sys, ok := index[idNum]
if !ok {
return nil, fmt.Errorf("No such system: %v", idNum)
}
return sys, nil
}
sys, ok := nameIndex[id]
if !ok {
return nil, fmt.Errorf("No such system: %v", id)
}
return sys, nil
}
func (s *System) Tick(frame int64) {
if s.colonizedBy != nil && s.money > 0 {
s.colonizedBy.Deposit(1)
@ -215,36 +198,17 @@ func (s System) String() string {
return fmt.Sprintf("%s (id: %v)", s.name, s.id)
}
type Neighborhood []Neighbor
func (n Neighborhood) Len() int { return len(n) }
func (n Neighborhood) Less(i, j int) bool { return n[i].distance < n[j].distance }
func (n Neighborhood) Swap(i, j int) { n[i], n[j] = n[j], n[i] }
type Neighbor struct {
id int
distance float64
}
func (e *System) Nearby(n int) ([]Neighbor, error) {
rows, err := db.Query(`
select planets.id, edges.distance
from edges
join planets on edges.id_2 = planets.id
where edges.id_1 = ?
order by distance
limit ?
;`, e.id, n)
if err != nil {
log_error("unable to get nearby systems for %s: %v", e.name, err)
return nil, err
}
neighbors := make([]Neighbor, 0, n)
for rows.Next() {
var neighbor Neighbor
if err := rows.Scan(&neighbor.id, &neighbor.distance); err != nil {
log_error("error unpacking row from nearby neighbors query: %v", err)
continue
}
neighbors = append(neighbors, neighbor)
}
return neighbors, nil
}
func countSystems() (int, error) {
row := db.QueryRow(`select count(*) from planets`)

Loading…
Cancel
Save