-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday-1.py
executable file
·138 lines (103 loc) · 3.64 KB
/
day-1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#!/usr/bin/env python
"""Advent of Code Programming Puzzles
2019 Edition - Day One
Puzzle Solution in Python
"""
import argparse
import logging
import os
import sys
EXIT_SUCCESS = 0
LOG_FORMAT = ('%(asctime)s - %(levelname)s - %(module)s - '
'%(funcName)s - %(message)s')
log = logging.getLogger(__name__)
def load_contents(filename: str) -> list[int]:
"""Load contents from the given file
:param filename: filename as string
:return: list of integers
"""
contents = list(map(int, open(filename).read().strip().split(os.linesep)))
log.info(f'Loaded {len(contents)} values from file {filename}')
return contents
# Puzzle Solving Methods -------------------------------------------------------
def compute_required_fuel(mass: int) -> int:
"""Compute required fuel from a mass
:param mass: mass value
:return: required fuel quantity
"""
required_fuel = mass // 3 - 2
return required_fuel
def solve(contents: list[int]):
"""Solve part one of the puzzle
:param contents: list of integers
:return: answer for the part one of the puzzle
"""
mass_values = contents
fuel_values = [compute_required_fuel(mass) for mass in mass_values]
answer = sum(fuel_values)
return answer
def compute_recursive_required_fuel(mass: int) -> int:
"""Compute required fuel from a mass taking the weight of fuel into account
:param mass: mass value
:return: total required fuel quantity
"""
fuel = compute_required_fuel(mass=mass)
if fuel <= 0:
return 0
extra_fuel = compute_recursive_required_fuel(mass=fuel)
total_fuel = fuel + extra_fuel
return total_fuel
def solve_part_two(contents: list[int]):
"""Solve part two of the puzzle
:param contents: list of integers
:return: answer for the part one of the puzzle
"""
mass_values = contents
fuel_values = [compute_recursive_required_fuel(mass) for mass in mass_values]
answer = sum(fuel_values)
return answer
# Support Methods --------------------------------------------------------------
def configure_logger(verbose: bool):
"""Configure logging
:param verbose: display debug and info messages
:return: nothing
"""
logger = logging.getLogger()
logger.handlers = []
stdout = logging.StreamHandler(sys.stdout)
stdout.setLevel(level=logging.WARNING)
stdout.setFormatter(logging.Formatter(LOG_FORMAT))
logger.addHandler(stdout)
if verbose:
stdout.setLevel(level=logging.DEBUG)
logger.setLevel(level=logging.DEBUG)
def parse_arguments() -> argparse.Namespace:
"""Parse arguments provided by the command-line
:return: list of decoded arguments
"""
parser = argparse.ArgumentParser(description=__doc__)
pa = parser.add_argument
pa('filename', type=str, help='input contents filename')
pa('-p', '--part', type=int, help='solve only the given part')
pa('-v', '--verbose', action='store_true', help='print extra messages')
arguments = parser.parse_args()
return arguments
def main() -> int:
"""Script main method
:return: script exit code returned to the shell
"""
args = parse_arguments()
configure_logger(verbose=args.verbose)
log.debug(f'Arguments: {args}')
contents = load_contents(filename=args.filename)
compute_part_one = not args.part or 1 == args.part
compute_part_two = not args.part or 2 == args.part
if compute_part_one:
answer = solve(contents=contents)
print(answer)
if compute_part_two:
answer = solve_part_two(contents=contents)
print(answer)
return EXIT_SUCCESS
if __name__ == "__main__":
sys.exit(main())