From c78214da96da2873313400f9530a46d500ec9892 Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Sat, 8 Nov 2014 00:46:42 -0500 Subject: [PATCH] computing distances between planets --- db.go | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ errors.go | 1 + main.go | 6 +--- speck.go | 36 ++++++++++++++++---- 4 files changed, 132 insertions(+), 11 deletions(-) create mode 100644 db.go diff --git a/db.go b/db.go new file mode 100644 index 0000000..f3f1431 --- /dev/null +++ b/db.go @@ -0,0 +1,100 @@ +package main + +import ( + "database/sql" + _ "github.com/mattn/go-sqlite3" + "math" + "os" +) + +func setupDb() { + db, err := sql.Open("sqlite3", "./exo.db") + if err != nil { + bail(E_No_DB, "unable to open database: %v", err) + } + defer db.Close() + + stmnt := `create table if not exists planets ( + id integer not null primary key autoincrement, + name text, + x integer, + y integer, + z integer, + planets integer + );` + _, err = db.Exec(stmnt) + if err != nil { + log_error("couldn't create table: %v", err) + return + } + + n, err := countPlanets(db) + log_info("num planets: %v error: %v", n, err) + if n == 0 { + fi, err := os.Open(dataPath) + if err != nil { + bail(E_No_Data, "unable to open data path: %v", err) + } + c := make(chan exoSystem) + go speckStream(fi, c) + for planet := range c { + planet.Store(db) + } + } + + idx := indexPlanets(db) + log_info("%v", idx) + fillEdges(db, idx) + + stmnt = `create table if not exists edges ( + id_1 integer, + id_2 integer, + distance real + );` + _, err = db.Exec(stmnt) + if err != nil { + log_error("couldn't create distance table: %v", err) + return + } + +} + +func sq(x float64) float64 { + return x * x +} + +func dist3d(x1, y1, z1, x2, y2, z2 float64) float64 { + return math.Sqrt(sq(x1-x2) + sq(y1-y2) + sq(z1-z2)) +} + +func planetDistance(p1, p2 exoSystem) float64 { + return dist3d(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z) +} + +func indexPlanets(db *sql.DB) map[int]exoSystem { + rows, err := db.Query(`select * from planets`) + if err != nil { + log_error("unable to select all planets: %v", err) + return nil + } + defer rows.Close() + planets := make(map[int]exoSystem, 551) + for rows.Next() { + var id int + p := exoSystem{} + if err := rows.Scan(&id, &p.name, &p.x, &p.y, &p.z, &p.planets); err != nil { + log_info("unable to scan planet row: %v", err) + continue + } + planets[id] = p + } + return planets +} + +func fillEdges(db *sql.DB, planets map[int]exoSystem) { + for i := 0; i < len(planets); i++ { + for j := i + 1; j < len(planets); j++ { + log_info("distance from %s to %s: %v", planets[i].name, planets[j].name, planetDistance(planets[i], planets[j])) + } + } +} diff --git a/errors.go b/errors.go index 31e22e7..1201796 100644 --- a/errors.go +++ b/errors.go @@ -7,6 +7,7 @@ import ( const ( E_Ok int = iota E_No_Data + E_No_DB ) type errorGroup []error diff --git a/main.go b/main.go index af4ce3c..95723cc 100644 --- a/main.go +++ b/main.go @@ -27,9 +27,5 @@ func bail(status int, template string, args ...interface{}) { } func main() { - fi, err := os.Open(dataPath) - if err != nil { - bail(E_No_Data, "unable to open data path: %v", err) - } - speckStream(fi) + setupDb() } diff --git a/speck.go b/speck.go index b612423..0b0883a 100644 --- a/speck.go +++ b/speck.go @@ -2,6 +2,7 @@ package main import ( "bufio" + "database/sql" "fmt" "io" "regexp" @@ -9,7 +10,8 @@ import ( "strings" ) -func speckStream(r io.ReadCloser) { +func speckStream(r io.ReadCloser, c chan exoSystem) { + defer close(c) defer r.Close() keep := regexp.MustCompile(`^\s*[\d-]`) @@ -28,7 +30,9 @@ func speckStream(r io.ReadCloser) { if !keep.Match(line) { continue } - parseSpeckLine(line) + planet := parseSpeckLine(line) + c <- *planet + } } @@ -38,11 +42,31 @@ type exoSystem struct { name string } +func (e exoSystem) Store(db *sql.DB) { + _, err := db.Exec(` + insert into planets + (name, x, y, z, planets) + values + (?, ?, ?, ?, ?) + ;`, e.name, e.x, e.y, e.z, e.planets) + if err != nil { + log_error("%v", err) + } +} + +func countPlanets(db *sql.DB) (int, error) { + row := db.QueryRow(`select count(*) from planets`) + + var n int + err := row.Scan(&n) + return n, err +} + func (e exoSystem) String() string { - return fmt.Sprintf("", e.name, e.x, e.y, e.z, e.planets) + return fmt.Sprintf("", e.name, e.x, e.y, e.z, e.planets) } -func parseSpeckLine(line []byte) { +func parseSpeckLine(line []byte) *exoSystem { parts := strings.Split(string(line), " ") var err error var g errorGroup @@ -57,10 +81,10 @@ func parseSpeckLine(line []byte) { s.planets, err = strconv.Atoi(parts[3]) g.AddError(err) - s.name = strings.TrimSpace(strings.Join(parts[7:], " ")) + s.name = strings.TrimSpace(strings.Join(parts[7:], " ")) if g != nil { log_error("%v", g) } - log_info("%v", s) + return s }