Compare commits
7 Commits
0f6bf9563e
...
adea09622c
Author | SHA1 | Date | |
---|---|---|---|
adea09622c | |||
4cc516a620 | |||
ef196af7e3 | |||
7a29670437 | |||
532ca84519 | |||
c524009ad3 | |||
70aa64c63a |
46
2017/07/7.md
46
2017/07/7.md
@ -67,6 +67,48 @@ larger.)
|
|||||||
Before you\'re ready to help them, you need to make sure your
|
Before you\'re ready to help them, you need to make sure your
|
||||||
information is correct. *What is the name of the bottom program?*
|
information is correct. *What is the name of the bottom program?*
|
||||||
|
|
||||||
To begin, [get your puzzle input](7/input).
|
Your puzzle answer was `xegshds`.
|
||||||
|
|
||||||
Answer:
|
## \-\-- Part Two \-\-- {#part2}
|
||||||
|
|
||||||
|
The programs explain the situation: they can\'t get down. Rather, they
|
||||||
|
*could* get down, if they weren\'t expending all of their energy trying
|
||||||
|
to keep the tower balanced. Apparently, one program has the *wrong
|
||||||
|
weight*, and until it\'s fixed, they\'re stuck here.
|
||||||
|
|
||||||
|
For any program holding a disc, each program standing on that disc forms
|
||||||
|
a sub-tower. Each of those sub-towers are supposed to be the same
|
||||||
|
weight, or the disc itself isn\'t balanced. The weight of a tower is the
|
||||||
|
sum of the weights of the programs in that tower.
|
||||||
|
|
||||||
|
In the example above, this means that for `ugml`\'s disc to be balanced,
|
||||||
|
`gyxo`, `ebii`, and `jptl` must all have the same weight, and they do:
|
||||||
|
`61`.
|
||||||
|
|
||||||
|
However, for `tknk` to be balanced, each of the programs standing on its
|
||||||
|
disc *and all programs above it* must each match. This means that the
|
||||||
|
following sums must all be the same:
|
||||||
|
|
||||||
|
- `ugml` + (`gyxo` + `ebii` + `jptl`) = 68 + (61 + 61 + 61) = 251
|
||||||
|
- `padx` + (`pbga` + `havc` + `qoyq`) = 45 + (66 + 66 + 66) = 243
|
||||||
|
- `fwft` + (`ktlj` + `cntj` + `xhth`) = 72 + (57 + 57 + 57) = 243
|
||||||
|
|
||||||
|
As you can see, `tknk`\'s disc is unbalanced: `ugml`\'s stack is heavier
|
||||||
|
than the other two. Even though the nodes above `ugml` are balanced,
|
||||||
|
`ugml` itself is too heavy: it needs to be `8` units lighter for its
|
||||||
|
stack to weigh `243` and keep the towers balanced. If this change were
|
||||||
|
made, its weight would be `60`.
|
||||||
|
|
||||||
|
Given that exactly one program is the wrong weight, *what would its
|
||||||
|
weight need to be* to balance the entire tower?
|
||||||
|
|
||||||
|
Your puzzle answer was `299`.
|
||||||
|
|
||||||
|
Both parts of this puzzle are complete! They provide two gold stars:
|
||||||
|
\*\*
|
||||||
|
|
||||||
|
At this point, you should [return to your Advent calendar](/2017) and
|
||||||
|
try another puzzle.
|
||||||
|
|
||||||
|
If you still want to see it, you can [get your puzzle
|
||||||
|
input](7/input).
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
#!/bin/python3
|
#!/bin/python3
|
||||||
import sys, re
|
import sys, re
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
from collections import Counter
|
||||||
|
|
||||||
input_f = 'test'
|
input_f = 'input'
|
||||||
part = 2
|
part = 2
|
||||||
|
|
||||||
|
|
||||||
@ -11,7 +12,8 @@ part = 2
|
|||||||
# Part 1 #
|
# Part 1 #
|
||||||
# #
|
# #
|
||||||
#########################################
|
#########################################
|
||||||
if part == 1:
|
|
||||||
|
def part1():
|
||||||
children = []
|
children = []
|
||||||
mains = []
|
mains = []
|
||||||
with open(input_f)as file:
|
with open(input_f)as file:
|
||||||
@ -27,7 +29,10 @@ if part == 1:
|
|||||||
|
|
||||||
for x in mains:
|
for x in mains:
|
||||||
if x not in children:
|
if x not in children:
|
||||||
print(x)
|
return x
|
||||||
|
|
||||||
|
if part == 1:
|
||||||
|
print(part1())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -36,17 +41,136 @@ if part == 1:
|
|||||||
# Part 2 #
|
# Part 2 #
|
||||||
# #
|
# #
|
||||||
#########################################
|
#########################################
|
||||||
|
|
||||||
|
def find_children(x,grid):
|
||||||
|
# x will be a string like 'tknk'
|
||||||
|
print('Testing ',x)
|
||||||
|
found = []
|
||||||
|
for i in grid:
|
||||||
|
if i.startswith(x):
|
||||||
|
|
||||||
|
match = re.search(r"-> (.+)", i)
|
||||||
|
if match:
|
||||||
|
found = [item.strip() for item in match.group(1).split(",")]
|
||||||
|
print(found)
|
||||||
|
else:
|
||||||
|
print([i for i in grid if i.startswith(x)])
|
||||||
|
if found != None:
|
||||||
|
for j in found:
|
||||||
|
find_children(j,grid)
|
||||||
|
|
||||||
|
def calculate_weights(node, tree, weights, total_weights):
|
||||||
|
# Compute total weight for the current node
|
||||||
|
total = weights[node]
|
||||||
|
for child in tree[node]:
|
||||||
|
total += calculate_weights(child, tree, weights, total_weights)
|
||||||
|
total_weights[node] = total
|
||||||
|
return total
|
||||||
|
|
||||||
|
def find_outlier(lst):
|
||||||
|
count = Counter(lst)
|
||||||
|
outlier = None
|
||||||
|
reference = None
|
||||||
|
for num, freq in count.items():
|
||||||
|
if freq == 1 or freq < len(lst) - 1:
|
||||||
|
outlier = num
|
||||||
|
else:
|
||||||
|
reference = num
|
||||||
|
return outlier,reference
|
||||||
|
|
||||||
|
def find_unbalanced(node, tree, weights, total_weights):
|
||||||
|
child_weights = [total_weights[child] for child in tree[node]]
|
||||||
|
if len(set(child_weights)) == 1:
|
||||||
|
return None
|
||||||
|
|
||||||
|
weight_counts = {w: child_weights.count(w) for w in child_weights}
|
||||||
|
incorrect_weight = next(w for w, count in weight_counts.items() if count == 1)
|
||||||
|
correct_weight = next(w for w, count in weight_counts.items() if count > 1)
|
||||||
|
unbalanced_child = tree[node][child_weights.index(incorrect_weight)]
|
||||||
|
|
||||||
|
deeper_issue = find_unbalanced(unbalanced_child, tree, weights, total_weights)
|
||||||
|
if deeper_issue:
|
||||||
|
return deeper_issue
|
||||||
|
else:
|
||||||
|
return unbalanced_child, weights[unbalanced_child] + (correct_weight - incorrect_weight)
|
||||||
|
|
||||||
if part == 2:
|
if part == 2:
|
||||||
children = []
|
children = []
|
||||||
mains = []
|
mains = []
|
||||||
|
grid = []
|
||||||
with open(input_f)as file:
|
with open(input_f)as file:
|
||||||
for line in file:
|
for line in file:
|
||||||
l = line.rstrip()
|
l = line.rstrip()
|
||||||
if '->' in l:
|
grid.append(l)
|
||||||
x = l.split('->')
|
|
||||||
for i in x[1].split(','):
|
tree = {}
|
||||||
children.append(i.strip())
|
weights = {}
|
||||||
match = re.match(r"^(\S+)",x[0])
|
for line in grid:
|
||||||
if match:
|
match = re.match(r"(\w+) \((\d+)\)(?: -> (.+))?", line)
|
||||||
mains.append(match.group(1))
|
if match:
|
||||||
|
name = match.group(1)
|
||||||
|
weight = int(match.group(2))
|
||||||
|
children = match.group(3).split(", ") if match.group(3) else []
|
||||||
|
tree[name] = children
|
||||||
|
weights[name] = weight
|
||||||
|
|
||||||
|
total_weights = {}
|
||||||
|
|
||||||
|
calculate_weights(part1(),tree,weights,total_weights)
|
||||||
|
result = find_unbalanced(part1(), tree, weights, total_weights)
|
||||||
|
print(result)
|
||||||
|
#unbalanced_values = []
|
||||||
|
#for key,value in tree.items():
|
||||||
|
# if value:
|
||||||
|
# t_values = []
|
||||||
|
# max_v = 0
|
||||||
|
# change = 0
|
||||||
|
# for i in value:
|
||||||
|
# t_values.append(int(total_weights[i]))
|
||||||
|
# if all(v == t_values[0] for v in t_values):
|
||||||
|
# continue
|
||||||
|
# else:
|
||||||
|
# print('STOP')
|
||||||
|
# print(t_values)
|
||||||
|
# input()
|
||||||
|
# unbalanced_values.append(t_values)
|
||||||
|
|
||||||
|
|
||||||
|
#print(unbalanced_values)
|
||||||
|
#unbalanced_values = list(reversed(unbalanced_values))
|
||||||
|
#print(unbalanced_values)
|
||||||
|
|
||||||
|
#for t_values in unbalanced_values:
|
||||||
|
# outlier,reference = find_outlier(t_values)
|
||||||
|
# change = max(outlier,reference) - min(outlier,reference)
|
||||||
|
# max_v = max(outlier,reference)
|
||||||
|
|
||||||
|
#if t_values[0] == t_values[1]:
|
||||||
|
# if t_values[0] == t_values[2]:
|
||||||
|
# if t_values[1] == t_values[2]:
|
||||||
|
# change = t_values[1] - t_values[2]
|
||||||
|
# max_v = max(t_values[1],t_values[2])
|
||||||
|
# else:
|
||||||
|
# change = t_values[0]-t_values[2]
|
||||||
|
# max_v = max(t_values[0],t_values[2])
|
||||||
|
#else:
|
||||||
|
# change = t_values[0] - t_values[1]
|
||||||
|
# max_v = max(t_values[0],t_values[1])
|
||||||
|
|
||||||
|
# print(change)
|
||||||
|
# print(max_v)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# new_val = max_v-change
|
||||||
|
# print(new_val)
|
||||||
|
|
||||||
|
# for odx,o in enumerate(t_values):
|
||||||
|
# if o == max_v:
|
||||||
|
# total_weights[value[odx]] = new_val
|
||||||
|
|
||||||
|
#for kx,x in total_weights.items():
|
||||||
|
# if x == max_v:
|
||||||
|
# print(weights[kx])
|
||||||
|
# print(weights[kx]-change)
|
||||||
|
|
57
2017/08/8.md
Normal file
57
2017/08/8.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
## \-\-- Day 8: I Heard You Like Registers \-\--
|
||||||
|
|
||||||
|
You receive a signal
|
||||||
|
directly from the CPU. Because of your recent assistance with [jump
|
||||||
|
instructions](5), it would like you to compute the result of a series of
|
||||||
|
unusual register instructions.
|
||||||
|
|
||||||
|
Each instruction consists of several parts: the register to modify,
|
||||||
|
whether to increase or decrease that register\'s value, the amount by
|
||||||
|
which to increase or decrease it, and a condition. If the condition
|
||||||
|
fails, skip the instruction without modifying the register. The
|
||||||
|
registers all start at `0`. The instructions look like this:
|
||||||
|
|
||||||
|
b inc 5 if a > 1
|
||||||
|
a inc 1 if b < 5
|
||||||
|
c dec -10 if a >= 1
|
||||||
|
c inc -20 if c == 10
|
||||||
|
|
||||||
|
These instructions would be processed as follows:
|
||||||
|
|
||||||
|
- Because `a` starts at `0`, it is not greater than `1`, and so `b` is
|
||||||
|
not modified.
|
||||||
|
- `a` is increased by `1` (to `1`) because `b` is less than `5` (it is
|
||||||
|
`0`).
|
||||||
|
- `c` is decreased by `-10` (to `10`) because `a` is now greater than
|
||||||
|
or equal to `1` (it is `1`).
|
||||||
|
- `c` is increased by `-20` (to `-10`) because `c` is equal to `10`.
|
||||||
|
|
||||||
|
After this process, the largest value in any register is `1`.
|
||||||
|
|
||||||
|
You might also encounter `<=` (less than or equal to) or `!=` (not equal
|
||||||
|
to). However, the CPU doesn\'t have the bandwidth to tell you what all
|
||||||
|
the registers are named, and leaves that to you to determine.
|
||||||
|
|
||||||
|
*What is the largest value in any register* after completing the
|
||||||
|
instructions in your puzzle input?
|
||||||
|
|
||||||
|
Your puzzle answer was `4066`.
|
||||||
|
|
||||||
|
## \-\-- Part Two \-\-- {#part2}
|
||||||
|
|
||||||
|
To be safe, the CPU also needs to know *the highest value held in any
|
||||||
|
register during this process* so that it can decide how much memory to
|
||||||
|
allocate to these operations. For example, in the above instructions,
|
||||||
|
the highest value ever held was `10` (in register `c` after the third
|
||||||
|
instruction was evaluated).
|
||||||
|
|
||||||
|
Your puzzle answer was `4829`.
|
||||||
|
|
||||||
|
Both parts of this puzzle are complete! They provide two gold stars:
|
||||||
|
\*\*
|
||||||
|
|
||||||
|
At this point, you should [return to your Advent calendar](/2017) and
|
||||||
|
try another puzzle.
|
||||||
|
|
||||||
|
If you still want to see it, you can [get your puzzle
|
||||||
|
input](8/input).
|
136
2017/08/solution.py
Normal file
136
2017/08/solution.py
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
#!/bin/python3
|
||||||
|
import sys,re
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
input_f = 'input'
|
||||||
|
|
||||||
|
part = 2
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 1 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
|
||||||
|
if part == 1:
|
||||||
|
grid = []
|
||||||
|
values = {}
|
||||||
|
with open(input_f) as file:
|
||||||
|
for line in file:
|
||||||
|
grid.append(line.rstrip())
|
||||||
|
|
||||||
|
#pprint(grid)
|
||||||
|
|
||||||
|
|
||||||
|
pattern = r"(\w+)\s(inc|dec)\s(-?\d+)\sif\s(\w+)\s([<>=!]+)\s(-?\d+)"
|
||||||
|
|
||||||
|
# Process each instruction
|
||||||
|
for instruction in grid:
|
||||||
|
match = re.match(pattern, instruction)
|
||||||
|
if match:
|
||||||
|
input_var = match.group(1)
|
||||||
|
change = match.group(2)
|
||||||
|
value = int(match.group(3))
|
||||||
|
con1 = match.group(4)
|
||||||
|
con2 = match.group(5)
|
||||||
|
con3 = int(match.group(6))
|
||||||
|
|
||||||
|
#print(f"input = {input_var}, change = {change}, value = {value}, con1 = {con1}, con2 = {con2}, con3 = {con3}")
|
||||||
|
|
||||||
|
else:
|
||||||
|
print(instruction)
|
||||||
|
print('NO MATCH')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
#print(f"input = {input_var}, change = {change}, value = {value}, con1 = {con1}, con2 = {con2}, con3 = {con3}")
|
||||||
|
|
||||||
|
if input_var not in values:
|
||||||
|
values[input_var] = 0
|
||||||
|
if con1 not in values:
|
||||||
|
values[con1] = 0
|
||||||
|
|
||||||
|
condition = f"{values[con1]} {con2} {con3}"
|
||||||
|
|
||||||
|
#print('calculation =======',condition)
|
||||||
|
|
||||||
|
if eval(condition):
|
||||||
|
if change == 'inc':
|
||||||
|
values[input_var] += value
|
||||||
|
if change == 'dec':
|
||||||
|
values[input_var] -= value
|
||||||
|
|
||||||
|
|
||||||
|
#pprint(values)
|
||||||
|
max_v = 0
|
||||||
|
for key, i in values.items():
|
||||||
|
if max_v < i:
|
||||||
|
max_v = i
|
||||||
|
print(max_v)
|
||||||
|
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 2 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
|
||||||
|
def find_max(x):
|
||||||
|
#print(x)
|
||||||
|
max_v = 0
|
||||||
|
for key, i in values.items():
|
||||||
|
if max_v < i:
|
||||||
|
max_v = i
|
||||||
|
return max_v
|
||||||
|
|
||||||
|
if part == 2:
|
||||||
|
grid = []
|
||||||
|
values = {}
|
||||||
|
total_max = 0
|
||||||
|
with open(input_f) as file:
|
||||||
|
for line in file:
|
||||||
|
grid.append(line.rstrip())
|
||||||
|
|
||||||
|
#pprint(grid)
|
||||||
|
|
||||||
|
|
||||||
|
pattern = r"(\w+)\s(inc|dec)\s(-?\d+)\sif\s(\w+)\s([<>=!]+)\s(-?\d+)"
|
||||||
|
# Process each instruction
|
||||||
|
for instruction in grid:
|
||||||
|
match = re.match(pattern, instruction)
|
||||||
|
if match:
|
||||||
|
input_var = match.group(1)
|
||||||
|
change = match.group(2)
|
||||||
|
value = int(match.group(3))
|
||||||
|
con1 = match.group(4)
|
||||||
|
con2 = match.group(5)
|
||||||
|
con3 = int(match.group(6))
|
||||||
|
|
||||||
|
#print(f"input = {input_var}, change = {change}, value = {value}, con1 = {con1}, con2 = {con2}, con3 = {con3}")
|
||||||
|
|
||||||
|
else:
|
||||||
|
print(instruction)
|
||||||
|
print('NO MATCH')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
#print(f"input = {input_var}, change = {change}, value = {value}, con1 = {con1}, con2 = {con2}, con3 = {con3}")
|
||||||
|
|
||||||
|
if input_var not in values:
|
||||||
|
values[input_var] = 0
|
||||||
|
if con1 not in values:
|
||||||
|
values[con1] = 0
|
||||||
|
|
||||||
|
condition = f"{values[con1]} {con2} {con3}"
|
||||||
|
|
||||||
|
#print('calculation =======',condition)
|
||||||
|
|
||||||
|
if eval(condition):
|
||||||
|
if change == 'inc':
|
||||||
|
values[input_var] += value
|
||||||
|
if change == 'dec':
|
||||||
|
values[input_var] -= value
|
||||||
|
|
||||||
|
temp_max = find_max(values)
|
||||||
|
if total_max < temp_max:
|
||||||
|
total_max = temp_max
|
||||||
|
#print('New Max Found',total_max)
|
||||||
|
print(total_max)
|
||||||
|
#pprint(values)
|
||||||
|
|
103
2017/09/9.md
Normal file
103
2017/09/9.md
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
## \-\-- Day 9: Stream Processing \-\--
|
||||||
|
|
||||||
|
A large stream blocks your path. According to the locals, it\'s not safe
|
||||||
|
to [cross the
|
||||||
|
stream]{title="\"Don't cross the streams!\", they yell, even though there's only one. They seem to think they're hilarious."}
|
||||||
|
at the moment because it\'s full of *garbage*. You look down at the
|
||||||
|
stream; rather than water, you discover that it\'s a *stream of
|
||||||
|
characters*.
|
||||||
|
|
||||||
|
You sit for a while and record part of the stream (your puzzle input).
|
||||||
|
The characters represent *groups* - sequences that begin with `{` and
|
||||||
|
end with `}`. Within a group, there are zero or more other things,
|
||||||
|
separated by commas: either another *group* or *garbage*. Since groups
|
||||||
|
can contain other groups, a `}` only closes the *most-recently-opened
|
||||||
|
unclosed group* - that is, they are nestable. Your puzzle input
|
||||||
|
represents a single, large group which itself contains many smaller
|
||||||
|
ones.
|
||||||
|
|
||||||
|
Sometimes, instead of a group, you will find *garbage*. Garbage begins
|
||||||
|
with `<` and ends with `>`. Between those angle brackets, almost any
|
||||||
|
character can appear, including `{` and `}`. *Within* garbage, `<` has
|
||||||
|
no special meaning.
|
||||||
|
|
||||||
|
In a futile attempt to clean up the garbage, some program has *canceled*
|
||||||
|
some of the characters within it using `!`: inside garbage, *any*
|
||||||
|
character that comes after `!` should be *ignored*, including `<`, `>`,
|
||||||
|
and even another `!`.
|
||||||
|
|
||||||
|
You don\'t see any characters that deviate from these rules. Outside
|
||||||
|
garbage, you only find well-formed groups, and garbage always terminates
|
||||||
|
according to the rules above.
|
||||||
|
|
||||||
|
Here are some self-contained pieces of garbage:
|
||||||
|
|
||||||
|
- `<>`, empty garbage.
|
||||||
|
- `<random characters>`, garbage containing random characters.
|
||||||
|
- `<<<<>`, because the extra `<` are ignored.
|
||||||
|
- `<{!>}>`, because the first `>` is canceled.
|
||||||
|
- `<!!>`, because the second `!` is canceled, allowing the `>` to
|
||||||
|
terminate the garbage.
|
||||||
|
- `<!!!>>`, because the second `!` and the first `>` are canceled.
|
||||||
|
- `<{o"i!a,<{i<a>`, which ends at the first `>`.
|
||||||
|
|
||||||
|
Here are some examples of whole streams and the number of groups they
|
||||||
|
contain:
|
||||||
|
|
||||||
|
- `{}`, `1` group.
|
||||||
|
- `{{{}}}`, `3` groups.
|
||||||
|
- `{{},{}}`, also `3` groups.
|
||||||
|
- `{{{},{},{{}}}}`, `6` groups.
|
||||||
|
- `{<{},{},{{}}>}`, `1` group (which itself contains garbage).
|
||||||
|
- `{<a>,<a>,<a>,<a>}`, `1` group.
|
||||||
|
- `{{<a>},{<a>},{<a>},{<a>}}`, `5` groups.
|
||||||
|
- `{{<!>},{<!>},{<!>},{<a>}}`, `2` groups (since all but the last `>`
|
||||||
|
are canceled).
|
||||||
|
|
||||||
|
Your goal is to find the total score for all groups in your input. Each
|
||||||
|
group is assigned a *score* which is one more than the score of the
|
||||||
|
group that immediately contains it. (The outermost group gets a score of
|
||||||
|
`1`.)
|
||||||
|
|
||||||
|
- `{}`, score of `1`.
|
||||||
|
- `{{{}}}`, score of `1 + 2 + 3 = 6`.
|
||||||
|
- `{{},{}}`, score of `1 + 2 + 2 = 5`.
|
||||||
|
- `{{{},{},{{}}}}`, score of `1 + 2 + 3 + 3 + 3 + 4 = 16`.
|
||||||
|
- `{<a>,<a>,<a>,<a>}`, score of `1`.
|
||||||
|
- `{{<ab>},{<ab>},{<ab>},{<ab>}}`, score of `1 + 2 + 2 + 2 + 2 = 9`.
|
||||||
|
- `{{<!!>},{<!!>},{<!!>},{<!!>}}`, score of `1 + 2 + 2 + 2 + 2 = 9`.
|
||||||
|
- `{{<a!>},{<a!>},{<a!>},{<ab>}}`, score of `1 + 2 = 3`.
|
||||||
|
|
||||||
|
*What is the total score* for all groups in your input?
|
||||||
|
|
||||||
|
Your puzzle answer was `11898`.
|
||||||
|
|
||||||
|
## \-\-- Part Two \-\-- {#part2}
|
||||||
|
|
||||||
|
Now, you\'re ready to remove the garbage.
|
||||||
|
|
||||||
|
To prove you\'ve removed it, you need to count all of the characters
|
||||||
|
within the garbage. The leading and trailing `<` and `>` don\'t count,
|
||||||
|
nor do any canceled characters or the `!` doing the canceling.
|
||||||
|
|
||||||
|
- `<>`, `0` characters.
|
||||||
|
- `<random characters>`, `17` characters.
|
||||||
|
- `<<<<>`, `3` characters.
|
||||||
|
- `<{!>}>`, `2` characters.
|
||||||
|
- `<!!>`, `0` characters.
|
||||||
|
- `<!!!>>`, `0` characters.
|
||||||
|
- `<{o"i!a,<{i<a>`, `10` characters.
|
||||||
|
|
||||||
|
*How many non-canceled characters are within the garbage* in your puzzle
|
||||||
|
input?
|
||||||
|
|
||||||
|
Your puzzle answer was `5601`.
|
||||||
|
|
||||||
|
Both parts of this puzzle are complete! They provide two gold stars:
|
||||||
|
\*\*
|
||||||
|
|
||||||
|
At this point, you should [return to your Advent calendar](/2017) and
|
||||||
|
try another puzzle.
|
||||||
|
|
||||||
|
If you still want to see it, you can [get your puzzle
|
||||||
|
input](9/input).
|
46
2017/09/solution.py
Normal file
46
2017/09/solution.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#!/bin/python3
|
||||||
|
import sys,re
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
input_f = 'input'
|
||||||
|
|
||||||
|
part = 2
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 1 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
if part == 1:
|
||||||
|
with open(input_f) as file:
|
||||||
|
for line in file:
|
||||||
|
clean_string = re.sub(r"!.", "", line.rstrip())
|
||||||
|
clean_string = re.sub(r"<.*?>", "", clean_string)
|
||||||
|
clean_string = re.sub(r",", "", clean_string)
|
||||||
|
level = 0
|
||||||
|
numbers = []
|
||||||
|
for i in clean_string:
|
||||||
|
if i == '{':
|
||||||
|
level += 1
|
||||||
|
if i == '}':
|
||||||
|
numbers.append(level)
|
||||||
|
level -= 1
|
||||||
|
|
||||||
|
print(sum(numbers))
|
||||||
|
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 2 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
if part == 2:
|
||||||
|
with open(input_f) as file:
|
||||||
|
for line in file:
|
||||||
|
#print(line.rstrip(), end=' ')
|
||||||
|
length = 0
|
||||||
|
clean_string = line.rstrip()
|
||||||
|
clean_string = re.sub(r"!.",'',clean_string)
|
||||||
|
clean_string = re.findall(r"<(.*?)>", clean_string)
|
||||||
|
|
||||||
|
for i in clean_string:
|
||||||
|
length += len(i)
|
||||||
|
print(length)
|
7
2017/09/test2
Normal file
7
2017/09/test2
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<>
|
||||||
|
<random characters>
|
||||||
|
<<<<>
|
||||||
|
<{!>}>
|
||||||
|
<!!>
|
||||||
|
<!!!>>
|
||||||
|
<{o"i!a,<{i<a>
|
169
2017/10/10.md
Normal file
169
2017/10/10.md
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
## \-\-- Day 10: Knot Hash \-\--
|
||||||
|
|
||||||
|
You come across some programs that are trying to implement a software
|
||||||
|
emulation of a hash based on knot-tying. The hash these programs are
|
||||||
|
implementing isn\'t very strong, but you decide to help them anyway. You
|
||||||
|
make a mental note to remind the Elves later not to [invent their own
|
||||||
|
cryptographic functions]{title="NEW CRYPTOSYSTEM WHO DIS"}.
|
||||||
|
|
||||||
|
This hash function simulates tying a knot in a circle of string with 256
|
||||||
|
marks on it. Based on the input to be hashed, the function repeatedly
|
||||||
|
selects a span of string, brings the ends together, and gives the span a
|
||||||
|
half-twist to reverse the order of the marks within it. After doing this
|
||||||
|
many times, the order of the marks is used to build the resulting hash.
|
||||||
|
|
||||||
|
4--5 pinch 4 5 4 1
|
||||||
|
/ \ 5,0,1 / \/ \ twist / \ / \
|
||||||
|
3 0 --> 3 0 --> 3 X 0
|
||||||
|
\ / \ /\ / \ / \ /
|
||||||
|
2--1 2 1 2 5
|
||||||
|
|
||||||
|
To achieve this, begin with a *list* of numbers from `0` to `255`, a
|
||||||
|
*current position* which begins at `0` (the first element in the list),
|
||||||
|
a *skip size* (which starts at `0`), and a sequence of *lengths* (your
|
||||||
|
puzzle input). Then, for each length:
|
||||||
|
|
||||||
|
- *Reverse* the order of that *length* of elements in the *list*,
|
||||||
|
starting with the element at the *current position*.
|
||||||
|
- *Move* the *current position* forward by that *length* plus the
|
||||||
|
*skip size*.
|
||||||
|
- *Increase* the *skip size* by one.
|
||||||
|
|
||||||
|
The *list* is circular; if the *current position* and the *length* try
|
||||||
|
to reverse elements beyond the end of the list, the operation reverses
|
||||||
|
using as many extra elements as it needs from the front of the list. If
|
||||||
|
the *current position* moves past the end of the list, it wraps around
|
||||||
|
to the front. *Lengths* larger than the size of the *list* are invalid.
|
||||||
|
|
||||||
|
Here\'s an example using a smaller list:
|
||||||
|
|
||||||
|
Suppose we instead only had a circular list containing five elements,
|
||||||
|
`0, 1, 2, 3, 4`, and were given input lengths of `3, 4, 1, 5`.
|
||||||
|
|
||||||
|
- The list begins as `[0] 1 2 3 4` (where square brackets indicate the
|
||||||
|
*current position*).
|
||||||
|
- The first length, `3`, selects `([0] 1 2) 3 4` (where parentheses
|
||||||
|
indicate the sublist to be reversed).
|
||||||
|
- After reversing that section (`0 1 2` into `2 1 0`), we get
|
||||||
|
`([2] 1 0) 3 4`.
|
||||||
|
- Then, the *current position* moves forward by the *length*, `3`,
|
||||||
|
plus the *skip size*, 0: `2 1 0 [3] 4`. Finally, the *skip size*
|
||||||
|
increases to `1`.
|
||||||
|
|
||||||
|
```{=html}
|
||||||
|
<!-- -->
|
||||||
|
```
|
||||||
|
- The second length, `4`, selects a section which wraps:
|
||||||
|
`2 1) 0 ([3] 4`.
|
||||||
|
- The sublist `3 4 2 1` is reversed to form `1 2 4 3`:
|
||||||
|
`4 3) 0 ([1] 2`.
|
||||||
|
- The *current position* moves forward by the *length* plus the *skip
|
||||||
|
size*, a total of `5`, causing it not to move because it wraps
|
||||||
|
around: `4 3 0 [1] 2`. The *skip size* increases to `2`.
|
||||||
|
|
||||||
|
```{=html}
|
||||||
|
<!-- -->
|
||||||
|
```
|
||||||
|
- The third length, `1`, selects a sublist of a single element, and so
|
||||||
|
reversing it has no effect.
|
||||||
|
- The *current position* moves forward by the *length* (`1`) plus the
|
||||||
|
*skip size* (`2`): `4 [3] 0 1 2`. The *skip size* increases to `3`.
|
||||||
|
|
||||||
|
```{=html}
|
||||||
|
<!-- -->
|
||||||
|
```
|
||||||
|
- The fourth length, `5`, selects every element starting with the
|
||||||
|
second: `4) ([3] 0 1 2`. Reversing this sublist (`3 0 1 2 4` into
|
||||||
|
`4 2 1 0 3`) produces: `3) ([4] 2 1 0`.
|
||||||
|
- Finally, the *current position* moves forward by `8`: `3 4 2 1 [0]`.
|
||||||
|
The *skip size* increases to `4`.
|
||||||
|
|
||||||
|
In this example, the first two numbers in the list end up being `3` and
|
||||||
|
`4`; to check the process, you can multiply them together to produce
|
||||||
|
`12`.
|
||||||
|
|
||||||
|
However, you should instead use the standard list size of `256` (with
|
||||||
|
values `0` to `255`) and the sequence of *lengths* in your puzzle input.
|
||||||
|
Once this process is complete, *what is the result of multiplying the
|
||||||
|
first two numbers in the list*?
|
||||||
|
|
||||||
|
Your puzzle answer was `19591`.
|
||||||
|
|
||||||
|
The first half of this puzzle is complete! It provides one gold star: \*
|
||||||
|
|
||||||
|
## \-\-- Part Two \-\-- {#part2}
|
||||||
|
|
||||||
|
The logic you\'ve constructed forms a single *round* of the *Knot Hash*
|
||||||
|
algorithm; running the full thing requires many of these rounds. Some
|
||||||
|
input and output processing is also required.
|
||||||
|
|
||||||
|
First, from now on, your input should be taken not as a list of numbers,
|
||||||
|
but as a string of bytes instead. Unless otherwise specified, convert
|
||||||
|
characters to bytes using their [ASCII
|
||||||
|
codes](https://en.wikipedia.org/wiki/ASCII#Printable_characters). This
|
||||||
|
will allow you to handle arbitrary ASCII strings, and it also ensures
|
||||||
|
that your input lengths are never larger than `255`. For example, if you
|
||||||
|
are given `1,2,3`, you should convert it to the ASCII codes for each
|
||||||
|
character: `49,44,50,44,51`.
|
||||||
|
|
||||||
|
Once you have determined the sequence of lengths to use, add the
|
||||||
|
following lengths to the end of the sequence: `17, 31, 73, 47, 23`. For
|
||||||
|
example, if you are given `1,2,3`, your final sequence of lengths should
|
||||||
|
be `49,44,50,44,51,17,31,73,47,23` (the ASCII codes from the input
|
||||||
|
string combined with the standard length suffix values).
|
||||||
|
|
||||||
|
Second, instead of merely running one *round* like you did above, run a
|
||||||
|
total of `64` rounds, using the same *length* sequence in each round.
|
||||||
|
The *current position* and *skip size* should be preserved between
|
||||||
|
rounds. For example, if the previous example was your first round, you
|
||||||
|
would start your second round with the same *length* sequence
|
||||||
|
(`3, 4, 1, 5, 17, 31, 73, 47, 23`, now assuming they came from ASCII
|
||||||
|
codes and include the suffix), but start with the previous round\'s
|
||||||
|
*current position* (`4`) and *skip size* (`4`).
|
||||||
|
|
||||||
|
Once the rounds are complete, you will be left with the numbers from `0`
|
||||||
|
to `255` in some order, called the *sparse hash*. Your next task is to
|
||||||
|
reduce these to a list of only `16` numbers called the *dense hash*. To
|
||||||
|
do this, use numeric bitwise
|
||||||
|
[XOR](https://en.wikipedia.org/wiki/Bitwise_operation#XOR) to combine
|
||||||
|
each consecutive block of `16` numbers in the sparse hash (there are
|
||||||
|
`16` such blocks in a list of `256` numbers). So, the first element in
|
||||||
|
the dense hash is the first sixteen elements of the sparse hash XOR\'d
|
||||||
|
together, the second element in the dense hash is the second sixteen
|
||||||
|
elements of the sparse hash XOR\'d together, etc.
|
||||||
|
|
||||||
|
For example, if the first sixteen elements of your sparse hash are as
|
||||||
|
shown below, and the XOR operator is `^`, you would calculate the first
|
||||||
|
output number like this:
|
||||||
|
|
||||||
|
65 ^ 27 ^ 9 ^ 1 ^ 4 ^ 3 ^ 40 ^ 50 ^ 91 ^ 7 ^ 6 ^ 0 ^ 2 ^ 5 ^ 68 ^ 22 = 64
|
||||||
|
|
||||||
|
Perform this operation on each of the sixteen blocks of sixteen numbers
|
||||||
|
in your sparse hash to determine the sixteen numbers in your dense hash.
|
||||||
|
|
||||||
|
Finally, the standard way to represent a Knot Hash is as a single
|
||||||
|
[hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) string; the
|
||||||
|
final output is the dense hash in hexadecimal notation. Because each
|
||||||
|
number in your dense hash will be between `0` and `255` (inclusive),
|
||||||
|
always represent each number as two hexadecimal digits (including a
|
||||||
|
leading zero as necessary). So, if your first three numbers are
|
||||||
|
`64, 7, 255`, they correspond to the hexadecimal numbers `40, 07, ff`,
|
||||||
|
and so the first six characters of the hash would be `4007ff`. Because
|
||||||
|
every Knot Hash is sixteen such numbers, the hexadecimal representation
|
||||||
|
is always `32` hexadecimal digits (`0`-`f`) long.
|
||||||
|
|
||||||
|
Here are some example hashes:
|
||||||
|
|
||||||
|
- The empty string becomes `a2582a3a0e66e6e86e3812dcb672a272`.
|
||||||
|
- `AoC 2017` becomes `33efeb34ea91902bb2f59c9920caa6cd`.
|
||||||
|
- `1,2,3` becomes `3efbe78a8d82f29979031a4aa0b16a9d`.
|
||||||
|
- `1,2,4` becomes `63960835bcdc130f0b66d7ff4f6a5a8e`.
|
||||||
|
|
||||||
|
Treating your puzzle input as a string of ASCII characters, *what is the
|
||||||
|
Knot Hash of your puzzle input?* Ignore any leading or trailing
|
||||||
|
whitespace you might encounter.
|
||||||
|
|
||||||
|
Answer:
|
||||||
|
|
||||||
|
Although it hasn\'t changed, you can still [get your puzzle
|
||||||
|
input](10/input).
|
49
2017/10/solution.py
Normal file
49
2017/10/solution.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/python3
|
||||||
|
import sys,re
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
input_f = 'input'
|
||||||
|
|
||||||
|
def list2int(x):
|
||||||
|
return list(map(int, x))
|
||||||
|
|
||||||
|
part = 1
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 1 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
|
||||||
|
if part == 1:
|
||||||
|
|
||||||
|
size = 256
|
||||||
|
lengths = []
|
||||||
|
skip = 0
|
||||||
|
numbers = []
|
||||||
|
pos = 0
|
||||||
|
for i in range(0,size):
|
||||||
|
numbers.append(i)
|
||||||
|
|
||||||
|
with open(input_f) as file:
|
||||||
|
for line in file:
|
||||||
|
lengths = list2int(line.rsplit()[0].split(','))
|
||||||
|
|
||||||
|
for ldx, length in enumerate(lengths):
|
||||||
|
sub = [numbers[(pos + i) % len(numbers)] for i in range(length)]
|
||||||
|
rev = sub[::-1]
|
||||||
|
|
||||||
|
for i in range(length):
|
||||||
|
numbers[(pos + i) % len(numbers)] = rev[i]
|
||||||
|
|
||||||
|
pos += (length+skip)
|
||||||
|
pos = pos % len(numbers)
|
||||||
|
skip += 1
|
||||||
|
print(numbers[0]*numbers[1])
|
||||||
|
|
||||||
|
#########################################
|
||||||
|
# #
|
||||||
|
# Part 2 #
|
||||||
|
# #
|
||||||
|
#########################################
|
||||||
|
if part == 2:
|
||||||
|
exit()
|
@ -1,16 +1,17 @@
|
|||||||
#!/bin/python3
|
#!/bin/python3
|
||||||
import sys
|
import sys,re
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
|
||||||
input_f = sys.argv[1]
|
input_f = 'test'
|
||||||
|
|
||||||
|
|
||||||
|
part = 1
|
||||||
#########################################
|
#########################################
|
||||||
# #
|
# #
|
||||||
# Part 1 #
|
# Part 1 #
|
||||||
# #
|
# #
|
||||||
#########################################
|
#########################################
|
||||||
|
|
||||||
|
if part == 1
|
||||||
with open(input_f) as file:
|
with open(input_f) as file:
|
||||||
for line in file:
|
for line in file:
|
||||||
|
|
||||||
@ -22,3 +23,5 @@ with open(input_f) as file:
|
|||||||
# Part 2 #
|
# Part 2 #
|
||||||
# #
|
# #
|
||||||
#########################################
|
#########################################
|
||||||
|
if part == 2:
|
||||||
|
exit()
|
||||||
|
Loading…
Reference in New Issue
Block a user