1 | package main
|
2 |
|
3 | import (
|
4 | "bytes"
|
5 | "fmt"
|
6 | "hash/fnv"
|
7 | "sort"
|
8 |
|
9 | "gonum.org/v1/gonum/graph"
|
10 | )
|
11 |
|
12 | // Map of route keys e.g. ORDJFK and
|
13 | // slice of weights to apply
|
14 | type WeightMap map[string][]float64
|
15 |
|
16 | type AirportMap map[string]Airport
|
17 |
|
18 | func (a AirportMap) Airport(id string) Airport {
|
19 | return a[id]
|
20 | }
|
21 |
|
22 | func (a AirportMap) HasCode(code string) bool {
|
23 | _, ok := a[code]
|
24 | return ok
|
25 | }
|
26 |
|
27 | func (a AirportMap) Ordered() []Airport {
|
28 | var (
|
29 | sorted []Airport
|
30 | codes []string
|
31 | )
|
32 | for key, _ := range a {
|
33 | codes = append(codes, key)
|
34 | }
|
35 | sort.Strings(codes)
|
36 | for _, code := range codes {
|
37 | sorted = append(sorted, a[code])
|
38 | }
|
39 | return sorted
|
40 | }
|
41 |
|
42 | type Airport struct {
|
43 | // ICAO code
|
44 | Code string
|
45 | Name string
|
46 | City string
|
47 | Country string
|
48 | Latitude float64
|
49 | Longitude float64
|
50 | }
|
51 |
|
52 | func (a Airport) String() string {
|
53 | return fmt.Sprintf(
|
54 | "%s:%s:%s",
|
55 | a.Code, a.City, a.Country,
|
56 | )
|
57 | }
|
58 |
|
59 | func (a Airport) DOTID() string { return fmt.Sprintf("\"%s\"", a.Code) }
|
60 |
|
61 | func (a Airport) ID() int64 {
|
62 | h := fnv.New64a()
|
63 | h.Write([]byte(a.String()))
|
64 | return int64(h.Sum64())
|
65 | }
|
66 |
|
67 | var _ graph.WeightedEdge = (*Route)(nil)
|
68 |
|
69 | type Route struct {
|
70 | to Airport
|
71 | from Airport
|
72 | weight float64
|
73 | }
|
74 |
|
75 | func (r Route) String() string {
|
76 | return fmt.Sprintf("%s->%s", r.from, r.to)
|
77 | }
|
78 |
|
79 | func (r Route) To() graph.Node { return r.to }
|
80 | func (r Route) From() graph.Node { return r.from }
|
81 | func (r Route) Weight() float64 { return r.weight }
|
82 | func (r Route) ReversedEdge() graph.Edge { return Route{to: r.from, from: r.to, weight: r.weight} }
|
83 |
|
84 | func SetWeight(r Route, weight float64) Route {
|
85 | return Route{to: r.to, from: r.from, weight: weight}
|
86 | }
|
87 |
|
88 | type Itinerary struct {
|
89 | // Ordered list of airports
|
90 | stops []Airport
|
91 | weight float64
|
92 | }
|
93 |
|
94 | func (i Itinerary) String() string {
|
95 | buf := bytes.NewBuffer(nil)
|
96 | buf.WriteString(fmt.Sprintf("%f:", i.weight))
|
97 | for j, stop := range i.stops {
|
98 | buf.WriteString(stop.String())
|
99 | if j+1 != len(i.stops) {
|
100 | buf.WriteString("-->")
|
101 | }
|
102 | }
|
103 | return buf.String()
|
104 | }
|