aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--example.json127
-rw-r--r--packliste.go153
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
+}