Compare commits

..

7 Commits

Author SHA1 Message Date
4c87065d03 Updated 2017 2024-11-16 08:05:16 +01:00
7b023710bb Added 2017/03 Part 2 2024-11-16 08:04:51 +01:00
3901ccc70e Added 2017/06 2024-11-15 19:41:45 +01:00
e36ec10c6f Added 2017/05 2024-11-15 18:28:48 +01:00
cf139d7a9d Updated template 2024-11-15 17:13:32 +01:00
ca17d18358 Added 2017/04 2024-11-15 17:10:56 +01:00
931dbde893 Added 2017/03 2024-11-15 16:47:27 +01:00
17 changed files with 767 additions and 5 deletions

View File

@ -31,7 +31,6 @@ sum = 0
with open(input_f) as file: with open(input_f) as file:
for line in file: for line in file:
line = list(map(int,line.rstrip('\n').split())) line = list(map(int,line.rstrip('\n').split()))
print(line)
for idx,i in enumerate(line): for idx,i in enumerate(line):
length=len(line) length=len(line)
for j in range(0,length): for j in range(0,length):

77
2017/03/3.md Normal file
View File

@ -0,0 +1,77 @@
## \-\-- Day 3: Spiral Memory \-\--
You come across an experimental new kind of memory stored on an
[infinite two-dimensional
grid]{title="Good thing we have all these infinite two-dimensional grids lying around!"}.
Each square on the grid is allocated in a spiral pattern starting at a
location marked `1` and then counting up while spiraling outward. For
example, the first few squares are allocated like this:
17 16 15 14 13
18 5 4 3 12
19 6 1 2 11
20 7 8 9 10
21 22 23---> ...
While this is very space-efficient (no squares are skipped), requested
data must be carried back to square `1` (the location of the only access
port for this memory system) by programs that can only move up, down,
left, or right. They always take the shortest path: the [Manhattan
Distance](https://en.wikipedia.org/wiki/Taxicab_geometry) between the
location of the data and square `1`.
For example:
- Data from square `1` is carried `0` steps, since it\'s at the access
port.
- Data from square `12` is carried `3` steps, such as: down, left,
left.
- Data from square `23` is carried only `2` steps: up twice.
- Data from square `1024` must be carried `31` steps.
*How many steps* are required to carry the data from the square
identified in your puzzle input all the way to the access port?
Your puzzle answer was `371`.
## \-\-- Part Two \-\-- {#part2}
As a stress test on the system, the programs here clear the grid and
then store the value `1` in square `1`. Then, in the same allocation
order as shown above, they store the sum of the values in all adjacent
squares, including diagonals.
So, the first few squares\' values are chosen as follows:
- Square `1` starts with the value `1`.
- Square `2` has only one adjacent filled square (with value `1`), so
it also stores `1`.
- Square `3` has both of the above squares as neighbors and stores the
sum of their values, `2`.
- Square `4` has all three of the aforementioned squares as neighbors
and stores the sum of their values, `4`.
- Square `5` only has the first and fourth squares as neighbors, so it
gets the value `5`.
Once a square is written, its value does not change. Therefore, the
first few squares would receive the following values:
147 142 133 122 59
304 5 4 2 57
330 10 1 1 54
351 11 23 25 26
362 747 806---> ...
What is the *first value written* that is *larger* than your puzzle
input?
Your puzzle answer was `369601`.
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.
Your puzzle input was `368078`{.puzzle-input}.

56
2017/03/solution.py Normal file
View File

@ -0,0 +1,56 @@
#!/bin/python3
import sys
from pprint import pprint
import numpy as np
import math
def manhattan_distance(a, b):
return np.abs(a - b).sum()
def spiral_ccw(A):
A = np.array(A)
out = []
while(A.size):
out.append(A[0][::-1]) # first row reversed
A = A[1:][::-1].T # cut off first row and rotate clockwise
return np.concatenate(out)
def base_spiral(nrow, ncol):
return spiral_ccw(np.arange(nrow*ncol).reshape(nrow,ncol))[::-1]
def to_spiral(A):
A = np.array(A)
B = np.empty_like(A)
B.flat[base_spiral(*A.shape)] = A.flat
return B
input_f = sys.argv[1]
#########################################
# #
# Part 1 #
# #
#########################################
number = int(input_f)
org = number
while not math.sqrt(number).is_integer():
number+=1
mid = int((math.sqrt(number)-1)/2)
length = int(math.sqrt(number))
a = [mid, mid]
arr = to_spiral(np.arange(1,number+1).reshape(length,length))
b = np.where(arr == org)
print(manhattan_distance(np.array(a),np.array([b[0][0],b[1][0]])))
#########################################
# #
# Part 2 #
# #
#########################################

132
2017/03/solution2.py Normal file
View File

@ -0,0 +1,132 @@
#!/bin/python3
import sys
from pprint import pprint
import numpy as np
from math import ceil, sqrt
from itertools import cycle, count
import copy
def manhattan_distance(a, b):
return np.abs(a - b).sum()
def spiral_distances():
"""
Yields 1, 1, 2, 2, 3, 3, ...
"""
for distance in count(1):
for _ in (0, 1):
yield distance
def clockwise_directions():
"""
Yields right, down, left, up, right, down, left, up, right, ...
"""
left = (-1, 0)
right = (1, 0)
up = (0, -1)
down = (0, 1)
return cycle((right, up, left, down))
def spiral_movements():
"""
Yields each individual movement to make a spiral:
right, down, left, left, up, up, right, right, right, down, down, down, ...
"""
for distance, direction in zip(spiral_distances(), clockwise_directions()):
for _ in range(distance):
yield direction
def square(width):
"""
Returns a width x width 2D list filled with Nones
"""
return [[None] * width for _ in range(width)]
def spiral(inp):
width = int(ceil(sqrt(len(inp))))
print(width)
result = square(width)
x = width // 2
y = width // 2
for value, movement in zip(inp, spiral_movements()):
result[y][x] = value
dx, dy = movement
x += dx
y += dy
return result
def find_index(array, value):
for i, row in enumerate(array): # Loop through rows with their indices
for j, element in enumerate(row): # Loop through elements with their indices
if element == value: # Check if the element matches the value
return (i, j) # Return the row and column indices
return None # Return None if the value is not found
input_f = sys.argv[1]
number = int(input_f)
org = number
while not sqrt(number).is_integer():
number+=1
mid = int((sqrt(number)-1)/2)
length = int(sqrt(number))
a = [mid, mid]
ina = np.arange(1,number+1)
arr = spiral(ina)
pprint(np.array(arr))
tmp_arr = copy.deepcopy(arr)
for idx,i in enumerate(tmp_arr):
for jdx,j in enumerate(tmp_arr):
tmp_arr[jdx][idx] = 0
count = 1
x,y = find_index(arr,count)
tmp_arr[mid][mid] = 1
while True:
#pprint(np.array(arr))
#pprint(np.array(tmp_arr))
tmp = 0
x,y = find_index(arr,count)
#print(x,y)
#print("count:",count)
#print("arr:",arr[x][y])
#print("tmp_arr",tmp_arr[x][y])
# x y cant be negative. change x y everywhere to temp x y values and check they aren't negative.
cords = [[x+1,y],[x-1,y],[x,y+1],[x,y-1],[x+1,y+1],[x+1,y-1],[x-1,y+1],[x-1,y-1]]
for c in cords:
#print(c)
try:
if c[0] < 0 or c[1] < 0:
raise ValueError('Negative')
if tmp_arr[c[0]][c[1]] != 0:
#print(tmp_arr[c[0]][c[1]])
#print(c)
tmp+=tmp_arr[c[0]][c[1]]
#print("tmp:",tmp)
except Exception as e:
print('Error1',e)
tmp_arr[x][y] += tmp
if tmp > org:
print('Value:',tmp)
print('Org:',org)
exit()
#print(np.array(tmp_arr))
count += 1
#input()

7
2017/03/test2 Normal file
View File

@ -0,0 +1,7 @@
37 36 35 34 33 32 31
38 17 16 15 14 13 30
39 18 05 04 03 12 29
40 19 06 01 02 11 28
41 20 07 08 09 10 27
42 21 22 23 24 25 26
43 44 45 46 47 48 49

9
2017/03/test3 Normal file
View File

@ -0,0 +1,9 @@
65 64 63 62 61 60 59 58 57
66 37 36 35 34 33 32 31 56
67 38 17 16 15 14 13 30 55
68 39 18 05 04 03 12 29 54
69 40 19 06 01 02 11 28 53
70 41 20 07 08 09 10 27 52
71 42 21 22 23 24 25 26 51
72 43 44 45 46 47 48 49 50
73 74 75 76 77 78 79 80 81

53
2017/04/4.md Normal file
View File

@ -0,0 +1,53 @@
## \-\-- Day 4: High-Entropy Passphrases \-\--
A new system policy has been put in place that requires all accounts to
use a *passphrase* instead of simply a pass*word*. A passphrase consists
of a series of words (lowercase letters) separated by spaces.
To ensure security, a valid passphrase must contain no duplicate words.
For example:
- `aa bb cc dd ee` is valid.
- `aa bb cc dd aa` is not valid - the word `aa` appears more than
once.
- `aa bb cc dd aaa` is valid - `aa` and `aaa` count as different
words.
The system\'s full passphrase list is available as your puzzle input.
*How many passphrases are valid?*
Your puzzle answer was `383`.
## \-\-- Part Two \-\-- {#part2}
For added security, [yet another system
policy]{title="Because as everyone knows, the number of rules is proportional to the level of security."}
has been put in place. Now, a valid passphrase must contain no two words
that are anagrams of each other - that is, a passphrase is invalid if
any word\'s letters can be rearranged to form any other word in the
passphrase.
For example:
- `abcde fghij` is a valid passphrase.
- `abcde xyz ecdab` is not valid - the letters from the third word can
be rearranged to form the first word.
- `a ab abc abd abf abj` is a valid passphrase, because *all* letters
need to be used when forming another word.
- `iiii oiii ooii oooi oooo` is valid.
- `oiii ioii iioi iiio` is not valid - any of these words can be
rearranged to form any other word.
Under this new system policy, *how many passphrases are valid?*
Your puzzle answer was `265`.
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](4/input).

