Skip to content

Commit dfd05ec

Browse files
committed
Added solutions for day 12
1 parent e13e490 commit dfd05ec

File tree

3 files changed

+168
-1
lines changed

3 files changed

+168
-1
lines changed

advent2020/day12.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# MIT License
2+
#
3+
# Copyright (c) 2020 Andrew Krepps
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in all
13+
# copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
23+
24+
from . import util
25+
26+
27+
NORTH = (0, 1)
28+
SOUTH = (0, -1)
29+
EAST = (1, 0)
30+
WEST = (-1, 0)
31+
32+
33+
def parse_commands(lines):
34+
return [(line[0], int(line[1:])) for line in lines]
35+
36+
37+
def move_forward(pos, direction, distance):
38+
return pos[0] + direction[0]*distance, pos[1] + direction[1]*distance
39+
40+
41+
def move_ship(commands):
42+
pos = (0, 0)
43+
facings = [EAST, SOUTH, WEST, NORTH]
44+
facing_idx = 0
45+
for action, value in commands:
46+
direction = (0, 0)
47+
if action == 'N':
48+
direction = NORTH
49+
elif action == 'S':
50+
direction = SOUTH
51+
elif action == 'E':
52+
direction = EAST
53+
elif action == 'W':
54+
direction = WEST
55+
elif action == 'L':
56+
assert value % 90 == 0
57+
facing_idx = (facing_idx - value//90) % len(facings)
58+
elif action == 'R':
59+
assert value % 90 == 0
60+
facing_idx = (facing_idx + value//90) % len(facings)
61+
elif action == 'F':
62+
direction = facings[facing_idx]
63+
else:
64+
raise ValueError(f"Unrecognized action: {action}")
65+
pos = (pos[0] + direction[0]*value, pos[1] + direction[1]*value)
66+
return pos
67+
68+
69+
def rotate_cw_90_deg(direction):
70+
return direction[1], -direction[0]
71+
72+
73+
def move_ship_using_waypoint(commands, waypoint_pos):
74+
ship_pos = (0, 0)
75+
for action, value in commands:
76+
waypoint_adj = (0, 0)
77+
if action == 'N':
78+
waypoint_adj = NORTH
79+
elif action == 'S':
80+
waypoint_adj = SOUTH
81+
elif action == 'E':
82+
waypoint_adj = EAST
83+
elif action == 'W':
84+
waypoint_adj = WEST
85+
elif action == 'L':
86+
assert value % 90 == 0
87+
num_turns = (360 - value)//90
88+
for _ in range(num_turns):
89+
waypoint_pos = rotate_cw_90_deg(waypoint_pos)
90+
elif action == 'R':
91+
assert value % 90 == 0
92+
num_turns = value//90
93+
for _ in range(num_turns):
94+
waypoint_pos = rotate_cw_90_deg(waypoint_pos)
95+
elif action == 'F':
96+
ship_pos = move_forward(ship_pos, waypoint_pos, value)
97+
else:
98+
raise ValueError(f"Unrecognized action: {action}")
99+
waypoint_pos = move_forward(waypoint_pos, waypoint_adj, value)
100+
return ship_pos
101+
102+
103+
def get_manhattan_distance_from_origin(pos):
104+
return abs(pos[0]) + abs(pos[1])
105+
106+
107+
def get_part1_answer(commands):
108+
return get_manhattan_distance_from_origin(move_ship(commands))
109+
110+
111+
def get_part2_answer(commands):
112+
return get_manhattan_distance_from_origin(move_ship_using_waypoint(commands, (10, 1)))
113+
114+
115+
def run():
116+
with open(util.get_input_file_path("day12.txt")) as f:
117+
lines = [line.strip() for line in f if len(line.strip()) > 0]
118+
commands = parse_commands(lines)
119+
print(f"The answer to part 1 is {get_part1_answer(commands)}")
120+
print(f"The answer to part 2 is {get_part2_answer(commands)}")

main.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from advent2020 import day9
3535
from advent2020 import day10
3636
from advent2020 import day11
37+
from advent2020 import day12
3738

3839

3940
day_runners = [
@@ -47,7 +48,8 @@
4748
lambda: day8.run(),
4849
lambda: day9.run(),
4950
lambda: day10.run(),
50-
lambda: day11.run()
51+
lambda: day11.run(),
52+
lambda: day12.run()
5153
]
5254

5355

test/test_day12.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# MIT License
2+
#
3+
# Copyright (c) 2020 Andrew Krepps
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in all
13+
# copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
23+
24+
import unittest
25+
26+
from advent2020.day12 import get_part1_answer
27+
from advent2020.day12 import get_part2_answer
28+
from advent2020.day12 import parse_commands
29+
30+
31+
ship_data = """
32+
F10
33+
N3
34+
F7
35+
R90
36+
F11
37+
"""
38+
39+
40+
class Day12Test(unittest.TestCase):
41+
def test_day12(self):
42+
lines = [line.strip() for line in ship_data.split("\n") if len(line.strip()) > 0]
43+
commands = parse_commands(lines)
44+
self.assertEqual(get_part1_answer(commands), 25)
45+
self.assertEqual(get_part2_answer(commands), 286)

0 commit comments

Comments
 (0)