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