40
2017/04/solution.py Normal file
View File

@ -0,0 +1,40 @@
#!/bin/python3
import sys
from pprint import pprint
import numpy as np
input_f = sys.argv[1]
count = 0
#########################################
# #
# Part 1 #
# #
#########################################
with open(input_f) as file:
for line in file:
line = line.rstrip().split()
u,c = np.unique(line,return_counts=True)
if u[c > 1].size == 0:
count += 1
print(count)
#########################################
# #
# Part 2 #
# #
#########################################
count = 0
with open(input_f) as file:
for line in file:
line = line.rstrip().split()
for idx,x in enumerate(line):
line[idx] = ''.join(sorted(x))
u,c = np.unique(line,return_counts=True)
if u[c > 1].size == 0:
count += 1
print(count)

5
2017/04/test2 Normal file
View File

@ -0,0 +1,5 @@
abcde fghij
abcde xyz ecdab
a ab abc abd abf abj
iiii oiii ooii oooi oooo
oiii ioii iioi iiio

70
2017/05/5.md Normal file
View File

@ -0,0 +1,70 @@
## \-\-- Day 5: A Maze of Twisty Trampolines, All Alike \-\--
An urgent
interrupt arrives
from the CPU: it\'s trapped in a maze of jump instructions, and it would
like assistance from any programs with spare cycles to help find the
exit.
The message includes a list of the offsets for each jump. Jumps are
relative: `-1` moves to the previous instruction, and `2` skips the next
one. Start at the first instruction in the list. The goal is to follow
the jumps until one leads *outside* the list.
In addition, these instructions are a little strange; after each jump,
the offset of that instruction increases by `1`. So, if you come across
an offset of `3`, you would move three instructions forward, but change
it to a `4` for the next time it is encountered.
For example, consider the following list of jump offsets:
0
3
0
1
-3
Positive jumps (\"forward\") move downward; negative jumps move upward.
For legibility in this example, these offset values will be written all
on one line, with the current instruction marked in parentheses. The
following steps would be taken before an exit is found:
- `(0) 3  0  1  -3 ` - *before* we have taken any steps.
- `(1) 3  0  1  -3 ` - jump with offset `0` (that is, don\'t jump at
all). Fortunately, the instruction is then incremented to `1`.
- ` 2 (3) 0  1  -3 ` - step forward because of the instruction we just
modified. The first instruction is incremented again, now to `2`.
- ` 2  4  0  1 (-3)` - jump all the way to the end; leave a `4`
behind.
- ` 2 (4) 0  1  -2 ` - go back to where we just were; increment `-3`
to `-2`.
- ` 2  5  0  1  -2 ` - jump `4` steps forward, escaping the maze.
In this example, the exit is reached in `5` steps.
*How many steps* does it take to reach the exit?
Your puzzle answer was `381680`.
## \-\-- Part Two \-\-- {#part2}
Now, the jumps are even stranger: after each jump, if the offset was
*three or more*, instead *decrease* it by `1`. Otherwise, increase it by
`1` as before.
Using this rule with the above example, the process now takes `10`
steps, and the offset values after finding the exit are left as
`2 3 2 3 -1`.
*How many steps* does it now take to reach the exit?
Your puzzle answer was `29717847`.
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](5/input).

