Improve the README ahead of publishing to pip
[munter.git] / munter / munter.py
1 # -*- coding: utf-8 -*-
2
3
4 """
5 Munter Time Calculation
6 Alexander Vasarab
7 Wylark Mountaineering LLC
8
9 A rudimentary program which implements the Munter time calculation.
10 """
11
12 import sys
13 import argparse
14
15 class InvalidUnitsException(Exception):
16 pass
17
18 rates = {
19 'uphill': { 'rate': 4, 'direction': '↑' },
20 'flat': { 'rate': 6, 'direction': '→' }, # or downhill on foot
21 'downhill': { 'rate': 10, 'direction': '↓' },
22 'bushwhacking': { 'rate': 2, 'direction': '↹' },
23 }
24
25 unit_choices = ['metric', 'imperial']
26 travel_mode_choices = rates.keys()
27
28 def time_calc(distance, elevation, rate, units):
29 retval = {}
30
31 if units not in unit_choices:
32 raise InvalidUnitsException
33
34 unit_count = 0
35
36 if 'imperial' == units:
37 # convert to metric
38 distance = (distance * 1.609) # mi to km
39 elevation = (elevation * .305) # ft to m
40
41 unit_count = distance + (elevation / 100.0)
42
43 retval['time'] = (distance + (elevation / 100.0)) / rates[rate]['rate']
44 retval['unit_count'] = unit_count
45 retval['direction'] = rates[rate]['direction']
46 retval['pace'] = rates[rate]['rate']
47
48 return retval
49
50 def print_ugly_estimate(est):
51 hours = int(est['time'])
52 minutes = int((est['time'] - hours) * 60)
53 print("{human_time}".format(
54 human_time="{hours} hours {minutes} minutes".format(
55 hours=hours,
56 minutes=minutes)))
57
58 def print_pretty_estimate(est):
59 hours = int(est['time'])
60 minutes = int((est['time'] - hours) * 60)
61
62 # NOTE: Below, the line with the unicode up arrow uses an alignment
63 # value of 31. In the future, consider using e.g. wcwidth
64 # library so that this is more elegant.
65 print("\n\t╒═══════════════════════════════╕")
66 print("\t╎▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒╎╮")
67 print("\t╎▒{:^29}▒╎│".format(''))
68 print("\t╎▒{pace_readable:^31}▒╎│".format(
69 pace_readable="{units} {direction} @ {pace}".format(
70 units=round(est['unit_count']),
71 direction=est['direction'],
72 pace=est['pace'])))
73 print("\t╎▒{human_time:^29}▒╎│".format(
74 human_time="{hours} hours {minutes} minutes".format(
75 hours=hours,
76 minutes=minutes)))
77 print("\t╎▒{:^29}▒╎│".format(''))
78 print("\t╎▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒╎│")
79 print("\t╘═══════════════════════════════╛│")
80 print("\t └───────────────────────────────┘\n")
81
82 def get_parser():
83 parser = argparse.ArgumentParser(description='Munter Time Calculation')
84
85 parser.add_argument('--distance',
86 '-d',
87 type=float,
88 required=True,
89 help='Distance (in km, by default)')
90
91 parser.add_argument('--elevation',
92 '-e',
93 type=float,
94 required=True,
95 help='Elevation change (in m, by default)')
96
97 parser.add_argument('--travel-mode',
98 '-t',
99 type=str,
100 default='uphill',
101 choices=travel_mode_choices, required=False,
102 help='Travel mode (flat, by default)')
103
104 parser.add_argument('--units',
105 '-u',
106 type=str,
107 default='imperial',
108 required=False,
109 choices=unit_choices,
110 help='Units of input values')
111
112 parser.add_argument('--pretty',
113 '-p',
114 action='store_true',
115 default=False,
116 required=False);
117
118 return parser
119
120 def main():
121 parser = get_parser()
122 opts = parser.parse_args()
123
124 distance = opts.distance
125 elevation = opts.elevation
126 units = opts.units
127 travel_mode = opts.travel_mode
128
129 time_estimate = time_calc(distance, elevation, travel_mode, units=units)
130
131 if opts.pretty:
132 print_pretty_estimate(time_estimate)
133 else:
134 print_ugly_estimate(time_estimate)
135
136 return 0
137
138 if __name__ == "__main__":
139 sys.exit(main())