diff options
-rw-r--r-- | example.json | 127 | ||||
-rw-r--r-- | packliste.go | 153 |
2 files changed, 280 insertions, 0 deletions
diff --git a/example.json b/example.json new file mode 100644 index 0000000..164344a --- /dev/null +++ b/example.json @@ -0,0 +1,127 @@ +{ + "Kits": [ + {"Name": "general", "Items": [ + "phone", + "phone charger", + "keys", + "train ticket" + ]}, + {"Name": "clothing", "Items": [ + "t-shirt", + "pullover", + "trousers" + ]}, + {"Name": "tent", "Items": [ + "tent", + "sleeping bag", + "sleeping pad" + ]}, + {"Name": "first aid", "Items": [ + "first aid set" + ]}, + {"Name": "stuff", "Items": [ + "headlamp", + "multitool", + "knife", + "camera" + ]} + ], + + "Items": [ + { + "Name": "t-shirt", + "Scale": 2, + "Number": 1, + "Weight": 170, + "Limit": 3 + }, + { + "Name": "sleeping bag", + "Scale": 0, + "Number": 1, + "Weight": 620 + }, + { + "Name": "sleeping pad", + "Scale": 0, + "Number": 1, + "Weight": 680 + }, + { + "Name": "tent", + "Scale": 0, + "Number": 1, + "Weight": 1950 + }, + { + "Name": "camera", + "Scale": 0, + "Number": 1, + "Weight": 440, + "Note": "charge batteries" + }, + { + "Name": "first aid set", + "Scale": 0, + "Number": 1, + "Weight": 660 + }, + { + "Name": "phone", + "Scale": 0, + "Number": 1, + "Weight": 72, + "Note": "charge batteries, check prepaid account" + }, + { + "Name": "phone charger", + "Scale": 0, + "Number": 1, + "Weight": 45 + }, + { + "Name": "head lamp", + "Scale": 0, + "Number": 1, + "Weight": 90, + "Note": "pack additional batteries" + }, + { + "Name": "multitool", + "Scale": 0, + "Number": 1, + "Weight": 330 + }, + { + "Name": "knife", + "Scale": 0, + "Number": 1, + "Weight": 250 + }, + { + "Name": "pullover", + "Scale": 0, + "Number": 1, + "Weight": 500, + }, + { + "Name": "trousers", + "Scale": 0, + "Number": 1, + "Weight": 750, + "Spare": true + }, + { + "Name": "keys", + "Scale": 0, + "Number": 1, + "Weight": 150 + }, + { + "Name": "train ticket", + "Scale": 0, + "Number": 1, + "Weight": 0 + } + ] +} diff --git a/packliste.go b/packliste.go new file mode 100644 index 0000000..ed739f6 --- /dev/null +++ b/packliste.go @@ -0,0 +1,153 @@ +package main + +// TODO: Warn if undefined items are referenced +// TODO: Compact items defined multiple times in a kit + +import ( + "fmt" + "encoding/json" + "os" + "log" + "math" + "strconv" +) + +type Item struct { + Name string + Note string + Weight float64 + Scale int + Number int + Spare bool + Limit int +} + +type Kit struct { + Name string + Items []string +} + +type List struct { + Kits []Kit + Items []Item +} + +var kits map[string]Kit +var items map[string]Item +var notes []string + +func main() { + + if len(os.Args) < 4 { + fmt.Printf("Usage: %s filename days kit [kit] ...\n", os.Args[0]) + os.Exit(1) + } + + // arguments + + filename := os.Args[1] + + days, err := strconv.Atoi(os.Args[2]) + + if err != nil { + log.Fatal(err) + } + + // open JSON data + + file, err := os.Open(filename) + + if err != nil { + log.Fatal(err) + } + + // parse data + + dec := json.NewDecoder(file) + + var l List + err = dec.Decode(&l) + + if err != nil { + log.Fatal(err) + } + + // make maps of kits and items + + kits = make(map[string]Kit, 16) + + for _, kit := range l.Kits { + kits[kit.Name] = kit + } + + items = make(map[string]Item, 64) + + for _, item := range l.Items { + items[item.Name] = item + } + + // iterate over kit names provided on command line + + var weight float64 + + for _, kitname := range os.Args[3:] { + weight += useKit(kitname, days) + } + + fmt.Printf("\nTotal weight: %.3fkg\n", weight / 1000) + + fmt.Println("\n\nNotes: ") + + for _, note := range notes { + fmt.Printf("* %s\n", note) + } + +} + +func useKit(kitname string, days int) float64 { + + var weight float64 + var qty int + + fmt.Printf("=== %s ===\n", kitname) + + for _, itemname := range kits[kitname].Items { + + item, present := items[itemname] + + if !present { + continue + } + + // Scale == 0 means there will be item.Number items, + // independent of the number of days + if item.Scale == 0 { + qty = item.Number + } else { + qty = int( math.Ceil(float64(item.Number) / float64(item.Scale) * float64(days))) + } + + // Spare == true means there will one spare set added + if item.Spare { + qty += item.Number + } + + // TODO: Should this be (item.Limit * item.Number), or is the + // current solution fine? Unsure. Need to use brain. + if item.Limit > 0 && qty > (item.Limit) { + qty = item.Limit + } + + weight += float64(qty) * item.Weight + + if item.Note != "" { + notes = append(notes, item.Name + ": " + item.Note) + } + + fmt.Printf("%d x %s\n", qty, item.Name) + } + + fmt.Printf("--- %.3fkg\n", weight/1000) + + return weight +} |