85
2017/05/solution.py Normal file
View File

@ -0,0 +1,85 @@
#!/bin/python3
import sys
from pprint import pprint
input_f = sys.argv[1]
#########################################
# #
# Part 1 #
# #
#########################################
lines = []
with open(input_f) as file:
for line in file:
lines.append(int(line.rstrip()))
curr = 0
tmp = 0
prev = 0
steps=0
while curr <= len(lines)-1:
steps+=1
#print('Start:',lines)
#print('Starting at index',curr,'value',lines[curr])
prev = curr
if curr+lines[curr] > len(lines)-1:
break
#print('Jumps from [',curr,'] =',lines[curr],'to ',end='')
curr = lines[curr]+curr
#print('[',curr,'] =',lines[curr])
#print('Increment',lines[prev],end=' ')
lines[prev] += 1
#print('to',lines[prev])
#print('End:',lines,'curr=',curr)
#input()
print(steps)
#########################################
# #
# Part 2 #
# #
#########################################
lines = []
with open(input_f) as file:
for line in file:
lines.append(int(line.rstrip()))
curr = 0
tmp = 0
prev = 0
steps=0
while curr <= len(lines)-1:
steps+=1
#print('Start:',lines)
#print('Starting at index',curr,'value',lines[curr])
prev = curr
if curr+lines[curr] > len(lines)-1:
break
#print('Jumps from [',curr,'] =',lines[curr],'to ',end='')
curr = lines[curr]+curr
#print('[',curr,'] =',lines[curr])
offset = lines[prev] #abs((lines[prev])-(lines[curr]))
#print('Offset:',offset)
if offset >= 3:
#print('Decrease',lines[prev],end=' ')
lines[prev] -= 1
else:
#print('Increase',lines[prev],end=' ')
lines[prev] += 1
#print('to',lines[prev])
#print('End:',lines,'curr=',curr)
#input()
print(steps)

76
2017/06/6.md Normal file
View File

@ -0,0 +1,76 @@
## \-\-- Day 6: Memory Reallocation \-\--
A debugger program here is having an issue: it is trying to repair a
memory reallocation routine, but it keeps getting stuck in an infinite
loop.
In this area, there are [sixteen memory
banks]{title="There are also five currency banks, two river banks, three airplanes banking, a banked billards shot, and a left bank."};
each memory bank can hold any number of *blocks*. The goal of the
reallocation routine is to balance the blocks between the memory banks.
The reallocation routine operates in cycles. In each cycle, it finds the
memory bank with the most blocks (ties won by the lowest-numbered memory
bank) and redistributes those blocks among the banks. To do this, it
removes all of the blocks from the selected bank, then moves to the next
(by index) memory bank and inserts one of the blocks. It continues doing
this until it runs out of blocks; if it reaches the last memory bank, it
wraps around to the first one.
The debugger would like to know how many redistributions can be done
before a blocks-in-banks configuration is produced that *has been seen
before*.
For example, imagine a scenario with only four memory banks:
- The banks start with `0`, `2`, `7`, and `0` blocks. The third bank
has the most blocks, so it is chosen for redistribution.
- Starting with the next bank (the fourth bank) and then continuing to
the first bank, the second bank, and so on, the `7` blocks are
spread out over the memory banks. The fourth, first, and second
banks get two blocks each, and the third bank gets one back. The
final result looks like this: `2 4 1 2`.
- Next, the second bank is chosen because it contains the most blocks
(four). Because there are four memory banks, each gets one block.
The result is: `3 1 2 3`.
- Now, there is a tie between the first and fourth memory banks, both
of which have three blocks. The first bank wins the tie, and its
three blocks are distributed evenly over the other three banks,
leaving it with none: `0 2 3 4`.
- The fourth bank is chosen, and its four blocks are distributed such
that each of the four banks receives one: `1 3 4 1`.
- The third bank is chosen, and the same thing happens: `2 4 1 2`.
At this point, we\'ve reached a state we\'ve seen before: `2 4 1 2` was
already seen. The infinite loop is detected after the fifth block
redistribution cycle, and so the answer in this example is `5`.
Given the initial block counts in your puzzle input, *how many
redistribution cycles* must be completed before a configuration is
produced that has been seen before?
Your puzzle answer was `14029`.
## \-\-- Part Two \-\-- {#part2}
Out of curiosity, the debugger would also like to know the size of the
loop: starting from a state that has already been seen, how many block
redistribution cycles must be performed before that same state is seen
again?
In the example above, `2 4 1 2` is seen again after four cycles, and so
the answer in that example would be `4`.
*How many cycles* are in the infinite loop that arises from the
configuration in your puzzle input?
Your puzzle answer was `2765`.
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](6/input).

56
2017/06/solution.py Normal file
View File

@ -0,0 +1,56 @@
#!/bin/python3
import sys
from pprint import pprint
input_f = sys.argv[1]
#########################################
# #
# Part 1+2 #
# #
#########################################
line = []
tests = []
with open(input_f) as file:
for line in file:
line = line.rstrip().split()
line = list(map(int, line))
tests = []
steps = 0
tests.append(''.join(map(str,line)))
stop = False
while stop != True: #line not in tests:
steps+=1
idmx,mx = max(enumerate(line),key=lambda x: x[1])
tmp = idmx
#print(line)
#print(tests)
#print('Max [',idmx,'] =',mx)
while True:
#print(line)
#print('Min:',min(line))
#print(line[idmx])
#print('mx:',mx)
idmx = (idmx + 1) % len(line)
line[idmx] += 1
line[tmp] -= 1
#print(mx,min(line))
if mx == 1:
#print('APPENDING')
if ''.join(map(str,line)) in tests:
found_at = tests.index(''.join(map(str,line)))
#print(''.join(map(str,line)),tests)
stop = True
tests.append(''.join(map(str,line)))
break
mx -= 1
#input()
#input()
#print(tests)
#print(line)
print(steps)
print(steps-found_at)

1
2017/06/test2 Normal file
View File

@ -0,0 +1 @@
0 2 7 0

72
2017/07/7.md Normal file
View File

@ -0,0 +1,72 @@
## \-\-- Day 7: Recursive Circus \-\--
Wandering further through the circuits of the computer, you come upon a
tower of programs that have gotten
themselves into a bit of trouble. A recursive algorithm has gotten out
of hand, and now they\'re balanced precariously in a large tower.
One program at the bottom supports the entire tower. It\'s holding a
large disc, and on the disc are balanced several more sub-towers. At the
bottom of these sub-towers, standing on the bottom disc, are other
programs, each holding *their* own disc, and so on. At the very tops of
these sub-sub-sub-\...-towers, many programs stand simply keeping the
disc below them balanced but with no disc of their own.
You offer to help, but first you need to understand the structure of
these towers. You ask each program to yell out their *name*, their
*weight*, and (if they\'re holding a disc) the *names of the programs
immediately above them* balancing on that disc. You write this
information down (your puzzle input). Unfortunately, in their panic,
they don\'t do this in an orderly fashion; by the time you\'re done,
you\'re not sure which program gave which information.
For example, if your list is the following:
pbga (66)
xhth (57)
ebii (61)
havc (66)
ktlj (57)
fwft (72) -> ktlj, cntj, xhth
qoyq (66)
padx (45) -> pbga, havc, qoyq
tknk (41) -> ugml, padx, fwft
jptl (61)
ugml (68) -> gyxo, ebii, jptl
gyxo (61)
cntj (57)
\...then you would be able to recreate the structure of the towers that
looks like this:
gyxo
/
ugml - ebii
/ \
| jptl
|
| pbga
/ /
tknk --- padx - havc
\ \
| qoyq
|
| ktlj
\ /
fwft - cntj
\
xhth
In this example, `tknk` is at the bottom of the tower (the *bottom
program*), and is holding up `ugml`, `padx`, and `fwft`. Those programs
are, in turn, holding up other programs; in this example, none of those
programs are holding up any other programs, and are all the tops of
their own towers. (The actual tower balancing in front of you is much
larger.)
Before you\'re ready to help them, you need to make sure your
information is correct. *What is the name of the bottom program?*
To begin, [get your puzzle input](7/input).
Answer:

24
2017/07/solution.py Normal file
View File

@ -0,0 +1,24 @@
#!/bin/python3
import sys
from pprint import pprint
input_f = sys.argv[1]
#########################################
# #
# Part 1 #
# #
#########################################
with open(input_f) as file:
for line in file:
#########################################
# #
# Part 2 #
# #
#########################################

View File

@ -2,10 +2,7 @@
import sys import sys
from pprint import pprint from pprint import pprint
input_f = "input" #sys.argv[1] input_f = sys.argv[1]
with open(input_f) as file:
for line in file:
######################################### #########################################
@ -14,6 +11,9 @@ with open(input_f) as file:
# # # #
######################################### #########################################
with open(input_f) as file:
for line in file: