This commit is contained in:
Pim Kunis 2023-04-17 20:18:20 +02:00
commit 77064a9563
79 changed files with 10533 additions and 0 deletions

16
2018/1/2/Makefile Normal file
View file

@ -0,0 +1,16 @@
CXX = g++-7
CC = g++-7
CXXFLAGS = -Wall -Wextra
all: main
main.o: main.cpp
$(CXX) $(CXXFLAGS) -c main.cpp
main: main.o
clean:
rm -f *.o *.h.gch *.exe main
run: all
./main

998
2018/1/2/input Normal file
View file

@ -0,0 +1,998 @@
-14
-9
-14
-12
+13
+2
+7
-18
+10
-8
+13
+12
+11
-1
+9
+3
+6
-1
+11
-9
-6
+11
-3
+18
-7
+13
-11
+18
+10
+9
+16
+11
+14
-19
+14
-3
-8
-5
-10
-18
-9
-10
+6
+8
+10
+10
-19
+18
+17
-14
+4
+2
+4
-17
+3
-9
-16
-16
+7
+7
+21
+13
-11
+17
+11
+1
+19
-4
+6
-7
-13
-10
+11
-4
-2
-22
-9
+8
-19
-12
-13
-8
-16
-4
-14
-8
-1
+7
+11
-4
-4
-6
-13
-12
-11
-19
-3
+10
+1
+19
+12
+9
-12
+4
+16
+14
+1
-8
-9
+5
+17
+12
-20
+7
-11
+15
+18
-10
-4
-6
+9
+19
+8
+24
-18
-10
-11
-3
+17
+17
-4
-7
-10
+20
+8
+5
+19
+31
-9
+18
-7
-13
-2
-1
+12
+1
+11
-4
+13
+3
+2
+5
+8
-1
+7
+2
+6
+9
-10
+15
+8
-6
+12
+16
+10
-19
-18
-6
+9
+1
-19
+6
-1
+5
+18
+9
+12
-6
+18
-17
+15
+5
+13
-19
+10
+14
-7
+16
-18
+8
-5
-13
+17
+17
+15
-7
-3
+18
+5
+12
+17
+11
-18
+13
+16
-14
-10
+14
+18
+2
+14
+16
+18
+9
+14
-19
+16
-12
+7
-12
-1
+4
+10
+17
-2
-3
+6
+3
+18
+10
-6
+17
-5
-13
-20
+7
+7
+9
-19
+2
+12
+8
-11
+7
-3
-8
-2
-1
-5
-15
-16
-5
-12
+2
-10
-7
-14
-2
-14
-13
-19
-17
-5
+14
-4
+5
-3
-8
+2
+2
-14
-7
+4
+16
-19
-17
-16
-18
+2
-10
+14
-16
-8
+1
-12
+4
+6
-14
-19
+11
-16
+17
+20
+8
+7
+19
+8
-18
-15
+8
-11
-24
+11
-7
-14
-18
-19
-15
-13
+22
+15
-12
-2
+19
-9
-13
-4
+10
-14
-6
+12
-11
+8
-6
-1
-5
-16
+3
-1
+21
+1
-12
+22
+30
-16
+15
-16
-7
-25
+28
+29
+10
-5
+23
+2
-12
+6
+15
+24
-4
+8
+14
-7
-13
+23
-2
+17
+4
-5
-5
-4
+6
+15
-10
+16
-1
-9
-16
-5
-10
+2
-22
+18
+10
+9
+15
-10
-19
+9
+41
+6
-4
-10
+13
+7
+6
+14
+4
+5
+19
+7
-17
-8
+7
-5
+21
-2
+12
-13
-16
+9
+11
+16
-1
+12
-15
+1
+10
-15
-20
-19
-11
+16
-9
+8
-22
+17
+18
-1
+13
+5
+23
-16
+11
-3
+18
+10
+10
-8
-6
+12
+11
+15
-19
-3
+6
-14
-10
+1
+18
-16
+8
+17
-21
-22
-5
-18
-15
-15
-5
-8
-3
-13
+5
+14
+1
+29
+12
+2
+22
+25
-34
-2
-27
+15
-23
-28
-13
+9
-26
-16
+17
-7
+35
+77
+47
-8
+34
-12
+1
-20
+24
+19
-16
+19
-14
+12
+7
+14
+13
-21
-5
-2
-5
+13
+3
+3
+2
-17
-15
+7
+12
+7
+2
-8
-12
-7
+3
-15
-16
+22
+10
-3
-10
+30
+17
-10
+11
-5
-1
+4
+15
+2
+54
-36
+53
-19
-9
-10
+50
+1
+21
+13
+14
-24
-6
-52
+11
-95
-25
-5
-14
+70
+199
-3
+2
-7
-7
+49
-7
+11
-33
-10
+13
+86
-34
-34
+127
-25
-1700
-76565
-15
+43
-9
-9
+41
+24
+24
-27
+13
-16
-19
-29
-4
-52
-25
-9
-7
+6
-19
+2
+3
+7
+19
-7
-3
+6
-16
-3
-20
+18
+16
+8
+6
-13
+18
+7
+8
-23
-1
-14
-8
-1
-8
-10
-11
-2
-5
-16
+5
+3
-17
-5
-16
-8
+7
-18
-7
-3
+13
+9
+4
+15
+19
+17
-1
-4
+14
+14
+5
-21
+11
-22
+18
+3
-13
-20
-6
-12
+4
-1
+5
+7
-19
+17
-14
+6
+6
+8
+16
+1
+8
+5
+4
+1
+22
-21
-10
-20
+15
+6
+12
+17
+9
+14
+1
-5
+10
-62
-19
-13
-1
-19
-2
-16
+4
+5
-17
-16
-3
-14
-7
+15
+5
-12
-2
+19
-13
+1
-15
-16
+12
-16
-17
+13
+12
-16
+19
+7
+1
-10
+16
-2
-8
-16
+11
-9
-12
+13
-12
+1
-11
-12
-4
+12
-9
-16
-7
+16
+12
+2
-17
-17
+9
-7
-10
-8
+1
-2
+7
+9
+8
+8
-17
-5
-7
-11
-8
-10
-6
+11
-17
-8
-13
+18
-19
+10
-19
-12
-5
-12
-15
+3
-15
+14
+9
+19
-1
-12
-10
+12
-18
-15
+4
-15
+17
-20
+10
+1
+15
+10
+10
-9
+12
-16
+15
+14
+5
-6
+3
+14
-3
+8
+2
-1
+3
-10
-7
+23
-3
-22
+5
+21
+18
-15
-9
+11
+3
+14
+11
+19
-14
-18
+14
-4
+13
+12
+12
+18
+9
-4
-18
+4
+17
-10
+20
-2
+9
-2
+4
-10
+19
-16
+4
-22
-1
+13
+7
+11
+2
+11
-19
+11
+9
+14
-9
+5
+7
+2
+13
+10
+1
+16
-5
-17
-8
+5
+4
+6
+1
+12
+14
-19
+1
+11
-8
-25
-6
-18
+26
+17
+12
-15
+19
+7
-5
+20
-5
+2
+12
-11
-6
-2
+6
-19
-24
-15
+20
+3
+26
+17
+13
-23
+31
+5
+29
-30
+5
+56
-59
-59
-40
-14
+18
-66
-7
-23
-1
-12
-6
-16
+4
+8
+17
+21
-14
-18
-7
-18
-5
+1
+12
+2
+2
+15
+21
-20
-4
-4
-14
-9
-22
+15
-9
+13
-16
+7
-17
-10
-3
-14
+2
-10
-19
-8
-19
+6
-15
-18
+3
-19
+10
-6
+7
+20
-4
-6
-13
-14
-11
+5
+7
-9
+11
-1
+9
+13
-15
-10
-13
-5
-13
-6
+5
+20
-7
-10
+13
-5
+13
-6
+5
-18
-12
-12
-17
+6
-9
-21
+1
+6
-12
+15
-14
+24
+6
+18
-16
+15
-18
-6
+20
+11
+4
-17
+8
-9
+78549

44
2018/1/2/main.cpp Normal file
View file

@ -0,0 +1,44 @@
#include <map>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
map<int, bool> freqs;
ifstream input;
input.open("input");
string line;
int total = 0;
int number;
if (input.is_open()) {
while (true) {
input.clear();
input.seekg(0, ios::beg);
while (getline(input, line)) {
auto found = freqs.find(total);
if (found == freqs.end()) {
// Insert new value
freqs.insert(pair<int,bool>(total, true));
} else {
// Value was found. Exit.
cout << found->first << endl;
input.close();
return 0;
}
number = stoi(line);
total += number;
}
}
} else {
cout << "Could not open file." << endl;
}
return 1;
}

998
2018/1/input Normal file
View file

@ -0,0 +1,998 @@
-14
-9
-14
-12
+13
+2
+7
-18
+10
-8
+13
+12
+11
-1
+9
+3
+6
-1
+11
-9
-6
+11
-3
+18
-7
+13
-11
+18
+10
+9
+16
+11
+14
-19
+14
-3
-8
-5
-10
-18
-9
-10
+6
+8
+10
+10
-19
+18
+17
-14
+4
+2
+4
-17
+3
-9
-16
-16
+7
+7
+21
+13
-11
+17
+11
+1
+19
-4
+6
-7
-13
-10
+11
-4
-2
-22
-9
+8
-19
-12
-13
-8
-16
-4
-14
-8
-1
+7
+11
-4
-4
-6
-13
-12
-11
-19
-3
+10
+1
+19
+12
+9
-12
+4
+16
+14
+1
-8
-9
+5
+17
+12
-20
+7
-11
+15
+18
-10
-4
-6
+9
+19
+8
+24
-18
-10
-11
-3
+17
+17
-4
-7
-10
+20
+8
+5
+19
+31
-9
+18
-7
-13
-2
-1
+12
+1
+11
-4
+13
+3
+2
+5
+8
-1
+7
+2
+6
+9
-10
+15
+8
-6
+12
+16
+10
-19
-18
-6
+9
+1
-19
+6
-1
+5
+18
+9
+12
-6
+18
-17
+15
+5
+13
-19
+10
+14
-7
+16
-18
+8
-5
-13
+17
+17
+15
-7
-3
+18
+5
+12
+17
+11
-18
+13
+16
-14
-10
+14
+18
+2
+14
+16
+18
+9
+14
-19
+16
-12
+7
-12
-1
+4
+10
+17
-2
-3
+6
+3
+18
+10
-6
+17
-5
-13
-20
+7
+7
+9
-19
+2
+12
+8
-11
+7
-3
-8
-2
-1
-5
-15
-16
-5
-12
+2
-10
-7
-14
-2
-14
-13
-19
-17
-5
+14
-4
+5
-3
-8
+2
+2
-14
-7
+4
+16
-19
-17
-16
-18
+2
-10
+14
-16
-8
+1
-12
+4
+6
-14
-19
+11
-16
+17
+20
+8
+7
+19
+8
-18
-15
+8
-11
-24
+11
-7
-14
-18
-19
-15
-13
+22
+15
-12
-2
+19
-9
-13
-4
+10
-14
-6
+12
-11
+8
-6
-1
-5
-16
+3
-1
+21
+1
-12
+22
+30
-16
+15
-16
-7
-25
+28
+29
+10
-5
+23
+2
-12
+6
+15
+24
-4
+8
+14
-7
-13
+23
-2
+17
+4
-5
-5
-4
+6
+15
-10
+16
-1
-9
-16
-5
-10
+2
-22
+18
+10
+9
+15
-10
-19
+9
+41
+6
-4
-10
+13
+7
+6
+14
+4
+5
+19
+7
-17
-8
+7
-5
+21
-2
+12
-13
-16
+9
+11
+16
-1
+12
-15
+1
+10
-15
-20
-19
-11
+16
-9
+8
-22
+17
+18
-1
+13
+5
+23
-16
+11
-3
+18
+10
+10
-8
-6
+12
+11
+15
-19
-3
+6
-14
-10
+1
+18
-16
+8
+17
-21
-22
-5
-18
-15
-15
-5
-8
-3
-13
+5
+14
+1
+29
+12
+2
+22
+25
-34
-2
-27
+15
-23
-28
-13
+9
-26
-16
+17
-7
+35
+77
+47
-8
+34
-12
+1
-20
+24
+19
-16
+19
-14
+12
+7
+14
+13
-21
-5
-2
-5
+13
+3
+3
+2
-17
-15
+7
+12
+7
+2
-8
-12
-7
+3
-15
-16
+22
+10
-3
-10
+30
+17
-10
+11
-5
-1
+4
+15
+2
+54
-36
+53
-19
-9
-10
+50
+1
+21
+13
+14
-24
-6
-52
+11
-95
-25
-5
-14
+70
+199
-3
+2
-7
-7
+49
-7
+11
-33
-10
+13
+86
-34
-34
+127
-25
-1700
-76565
-15
+43
-9
-9
+41
+24
+24
-27
+13
-16
-19
-29
-4
-52
-25
-9
-7
+6
-19
+2
+3
+7
+19
-7
-3
+6
-16
-3
-20
+18
+16
+8
+6
-13
+18
+7
+8
-23
-1
-14
-8
-1
-8
-10
-11
-2
-5
-16
+5
+3
-17
-5
-16
-8
+7
-18
-7
-3
+13
+9
+4
+15
+19
+17
-1
-4
+14
+14
+5
-21
+11
-22
+18
+3
-13
-20
-6
-12
+4
-1
+5
+7
-19
+17
-14
+6
+6
+8
+16
+1
+8
+5
+4
+1
+22
-21
-10
-20
+15
+6
+12
+17
+9
+14
+1
-5
+10
-62
-19
-13
-1
-19
-2
-16
+4
+5
-17
-16
-3
-14
-7
+15
+5
-12
-2
+19
-13
+1
-15
-16
+12
-16
-17
+13
+12
-16
+19
+7
+1
-10
+16
-2
-8
-16
+11
-9
-12
+13
-12
+1
-11
-12
-4
+12
-9
-16
-7
+16
+12
+2
-17
-17
+9
-7
-10
-8
+1
-2
+7
+9
+8
+8
-17
-5
-7
-11
-8
-10
-6
+11
-17
-8
-13
+18
-19
+10
-19
-12
-5
-12
-15
+3
-15
+14
+9
+19
-1
-12
-10
+12
-18
-15
+4
-15
+17
-20
+10
+1
+15
+10
+10
-9
+12
-16
+15
+14
+5
-6
+3
+14
-3
+8
+2
-1
+3
-10
-7
+23
-3
-22
+5
+21
+18
-15
-9
+11
+3
+14
+11
+19
-14
-18
+14
-4
+13
+12
+12
+18
+9
-4
-18
+4
+17
-10
+20
-2
+9
-2
+4
-10
+19
-16
+4
-22
-1
+13
+7
+11
+2
+11
-19
+11
+9
+14
-9
+5
+7
+2
+13
+10
+1
+16
-5
-17
-8
+5
+4
+6
+1
+12
+14
-19
+1
+11
-8
-25
-6
-18
+26
+17
+12
-15
+19
+7
-5
+20
-5
+2
+12
-11
-6
-2
+6
-19
-24
-15
+20
+3
+26
+17
+13
-23
+31
+5
+29
-30
+5
+56
-59
-59
-40
-14
+18
-66
-7
-23
-1
-12
-6
-16
+4
+8
+17
+21
-14
-18
-7
-18
-5
+1
+12
+2
+2
+15
+21
-20
-4
-4
-14
-9
-22
+15
-9
+13
-16
+7
-17
-10
-3
-14
+2
-10
-19
-8
-19
+6
-15
-18
+3
-19
+10
-6
+7
+20
-4
-6
-13
-14
-11
+5
+7
-9
+11
-1
+9
+13
-15
-10
-13
-5
-13
-6
+5
+20
-7
-10
+13
-5
+13
-6
+5
-18
-12
-12
-17
+6
-9
-21
+1
+6
-12
+15
-14
+24
+6
+18
-16
+15
-18
-6
+20
+11
+4
-17
+8
-9
+78549

36
2018/1/main.c Normal file
View file

@ -0,0 +1,36 @@
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
FILE *stream;
char *line = NULL;
size_t len = 0;
int nread;
if (argc != 2) {
fprintf(stderr, "Usage: %s <file>\n", argv[0]);
exit(EXIT_FAILURE);
}
stream = fopen(argv[1], "r");
if (stream == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
int number;
int total = 0;
while ((nread = getline(&line, &len, stream)) != -1) {
number = atoi(line);
total += number;
}
printf("%d\n", total);
free(line);
fclose(stream);
exit(EXIT_SUCCESS);
}

16
2018/2/2/Makefile Normal file
View file

@ -0,0 +1,16 @@
CXX = g++-7
CC = g++-7
CXXFLAGS = -Wall -Wextra
all: main
main.o: main.cpp
$(CXX) $(CXXFLAGS) -c main.cpp
main: main.o
clean:
rm -f *.o *.h.gch *.exe main
run: all
./main

37
2018/2/2/main.cpp Normal file
View file

@ -0,0 +1,37 @@
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
using namespace std;
int main () {
ifstream input;
input.open("../input");
string line;
vector<string> strings = {};
while (getline(input, line)) {
strings.push_back(line);
}
// Compare every string with ones that come after it.
for (vector<string>::const_iterator it = strings.begin(); it != strings.end(); ++it) {
for (vector<string>::const_iterator it2 = ++it; it2 != strings.end(); ++it2) {
int differences = 0;
string::const_iterator str_it = it->begin();
for (string::const_iterator str_it2 = it2->begin(); str_it2 != it2->end(); ++str_it2) {
if (*str_it != *str_it2) {
++differences;
}
++str_it;
}
//cout << differences << endl;
if (differences == 1) {
cout << "Found a difference of 1 in strings: " << *it << " and " << *it2 << endl;
}
}
}
}

16
2018/2/Makefile Normal file
View file

@ -0,0 +1,16 @@
CXX = g++-7
CC = g++-7
CXXFLAGS = -Wall -Wextra
all: main
main.o: main.cpp
$(CXX) $(CXXFLAGS) -c main.cpp
main: main.o
clean:
rm -f *.o *.h.gch *.exe main
run: all
./main

250
2018/2/input Normal file
View file

@ -0,0 +1,250 @@
bazvmqthjtrnlosiecxyghkwud
pazvmqbijirzlosiecxyghkwud
pazvtqbmjtrnlosiecxyghkwzd
pazvmqbfjtrjlosnlcxyghkwud
pazvkqbfjtrtlosiecjyghkwud
paztmqbfjtrnbosiecxyglkwud
pazvmqbfjtunlosievxmghkwud
pazvmqbfjtmngosiecyyghkwud
jazvmqbfjtrnlosiecxygikpud
pazvqqbfctrnlosimcxyghkwud
pazvmqbfjtrnwogiecxyihkwud
pazvmqbfjtrqlojiecxeghkwud
payvmqbfjtrzlosiecxyghkwuk
pkzvmqnfjtrnlosieciyghkwud
pazvmqqfjtrnldsiecxyghkwui
pazvmqbfttrqlosiecxywhkwud
gazvmybfjthnlosiecxyghkwud
pazvmqbfjtrnlasiecxygptwud
pktvmqbfjtrnwosiecxyghkwud
pazvmqwfjtrnlosiecxgghkkud
pazvmzkbjtrnlosiecxyghkwud
pazvmqbfjtrnloslecxyghuwui
pezvmqbfjtrnlesieyxyghkwud
cazvmqbfjrrnlosiecxyghkmud
pazvmqrfjjrnlosiecxyghkwnd
pazvmqbgjtrnlosiecxyphtwud
pazvmqbvmtrnlosiecxyghkpud
pazdmqbfjtrnlosiecxyuhkpud
pazvmqbflnrnloshecxyghkwud
pazvvqbfjprilosiecxyghkwud
pazvwqbfjtrllosiecxyghknud
pazvmqbfjtrnloniecxdghkaud
pazvmqbfjtrnlvsuecxynhkwud
ptzvmqwfjtrnlosieccyghkwud
pkzvmqbjjtrnlosiecryghkwud
pazvmqqfjtrexosiecxyghkwud
pazgmqbfjtrneoyiecxyghkwud
paznmqbfjtrnlosiecxydhkwzd
pazvmqbfjtrnaosiwcxsghkwud
pazomqbfjxrnlosiewxyghkwud
pazsmqbfjprnlosiecxrghkwud
pazvmqbfqtrnoosiecxygmkwud
aazvmqbfjtrnlosiacxyghjwud
pazviqbfjtrnlobiecxygrkwud
qazwmqbfjhrnlosiecxyghkwud
pazvmqbfftrnlosiqcxygfkwud
patvmqbfjtonlosircxyghkwud
pazvmqbfjtrnlomaecxyghkpud
paztmqbfjtrulossecxyghkwud
pazvmqbijtrnlobiecxyghkwkd
pazvsqbfjtrnlospecxyghkqud
pbzmmqbfjtrnlosiecxyghkwhd
pezvkqbfjtenlosiecxyghkwud
razvmqbfjkrnlosiecxeghkwud
pazcmqbfjtrnloriecxyghkgud
pazvmqbfftfnlosiecvyghkwud
pazvmqpujtrnlosiepxyghkwud
patvgqbfjtrnloslecxyghkwud
pazvmqbfltrnlosibcxyghswud
pazvmebfjtrnlosaecxyehkwud
pazdmqbejtrnlosiecxyghrwud
pazvmcbfntrplosiecxyghkwud
pszvmqbfjtrnlosivcfyghkwud
puzvmqbfjtrnloeiecxyxhkwud
pazvmqbfjtrivooiecxyghkwud
pazvyqbfjtrngosiwcxyghkwud
pauvmqbfjtrnlosimexyghkwud
pazvmqbfjtrnwoshecxeghkwud
dazvmqbfjtrnloshecxygxkwud
pazvmqbfjtrtdosiecxyghvwud
pazxmqbfjtrnlosieceyghjwud
pazvmqbfjtrnlosihexjghkwud
pazvmqbfjsrnlosiecxughiwud
phzvcqbfjtrqlosiecxyghkwud
pazvmibfjtrnlosjecxxghkwud
pazvmqbfjtrbeosiecxlghkwud
pazvmqyfjttolosiecxyghkwud
fawvmqbfjtrnlosiecxyghkwhd
pazvmqbfjprnxosiecxyghkbud
macvmqbfjtrnlosiesxyghkwud
pazsmqbfjtrflouiecxyghkwud
pacvmqbfjtrnltsiecxyghcwud
pazvmqbfjtymlosiecxygykwud
pazvmqbfjtrclosiecxygukwmd
pazvmqbfjtrnlobiecxphhkwud
mazvmqbhitrnlosiecxyghkwud
pazvmqdtjtrnlrsiecxyghkwud
pazvmqbfjgrnllsieczyghkwud
pazvmqbfjtrilosiecxxgikwud
pazvmqbjjtrnlosreceyghkwud
paxvmmbfjtrilosiecxyghkwud
pazqmwbfjtrnlowiecxyghkwud
pazvmqbfjfrnqosiecxyghkwui
pazvmqbfjtrrgosiecxyghswud
pazvmqnfjtrnlosiecsyghkwmd
paiemqbmjtrnlosiecxyghkwud
pazvmqbfdtqnlosiecxyjhkwud
pazvmxbfjthndosiecxyghkwud
pqzvmqbfjtrnlosiecxbghkzud
pagrmqbfjtrnlosiecxygskwud
pazamqtfjtrnsosiecxyghkwud
pazvmqbfjtrnldshecxyzhkwud
pazvmnbfjtrllosieclyghkwud
snzvmqbfjnrnlosiecxyghkwud
pazvsqbfjdrnlosiecxyghswud
pazvmqnfjfrnlosiecsyghkwud
pazvmqbfjtrnlosiecxjghowum
pazvmqbfjtjnlosieczygfkwud
pazvmqbsjtrnloziecxyghkeud
pazvxqbgjtrnlooiecxyghkwud
pazvmqbfjtrnlooiecxmyhkwud
pazvmqbyftrnlosgecxyghkwud
pazvmqbfjtrnlosiwcxyqhksud
pazvmqkyjtrnlokiecxyghkwud
pazfmqbfjtrnlosijcxyohkwud
pazvmqbfjtrnlociecxygikcud
fazvmqbfjtrnlosiecxyjhkuud
pazvmqbojtknlohiecxyghkwud
pazvmqbfjtgnlosbecxyghkwux
pazvmqbfjtrnlocieckoghkwud
pazvdqbfjtrlltsiecxyghkwud
pazvmqbfjtsnlfsiecxyglkwud
przvpqbfjtrnyosiecxyghkwud
pazvmbrfjtrnlosiecxmghkwud
dazvmqbfttrnlostecxyghkwud
pazvmqbfttdnlosiecxygwkwud
pazvmqbvitrnlosieexyghkwud
pazvmqbfjhrnlosjecxyvhkwud
pazvmqbfstrnlosiecxyggkwpd
bazvmqbfjtrnlmsiecxyohkwud
patmmqbfjtrnlosizcxyghkwud
pazvmqbfwtrglosieqxyghkwud
pazvmqbfjtrnlosiecxdhhkwmd
pazvmqbfjdrnlosnexxyghkwud
oazrrqbfjtrnlosiecxyghkwud
pazvmqbfjcrnlosiecxygakwjd
pazvmqbfjtrnlosifcxfghkwyd
pazvmnbfjtrnlosiecxyahzwud
pazvmqbfgtrnlojiecxyghkgud
pazvmqbfjtrnlaliecxyghkwuy
pazvmqbfjtrnlfsiecrtghkwud
pazvmqbkjtrnloswecxdghkwud
pazvtqbfjtdnlosiecxyghkwuu
pozvmqbfrtrnlosiesxyghkwud
payvmqbfjornlossecxyghkwud
pazvuqbfjtrnlosiscxyghkpud
pgzcmqbfjtrnlotiecxyghkwud
pazvvqbfjtrnlobieyxyghkwud
pazycqbfjtrnlosiecxyzhkwud
pizvdqbfjtrnlosiecxbghkwud
pazvmqbfjtrnloqiecxmgtkwud
gazvmqbfjtrnlusiecxpghkwud
pazvmqdfjtralosiecxyghkwmd
pazvmqbfjtmnlosiecxywhawud
pazvlqbfjtrnlosqecxyghqwud
pazvmqbfjtrnlhsneixyghkwud
kazvmqbfjtrqlosimcxyghkwud
pazvmwbfjtrclosiecxyghkuud
pazvmqjfjtrnlosieckyghpwud
pezvmqbgjtrnloseecxyghkwud
pazvqqbfjtfnlosvecxyghkwud
oazvmqbfjtunlosiecxyghkwad
pazvmqbfjtrncoswecxyghfwud
pazvyqbfjtrnlosqecxygtkwud
pazvmqbfjtrvlzsiecxygwkwud
pazvmqbfjjrnlosiekxylhkwud
madvmqbfjtrnlosircxyghkwud
pazvmybfjtrnlisiecxyghkwbd
pazvmqbjjixnlosiecxyghkwud
pazvmqefjtrnloqiecxyghhwud
pazveqbfjtrnlosiecgygzkwud
pazvmqbfjtrxlosiecxmgwkwud
uazvmqufjtrnlosiecxyghkwuo
pasymqbfjtrnlosiecxyghowud
pazvmqbfjtlnlpsiecxyghswud
pnzvmqbfjprnloszecxyghkwud
pafjmqcfjtrnlosiecxyghkwud
pazvmqxfbtrnloqiecxyghkwud
pazvmzbfjtrnposiccxyghkwud
pazvmqbfjotulosiecxyghkwud
pazvmqbfotrnlosgecxykhkwud
przvmqbfjtrnlosiecxyqhkwcd
pazvmqbfjtsnlogiecxyyhkwud
pazvmqbfrtrnlzsiecxyghkwug
pazvmqbfjtrnlosiecxzgukwuo
pqzvmqbqjtrnlosdecxyghkwud
pazvmqbfjtqqlosiecxughkwud
pazvmqbfjtrnlosiedhyphkwud
pazsmqbcutrnlosiecxyghkwud
pazvmqbgrtrnlosiecxyghpwud
pazemqbfjtznlosiecxyghkvud
pazvkqbfjtrilosiecxyghkwod
pfzvmqbfjtrnlopiecxygjkwud
pazvmqvfjtreloniecxyghkwud
pazvmqbfjernljsiecxgghkwud
pazvmqikjtrnlosiecxyghqwud
pazvmqbfjtrnpesoecxyghkwud
fazvmqbfjtrnlosihchyghkwud
pazvmqbfjtgnloanecxyghkwud
pazvmqsfjqrnlosiecxychkwud
parvmqbfjtrnlosiecxygfuwud
przvmqbfjtrhlosihcxyghkwud
pazvmqbcjtrnlosimcxgghkwud
pazvmqbfjtrnlosceciyjhkwud
pazvkqbfjtrylosivcxyghkwud
pazvmqbfjtrnlgsieoxyghdwud
pazvmqnfstrnlowiecxyghkwud
pazvmqbfdtrnlosieumyghkwud
pazvmqbfjtrnlosyecxfghkwul
pazvmqbfjtrclosivcxyghkcud
pazjmqbfjtrnlosiecxygokwkd
hazvmqbfjtrflosiecxzghkwud
wazvmqbfjtrnlomiecxyphkwud
yazvmqbfjirnkosiecxyghkwud
pczvmqbfjtrnlohiecxyghkwpd
pazvmqbfotrbeosiecxlghkwud
pazvmqbfjtrplosiecxynhzwud
paxvbqbwjtrnlosiecxyghkwud
pazvmqvfjtrnlosiecbyghqwud
pazjmqbfjtrnlosiecxoghkwed
pazvmqbfjtreljsitcxyghkwud
mazamqbfjtrnlosiecxoghkwud
pazvmqbfjjrnposiscxyghkwud
pbrvmqbfjtrnloliecxyghkwud
pazvmqbfjtrnlosiecxgghkyyd
pmzvmqbfntrnlosiecxyghkwuw
pazvzqbfjtrnlosienxyghzwud
pazvmqifjtvnlosrecxyghkwud
tazvmqbhjtjnlosiecxyghkwud
pazvmqbfjtlnxosiecxyghkwuo
pazvmqbfjennlosiecxyghkwxd
pahvmqbfjhrnlosiecxythkwud
pazvmlkfjtrnlxsiecxyghkwud
pfzvmqbojtrnlosieciyghkwud
pazvbqbfjtrollsiecxyghkwud
eazvmqbfjtrnlosiecayghkoud
pazvmqbfjtjnlvsiecxyghkwsd
pazvoqbojtrnlosiecfyghkwud
pazvmqbfjtuslosiecxyghksud
pazvmqbfjnrnlosiedxyghkwup
pazvmqbjjtrnlosieaxyghdwud
pazccqbfjtrhlosiecxyghkwud
pbzvmqkfjtrnlosievxyghkwud
pazvmqrljtrnlosiscxyghkwud
pazvmqbfjfoqlosiecxyghkwud
pazcmqbfjtrnlosiecxyihkwuf
pszvmqbfjtrnnosiacxyghkwud
aazvmqbfjtrnlosieyxyghkwld
pazvrqbfntrnlosiycxyghkwud
pkzvoqbfjtrnlosiecxyghxwud

48
2018/2/main.cpp Normal file
View file

@ -0,0 +1,48 @@
#include <iostream>
#include <map>
#include <fstream>
using namespace std;
int main () {
int twice = 0;
int thrice = 0;
ifstream input;
input.open("input");
string line;
while (getline(input, line)) {
map<char, int> freqs;
for (string::const_iterator it = line.begin(); it != line.end(); ++it) {
auto found = freqs.find(*it);
if (found == freqs.end()) {
freqs.insert(pair<char,int>(*it, 1));
} else {
found->second++;
}
}
int twice_found = false;
int thrice_found = false;
for (map<char, int>::const_iterator it = freqs.begin(); it != freqs.end(); ++it) {
if (it->second == 2) {
twice_found = true;
} else if (it->second == 3) {
thrice_found = true;
}
}
if (twice_found) {
++twice;
}
if (thrice_found) {
++thrice;
}
}
cout << (twice * thrice) << endl;
}

1347
2018/3/input Normal file

File diff suppressed because it is too large Load diff

31
2018/3/main.rb Normal file
View file

@ -0,0 +1,31 @@
require 'pry'
arr = Array.new(1000){Array.new(1000){{count: 0, id: nil}}}
ids = Array.new
dups = Array.new
File.open("input", "r") do |f|
f.each_line do |line|
id = line[/\d+/].to_i
offset_left, offset_top = line[/\d+,\d+/].split(",").map(&:to_i)
width, height = line[/\d+x\d+/].split("x").map(&:to_i)
ids.push id
height.times do |y|
width.times do |x|
arr[offset_top + y][offset_left + x][:count] += 1
if arr[offset_top + y][offset_left + x][:id] != nil
dups.push arr[offset_top + y][offset_left + x][:id]
dups.push id
end
arr[offset_top + y][offset_left + x][:id] = id
end
end
end
end
puts arr.flatten.select{|a| a[:count] > 1}.count
puts (ids - dups.uniq)

1110
2018/4/input Normal file

File diff suppressed because it is too large Load diff

88
2018/4/main.rb Normal file
View file

@ -0,0 +1,88 @@
require 'pry'
events = []
guards = {}
File.open("input", "r") do |f|
f.each_line do |line|
events.push ({
date: line[/\d{4}-\d{2}-\d{2} \d{2}:\d{2}/],
type: (line.end_with?("shift\n") ? :begins_shift : (line.end_with?("asleep\n") ? :falls_asleep : :wakes_up)),
id: line[/#\d+/].to_s[1..-1].to_i
})
end
end
events.sort_by! do |event|
event[:date]
end
current_guard = 0
begin_minute = 0
events.each do |event|
if event[:type] == :begins_shift
if guards[event[:id]].nil?
guards[event[:id]] = Array.new(60){0}
end
current_guard = event[:id]
elsif event[:type] == :falls_asleep
begin_minute = event[:date][-2..-1].to_i
else
(event[:date][-2..-1].to_i - begin_minute).times do |minute|
guards[current_guard][begin_minute + minute] += 1
end
end
end
# Strategy 1
sleepiest_guard = 0
longest_time = 0
guards.each do |id, counts|
time = counts.inject(:+)
if time > longest_time
longest_time = time
sleepiest_guard = id
end
end
sleepiest_minute = 0
max_count = 0
guards[sleepiest_guard].each_with_index do |count, index|
if count > max_count
max_count = count
sleepiest_minute = index
end
end
puts sleepiest_minute * sleepiest_guard
# Strategy 2
guard = 0
minute = 0
count = 0
guards.each do |id, counts|
max_count = 0
max_index = 0
counts.each_with_index do |count_, index|
if count_ > max_count
max_count = count_
max_index = index
end
end
if max_count > count
guard = id
minute = max_index
count = max_count
end
end
puts guard * minute

1
2018/5/input Normal file

File diff suppressed because one or more lines are too long

49
2018/5/main.rb Normal file
View file

@ -0,0 +1,49 @@
require 'pry'
input = File.open('input') {|file| file.readline}
('a'..'z').each do |letter|
output = input
temp = ""
i = 0
while i != output.length
if output[i].downcase != letter
temp += output[i]
end
i += 1
end
output = temp
temp = ""
removed = true
while removed
removed = false
i = 1
while i < output.length
if output[i - 1] != output[i] && output[i - 1].downcase == output[i].downcase
removed = true
i += 2
if i == output.length
temp += output[-1]
end
else
temp += output[i - 1]
i += 1
if i == output.length
temp += output[-1]
end
end
end
output = temp
temp = ""
end
puts "#{letter}: #{output.length}"
end

50
2018/6/input Normal file
View file

@ -0,0 +1,50 @@
135, 127
251, 77
136, 244
123, 169
253, 257
359, 309
100, 247
191, 323
129, 323
76, 284
69, 56
229, 266
74, 216
236, 130
152, 126
174, 319
315, 105
329, 146
288, 51
184, 344
173, 69
293, 80
230, 270
279, 84
107, 163
130, 176
347, 114
133, 331
237, 300
291, 283
246, 297
60, 359
312, 278
242, 76
81, 356
204, 291
187, 335
176, 98
103, 274
357, 144
314, 118
67, 196
156, 265
254, 357
218, 271
118, 94
300, 189
290, 356
354, 91
209, 334

75
2018/6/main.rb Normal file
View file

@ -0,0 +1,75 @@
require 'pry'
coords = []
# Parse input file.
File.open("input", "r") do |f|
f.each_line do |line|
x, y = line.split(", ").map(&:chomp).map(&:to_i)
coords.push({
x: x,
y: y,
})
end
end
# Create matrix with correct size
left_bound = right_bound = coords.first[:x]
top_bound = bottom_bound = coords.first[:y]
coords.each do |coord|
if coord[:x] < left_bound
left_bound = coord[:x]
end
if coord[:x] > right_bound
right_bound = coord[:x]
end
if coord[:y] < top_bound
top_bound = coord[:y]
end
if coord[:y] > bottom_bound
bottom_bound = coord[:y]
end
end
height = bottom_bound - top_bound + 1
width = right_bound - left_bound + 1
coords.map!{|coord| {x: coord[:x] - left_bound, y: coord[:y] - top_bound}}
matrix = Array.new(height){Array.new(width){0}}
# Fill the matrix with lowest distance to coordinates
(0...height).each do |y|
(0...width).each do |x|
coords.each_with_index do |coord, i|
distance = (x - coord[:x]).abs + (y - coord[:y]).abs
matrix[y][x] += distance
end
end
end
=begin
# Count the area for each coordinate.
(0...height).each do |y|
(0...width).each do |x|
if (y == 0 || x == 0 || y == height - 1 || x == width - 1) && matrix[y][x][:coords].length == 1
coords[matrix[y][x][:coords].first][:infinite] = true
else
if matrix[y][x][:coords].length == 1
coords[matrix[y][x][:coords].first][:area] += 1
end
end
end
end
=end
puts matrix.flatten.select{|point| point < 10000}.length

5
2018/6/sample Normal file
View file

@ -0,0 +1,5 @@
0, 0
0, 10
10, 0
10, 10
3, 4

101
2018/7/input Normal file
View file

@ -0,0 +1,101 @@
Step Z must be finished before step B can begin.
Step X must be finished before step D can begin.
Step D must be finished before step P can begin.
Step O must be finished before step C can begin.
Step C must be finished before step Y can begin.
Step K must be finished before step J can begin.
Step H must be finished before step T can begin.
Step B must be finished before step Q can begin.
Step V must be finished before step M can begin.
Step E must be finished before step W can begin.
Step S must be finished before step J can begin.
Step I must be finished before step N can begin.
Step T must be finished before step L can begin.
Step N must be finished before step M can begin.
Step P must be finished before step G can begin.
Step F must be finished before step Q can begin.
Step J must be finished before step G can begin.
Step L must be finished before step G can begin.
Step Y must be finished before step R can begin.
Step U must be finished before step A can begin.
Step W must be finished before step G can begin.
Step R must be finished before step G can begin.
Step G must be finished before step M can begin.
Step A must be finished before step Q can begin.
Step M must be finished before step Q can begin.
Step N must be finished before step F can begin.
Step Y must be finished before step W can begin.
Step J must be finished before step W can begin.
Step U must be finished before step G can begin.
Step X must be finished before step L can begin.
Step P must be finished before step J can begin.
Step L must be finished before step Y can begin.
Step G must be finished before step Q can begin.
Step K must be finished before step G can begin.
Step V must be finished before step J can begin.
Step F must be finished before step U can begin.
Step V must be finished before step N can begin.
Step I must be finished before step T can begin.
Step U must be finished before step W can begin.
Step S must be finished before step A can begin.
Step C must be finished before step G can begin.
Step L must be finished before step A can begin.
Step E must be finished before step L can begin.
Step D must be finished before step H can begin.
Step Z must be finished before step E can begin.
Step J must be finished before step U can begin.
Step R must be finished before step A can begin.
Step C must be finished before step J can begin.
Step T must be finished before step R can begin.
Step Z must be finished before step D can begin.
Step Y must be finished before step G can begin.
Step Y must be finished before step M can begin.
Step X must be finished before step H can begin.
Step S must be finished before step Q can begin.
Step R must be finished before step Q can begin.
Step D must be finished before step Q can begin.
Step G must be finished before step A can begin.
Step N must be finished before step A can begin.
Step F must be finished before step L can begin.
Step O must be finished before step N can begin.
Step T must be finished before step J can begin.
Step S must be finished before step T can begin.
Step O must be finished before step M can begin.
Step P must be finished before step Y can begin.
Step I must be finished before step U can begin.
Step V must be finished before step S can begin.
Step F must be finished before step G can begin.
Step P must be finished before step M can begin.
Step C must be finished before step S can begin.
Step A must be finished before step M can begin.
Step C must be finished before step Q can begin.
Step Y must be finished before step Q can begin.
Step O must be finished before step P can begin.
Step S must be finished before step R can begin.
Step S must be finished before step Y can begin.
Step I must be finished before step Q can begin.
Step O must be finished before step T can begin.
Step F must be finished before step W can begin.
Step U must be finished before step R can begin.
Step O must be finished before step U can begin.
Step D must be finished before step L can begin.
Step H must be finished before step I can begin.
Step P must be finished before step R can begin.
Step J must be finished before step L can begin.
Step P must be finished before step W can begin.
Step W must be finished before step Q can begin.
Step X must be finished before step Q can begin.
Step Z must be finished before step U can begin.
Step T must be finished before step U can begin.
Step D must be finished before step S can begin.
Step U must be finished before step Q can begin.
Step N must be finished before step G can begin.
Step E must be finished before step Q can begin.
Step X must be finished before step K can begin.
Step J must be finished before step R can begin.
Step X must be finished before step R can begin.
Step T must be finished before step W can begin.
Step K must be finished before step S can begin.
Step S must be finished before step G can begin.
Step P must be finished before step F can begin.
Step X must be finished before step C can begin.

101
2018/7/main.rb Normal file
View file

@ -0,0 +1,101 @@
require 'pry'
orders = []
instructions = []
# Parse input file.
File.open("input", "r") do |f|
f.each_line do |line|
first, second = line.scan(/\s[A-Z]{1}\s/).map(&:strip)
orders.push({
first: first,
then: second
})
instructions.push(first)
instructions.push(second)
end
end
instructions.uniq!
result = ""
workers = 5.times.map do
{
current_instruction: nil,
time_left: 0
}
end
time = 0
while !instructions.empty?
# Get a list of the next instructions available.
next_instructions = instructions.select do |instruction|
orders.none? do |order|
order[:then] == instruction && order[:first] != nil
end and workers.none? do |worker|
worker[:current_instruction] == instruction
end
end.sort
# Give free workers instructions.
workers.each_with_index do |worker, i|
if worker[:current_instruction].nil? and !next_instructions.empty?
workers[i][:current_instruction] = next_instructions[0]
workers[i][:time_left] = next_instructions[0].ord - "A".ord + 1 + 60
next_instructions.delete(next_instructions[0])
end
end
elapsed_time = workers.select do |worker|
!worker[:current_instruction].nil?
end.map do |worker|
worker[:time_left]
end.min
time += elapsed_time
workers.each_with_index do |worker, i|
if !workers[i][:current_instruction].nil?
workers[i][:time_left] -= elapsed_time
if workers[i][:time_left] == 0
instructions.delete(workers[i][:current_instruction])
orders.each do |order|
if order[:first] == workers[i][:current_instruction]
order[:first] = nil
end
end
workers[i][:current_instruction] = nil
end
end
end
#binding.pry
end
=begin
while !instructions.empty?
next_instruction = instructions.select do |instruction|
orders.none? do |order|
order[:then] == instruction && order[:first] != nil
end
end.sort.first
result += next_instruction
instructions.delete next_instruction
orders.each do |order|
if order[:first] == next_instruction
order[:first] = nil
end
end
end
=end
puts time

7
2018/7/sample Normal file
View file

@ -0,0 +1,7 @@
Step C must be finished before step A can begin.
Step C must be finished before step F can begin.
Step A must be finished before step B can begin.
Step A must be finished before step D can begin.
Step B must be finished before step E can begin.
Step D must be finished before step E can begin.
Step F must be finished before step E can begin.

4
2020/.formatter.exs Normal file
View file

@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

19
2020/lib/days/day1.ex Normal file
View file

@ -0,0 +1,19 @@
defmodule AOC.Day1 do
def part1 do
l = AOC.Util.input_integers(1, 1)
[x, y] = Enum.filter(l, &((2020 - &1) in l))
x * y
end
def find_three([h | tl]) do
case Enum.filter(tl, &((2020 - h - &1) in tl)) do
[x, y] -> h * x * y
_ -> find_three(tl)
end
end
def part2 do
AOC.Util.input_integers(1, 1)
|> find_three()
end
end

48
2020/lib/days/day10.ex Normal file
View file

@ -0,0 +1,48 @@
defmodule AOC.Day10 do
def find_diffs(xs), do: find_diffs(xs, %{})
def find_diffs([_], acc), do: acc
def find_diffs([x1, x2 | xs], acc) do
acc = Map.update(acc, x2 - x1, 1, &(&1 + 1))
find_diffs([x2 | xs], acc)
end
def count_walks([x | _] = xs) do
memo =
Enum.into(xs, %{}, &{&1, 0})
|> Map.put(x, 1)
count_walks(xs, memo)
end
def count_walks([x], memo), do: memo[x]
def count_walks([x | xs], memo) do
memo =
Enum.take(xs, 3)
|> Enum.reduce(memo, fn
next, memo when next - x <= 3 ->
Map.update!(memo, next, &(&1 + memo[x]))
_, memo ->
memo
end)
count_walks(xs, memo)
end
def parts do
input =
AOC.Util.input_integers(10, 1)
|> Enum.sort()
input = [0 | input] ++ [Enum.max(input) + 3]
%{1 => ones, 3 => threes} = find_diffs(input)
part1 = ones * threes
part2 = count_walks(input)
{part1, part2}
end
end

91
2020/lib/days/day11.ex Normal file
View file

@ -0,0 +1,91 @@
defmodule AOC.Day11 do
@x_size 95
@y_size 93
def parse_input do
AOC.Util.input_lines(11, 1)
|> Enum.with_index()
|> Enum.reduce(%{}, fn {line, y}, acc ->
line
|> String.split("", trim: true)
|> Enum.with_index()
|> Enum.reject(&(elem(&1, 0) == "."))
|> Enum.map(fn {_, i} -> {false, i} end)
|> Enum.into(acc, fn {c, x} -> {{x, y}, c} end)
end)
end
def count_direct_adj(seats, {x, y}) do
[
{x - 1, y - 1},
{x - 1, y},
{x - 1, y + 1},
{x, y - 1},
{x, y + 1},
{x + 1, y - 1},
{x + 1, y},
{x + 1, y + 1}
]
|> Enum.count(fn coords -> Map.get(seats, coords) end)
end
def look_direction(seats, coords, next_fun) do
{x, y} = coords = next_fun.(coords)
if x not in 0..@x_size or y not in 0..@y_size do
false
else
case Map.get(seats, coords) do
nil -> look_direction(seats, coords, next_fun)
x -> x
end
end
end
def count_sight_adj(seats, {x, y}) do
[
fn {x, y} -> {x + 1, y + 1} end,
fn {x, y} -> {x + 1, y - 1} end,
fn {x, y} -> {x - 1, y + 1} end,
fn {x, y} -> {x - 1, y - 1} end,
fn {x, y} -> {x + 1, y} end,
fn {x, y} -> {x - 1, y} end,
fn {x, y} -> {x, y + 1} end,
fn {x, y} -> {x, y - 1} end
]
|> Enum.count(&look_direction(seats, {x, y}, &1))
end
def simulate_round(seats, count_adj, min) do
Enum.reduce(seats, {%{}, false}, fn {coords, x}, {acc, changed} ->
new =
case {x, count_adj.(seats, coords)} do
{false, 0} -> true
{true, count} when count >= min -> false
_ -> x
end
{Map.put(acc, coords, new), changed or new != x}
end)
end
def find_stable(seats, count_adj, min) do
{seats, changed} = simulate_round(seats, count_adj, min)
if changed do
find_stable(seats, count_adj, min)
else
seats
end
end
def parts do
input = parse_input()
stable = find_stable(input, &count_direct_adj/2, 4)
part1 = Enum.count(stable, &elem(&1, 1))
stable = find_stable(input, &count_sight_adj/2, 5)
part2 = Enum.count(stable, &elem(&1, 1))
{part1, part2}
end
end

93
2020/lib/days/day12.ex Normal file
View file

@ -0,0 +1,93 @@
defmodule AOC.Day12 do
@turn_right %{
N: :E,
E: :S,
S: :W,
W: :N
}
def parse_input do
AOC.Util.input_lines(12, 1)
|> Enum.map(fn line ->
{action, value} = String.split_at(line, 1)
action = String.to_atom(action)
value = String.to_integer(value)
{action, value}
end)
end
def handle_instruction1({:N, value}, acc), do: Map.update!(acc, :y, &(&1 - value))
def handle_instruction1({:E, value}, acc), do: Map.update!(acc, :x, &(&1 + value))
def handle_instruction1({:S, value}, acc), do: Map.update!(acc, :y, &(&1 + value))
def handle_instruction1({:W, value}, acc), do: Map.update!(acc, :x, &(&1 - value))
def handle_instruction1({:F, value}, %{dir: dir} = acc),
do: handle_instruction1({dir, value}, acc)
def handle_instruction1({:L, value}, acc), do: handle_instruction1({:R, -value}, acc)
def handle_instruction1({:R, value}, %{dir: dir} = acc) do
value = rem(div(value, 90), 4)
value =
if value < 0 do
value + 4
else
value
end
dir =
List.duplicate(nil, value)
|> Enum.reduce(dir, fn _, d -> Map.get(@turn_right, d) end)
Map.put(acc, :dir, dir)
end
def handle_instruction2({:N, value}, acc), do: Map.update!(acc, :wpy, &(&1 - value))
def handle_instruction2({:E, value}, acc), do: Map.update!(acc, :wpx, &(&1 + value))
def handle_instruction2({:S, value}, acc), do: Map.update!(acc, :wpy, &(&1 + value))
def handle_instruction2({:W, value}, acc), do: Map.update!(acc, :wpx, &(&1 - value))
def handle_instruction2({:F, value}, %{x: x, y: y, wpx: wpx, wpy: wpy} = acc),
do: %{acc | x: x + value * wpx, y: y + value * wpy}
def handle_instruction2({:L, value}, acc), do: handle_instruction2({:R, -value}, acc)
def handle_instruction2({:R, value}, %{wpx: wpx, wpy: wpy} = acc) do
value = rem(div(value, 90), 4)
value =
if value < 0 do
value + 4
else
value
end
{wpx, wpy} =
case value do
0 -> {wpx, wpy}
1 -> {-wpy, wpx}
2 -> {-wpx, -wpy}
3 -> {wpy, -wpx}
end
%{acc | wpx: wpx, wpy: wpy}
end
def handle_instructions(instructions, instruction_handler) do
acc = %{x: 0, y: 0, dir: :E, wpx: 10, wpy: -1}
Enum.reduce(instructions, acc, instruction_handler)
end
def parts do
input = parse_input()
%{x: x, y: y} = handle_instructions(input, &handle_instruction1/2)
part1 = abs(x) + abs(y)
%{x: x, y: y} = handle_instructions(input, &handle_instruction2/2)
part2 = abs(x) + abs(y)
{part1, part2}
end
end

45
2020/lib/days/day13.ex Normal file
View file

@ -0,0 +1,45 @@
defmodule AOC.Day13 do
def parse_input do
[depart, buses] = AOC.Util.input_lines(13, 1)
depart = String.to_integer(depart)
buses =
buses
|> String.split(",")
|> Enum.map(fn
bus when bus == "x" -> :x
bus -> String.to_integer(bus)
end)
{depart, buses}
end
def find_earliest_bus(depart, buses), do: find_earliest_bus(depart, buses, {nil, :infinity})
def find_earliest_bus(_, [], earliest), do: earliest
def find_earliest_bus(depart, [bus | tl], {_, earliest} = acc) do
rounds = div(depart, bus)
rounds = if rounds * bus < depart, do: rounds + 1, else: rounds
wait = rounds * bus - depart
acc = if wait < earliest, do: {bus, wait}, else: acc
find_earliest_bus(depart, tl, acc)
end
def find_offsets(buses) do
buses
|> Enum.with_index()
|> Enum.reject(&(elem(&1, 0) |> is_atom()))
end
def parts do
{depart, buses} = parse_input()
{bus, earliest} = find_earliest_bus(depart, Enum.reject(buses, &is_atom/1))
part1 = bus * earliest
offsets = find_offsets(buses)
{part1, offsets}
end
end

36
2020/lib/days/day2.ex Normal file
View file

@ -0,0 +1,36 @@
defmodule AOC.Day2 do
def parse_line(line) do
[min, max, char, password] = String.split(line, [" ", "-", ":"], trim: true)
password = String.to_charlist(password)
[char] = String.to_charlist(char)
min = String.to_integer(min)
max = String.to_integer(max)
[password, char, min, max]
end
def validate_password1(password, char, min, max) do
count = Enum.count(password, &(&1 == char))
count in min..max
end
def part1 do
AOC.Util.input_lines(2, 1)
|> Enum.map(&parse_line/1)
|> Enum.map(&apply(__MODULE__, :validate_password1, &1))
|> Enum.count(&Function.identity/1)
end
def validate_password2(password, char, pos1, pos2) do
m1 = Enum.at(password, pos1 - 1) == char
m2 = Enum.at(password, pos2 - 1) == char
(m1 or m2) and not (m1 and m2)
end
def part2 do
AOC.Util.input_lines(2, 1)
|> Enum.map(&parse_line/1)
|> Enum.map(&apply(__MODULE__, :validate_password2, &1))
|> Enum.count(&Function.identity/1)
end
end

33
2020/lib/days/day3.ex Normal file
View file

@ -0,0 +1,33 @@
defmodule AOC.Day3 do
@line_length 31
def count_trees(lines, jump), do: count_trees(lines, jump, 0, 0)
def count_trees([], _, _, acc), do: acc
def count_trees([hd | tl], jump, x, acc) do
acc =
acc +
if String.at(hd, x) == "#" do
1
else
0
end
x = rem(x + jump, @line_length)
count_trees(tl, jump, x, acc)
end
def part1 do
AOC.Util.input_lines(3, 1)
|> count_trees(3)
end
def part2 do
lines = AOC.Util.input_lines(3, 1)
count_down2 = Enum.take_every(lines, 2) |> count_trees(1)
tree_counts = Enum.map([1, 3, 5, 7], &count_trees(lines, &1))
Enum.reduce([count_down2 | tree_counts], &*/2)
end
end

82
2020/lib/days/day4.ex Normal file
View file

@ -0,0 +1,82 @@
defmodule AOC.Day4 do
def parse_input(lines), do: parse_input(lines, [], %{})
def parse_input([], acc, el), do: [el | acc]
def parse_input(["" | tl], acc, el), do: parse_input(tl, [el | acc], %{})
def parse_input([hd | tl], acc, el) do
el =
String.split(hd)
|> Enum.map(&String.split(&1, ":"))
|> Enum.map(fn [k, v] -> {k, v} end)
|> Enum.into(el)
parse_input(tl, acc, el)
end
def validate_field_presence(%{
"byr" => _,
"iyr" => _,
"eyr" => _,
"hgt" => _,
"hcl" => _,
"ecl" => _,
"pid" => _
}),
do: true
def validate_field_presence(_), do: false
def part1 do
AOC.Util.input_lines(4, 1)
|> parse_input()
|> Enum.filter(&validate_field_presence/1)
|> Enum.count()
end
def validate_height(height) do
if String.ends_with?(height, ["cm", "in"]) do
{height, measure} = String.split_at(height, -2)
height = String.to_integer(height)
case measure do
"cm" -> height >= 150 and height <= 193
"in" -> height >= 59 and height <= 76
end
else
false
end
end
def validate_fields(%{
"byr" => byr,
"iyr" => iyr,
"eyr" => eyr,
"hgt" => hgt,
"hcl" => hcl,
"ecl" => ecl,
"pid" => pid
}) do
byr = String.to_integer(byr)
iyr = String.to_integer(iyr)
eyr = String.to_integer(eyr)
[
byr >= 1920 and byr <= 2002,
iyr >= 2010 and iyr <= 2020,
eyr >= 2020 and eyr <= 2030,
validate_height(hgt),
hcl =~ ~r/^#([a-f]|[0-9]){6}$/,
ecl in ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"],
pid =~ ~r/^[0-9]{9}$/
]
|> Enum.reduce(&and/2)
end
def part2 do
AOC.Util.input_lines(4, 1)
|> parse_input()
|> Enum.filter(&validate_field_presence/1)
|> Enum.filter(&validate_fields/1)
|> Enum.count()
end
end

42
2020/lib/days/day5.ex Normal file
View file

@ -0,0 +1,42 @@
defmodule AOC.Day5 do
@upper 'BR'
@lower 'FL'
def search_range([], x, x), do: x
def search_range([hd | tl], low, high) when hd in @lower do
search_range(tl, low, div(high + 1 + low, 2) - 1)
end
def search_range([hd | tl], low, high) when hd in @upper do
search_range(tl, div(low + high + 1, 2), high)
end
def search_seat({row_search, col_search}) do
row = search_range(row_search, 0, 127)
column = search_range(col_search, 0, 7)
{row, column}
end
def part1 do
AOC.Util.input_lines(5, 1)
|> Enum.map(&String.to_charlist/1)
|> Enum.map(&Enum.split(&1, 7))
|> Enum.map(&search_seat/1)
|> Enum.map(fn {r, c} -> r * 8 + c end)
|> Enum.max()
end
def find_missing_seat([l, r | _]) when r != l + 1, do: l + 1
def find_missing_seat([_ | tl]), do: find_missing_seat(tl)
def part2 do
AOC.Util.input_lines(5, 1)
|> Enum.map(&String.to_charlist/1)
|> Enum.map(&Enum.split(&1, 7))
|> Enum.map(&search_seat/1)
|> Enum.map(fn {r, c} -> r * 8 + c end)
|> Enum.sort()
|> find_missing_seat()
end
end

29
2020/lib/days/day6.ex Normal file
View file

@ -0,0 +1,29 @@
defmodule AOC.Day6 do
def part1 do
AOC.Util.input_file(6, 1)
|> String.split("\n\n")
|> Enum.map(fn group ->
group
|> String.replace("\n", "")
|> String.to_charlist()
|> Enum.uniq()
|> Enum.count()
end)
|> Enum.sum()
end
def part2 do
AOC.Util.input_file(6, 1)
|> String.split("\n\n")
|> Enum.map(fn group ->
count = String.split(group, "\n") |> Enum.count()
group
|> String.replace("\n", "")
|> String.to_charlist()
|> Enum.frequencies()
|> Enum.count(fn {_, v} -> v == count end)
end)
|> Enum.sum()
end
end

61
2020/lib/days/day7.ex Normal file
View file

@ -0,0 +1,61 @@
defmodule AOC.Day7 do
def parse_input(lines), do: parse_input(lines, %{})
def parse_input([], acc), do: acc
def parse_input([str | tl], acc) do
[container, str] = String.split(str, " bags contain ")
inner =
str
|> String.split(", ")
|> Enum.map(fn
"no other bags." ->
[]
bags ->
[num, adj1, adj2, _] = String.split(bags)
{String.to_integer(num), "#{adj1} #{adj2}"}
end)
|> List.flatten()
parse_input(tl, Map.put(acc, container, inner))
end
def find_golden_containers(map) do
map
|> Map.keys()
|> Enum.filter(fn
"shiny gold" -> false
bag -> find_golden_containers(map, bag)
end)
end
def find_golden_containers(_, "shiny gold"), do: true
def find_golden_containers(map, bag) do
map[bag]
|> Enum.map(fn {_, x} -> find_golden_containers(map, x) end)
|> Enum.any?()
end
def part1 do
AOC.Util.input_lines(7, 1)
|> parse_input()
|> find_golden_containers()
|> Enum.count()
end
def count_bags(map), do: count_bags(map, "shiny gold")
def count_bags(map, bag) do
map[bag]
|> Enum.map(fn {n, x} -> n * (count_bags(map, x) + 1) end)
|> Enum.sum()
end
def part2 do
AOC.Util.input_lines(7, 1)
|> parse_input()
|> count_bags()
end
end

60
2020/lib/days/day8.ex Normal file
View file

@ -0,0 +1,60 @@
defmodule AOC.Day8 do
def get_input do
AOC.Util.input_lines(8, 1)
|> Enum.map(fn line ->
[opcode, arg] = String.split(line)
{String.to_atom(opcode), String.to_integer(arg)}
end)
|> Enum.with_index()
|> Enum.into(%{}, fn {v, k} -> {k, v} end)
end
def find_loop(program), do: find_loop(program, 0, MapSet.new(), 0)
def find_loop(program, acc, seen, ip) do
cond do
MapSet.member?(seen, ip) ->
acc
ip >= length(Map.keys(program)) ->
{true, acc}
true ->
seen = MapSet.put(seen, ip)
{acc, ip} =
case program[ip] do
{:acc, arg} -> {acc + arg, ip + 1}
{:nop, _} -> {acc, ip + 1}
{:jmp, arg} -> {acc, ip + arg}
end
find_loop(program, acc, seen, ip)
end
end
def part1 do
get_input()
|> find_loop()
end
def perturb_program(program) do
program
|> Stream.reject(fn {_, {opcode, _}} -> opcode == :acc end)
|> Stream.map(fn
{ip, {:nop, arg}} -> {ip, {:jmp, arg}}
{ip, {:jmp, arg}} -> {ip, {:nop, arg}}
end)
|> Stream.map(fn {ip, v} ->
Map.put(program, ip, v)
end)
end
def part2 do
get_input()
|> perturb_program()
|> Stream.map(&find_loop/1)
|> Stream.filter(&is_tuple/1)
|> Enum.to_list()
end
end

46
2020/lib/days/day9.ex Normal file
View file

@ -0,0 +1,46 @@
defmodule AOC.Day9 do
@preamble_len 25
def find_invalid(queue, [hd | tl]) do
sums =
:queue.to_list(queue)
|> Combination.combine(2)
|> Enum.map(&Enum.sum/1)
queue =
:queue.in(hd, queue)
|> :queue.drop()
if hd in sums do
find_invalid(queue, tl)
else
hd
end
end
def find_weakness(invalid, [_ | tl] = nums) do
result =
Enum.reduce_while(nums, {0, []}, fn num, {sum, l} ->
sum = sum + num
if sum < invalid, do: {:cont, {sum, [num | l]}}, else: {:halt, {sum, l}}
end)
case result do
{sum, l} when sum == invalid -> Enum.min_max(l)
_ -> find_weakness(invalid, tl)
end
end
def parts do
input = AOC.Util.input_integers(9, 1)
{preamble, nums} = Enum.split(input, @preamble_len)
invalid =
preamble
|> :queue.from_list()
|> find_invalid(nums)
{min, max} = find_weakness(invalid, input)
{invalid, min + max}
end
end

21
2020/lib/util.ex Normal file
View file

@ -0,0 +1,21 @@
defmodule AOC.Util do
def input_file_name(day, input) do
Path.join([File.cwd!(), "inputs", "day#{day}", "input#{input}.txt"])
end
def input_file(day, input) do
input_file_name(day, input)
|> File.read!()
end
def input_lines(day, input) do
input_file_name(day, input)
|> File.stream!()
|> Enum.map(&String.trim/1)
end
def input_integers(day, input) do
input_lines(day, input)
|> Enum.map(&String.to_integer/1)
end
end

27
2020/mix.exs Normal file
View file

@ -0,0 +1,27 @@
defmodule Aoc2020.MixProject do
use Mix.Project
def project do
[
app: :aoc2020,
version: "0.1.0",
elixir: "~> 1.12-dev",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:combination, "~> 0.0.3"}
]
end
end

3
2020/mix.lock Normal file
View file

@ -0,0 +1,3 @@
%{
"combination": {:hex, :combination, "0.0.3", "746aedca63d833293ec6e835aa1f34974868829b1486b1e1cb0685f0b2ae1f41", [:mix], [], "hexpm", "72b099f463df42ef7dc6371d250c7070b57b6c5902853f69deb894f79eda18ca"},
}

View file

@ -0,0 +1 @@
ExUnit.start()

4
2021/.formatter.exs Normal file
View file

@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

17
2021/lib/days/day1.ex Normal file
View file

@ -0,0 +1,17 @@
defmodule AOC.Day1 do
def part1 do
AOC.Util.input_integers(1, 1)
|> Enum.chunk_every(2, 1, :discard)
|> Enum.map(fn [x, y] -> y > x end)
|> Enum.count(& &1)
end
def part2 do
AOC.Util.input_integers(1, 1)
|> Enum.chunk_every(3, 1, :discard)
|> Enum.map(&Enum.sum/1)
|> Enum.chunk_every(2, 1, :discard)
|> Enum.map(fn [x, y] -> y > x end)
|> Enum.count(& &1)
end
end

27
2021/lib/days/day2.ex Normal file
View file

@ -0,0 +1,27 @@
defmodule AOC.Day2 do
def parse_input do
AOC.Util.input_lines(2, 1)
|> Enum.map(fn l ->
[dir, amount] = String.split(l, " ")
{String.to_atom(dir), String.to_integer(amount)}
end)
end
def part1 do
parse_input()
|> Enum.reduce({0, 0}, fn
{:forward, amount}, {distance, depth} -> {distance + amount, depth}
{:down, amount}, {distance, depth} -> {distance, depth + amount}
{:up, amount}, {distance, depth} -> {distance, depth - amount}
end)
end
def part2 do
parse_input()
|> Enum.reduce({0, 0, 0}, fn
{:down, amount}, {distance, depth, aim} -> {distance, depth, aim + amount}
{:up, amount}, {distance, depth, aim} -> {distance, depth, aim - amount}
{:forward, amount}, {distance, depth, aim} -> {distance + amount, depth + aim * amount, aim}
end)
end
end

21
2021/lib/util.ex Normal file
View file

@ -0,0 +1,21 @@
defmodule AOC.Util do
def input_file_name(day, input) do
Path.join([File.cwd!(), "inputs", "day#{day}", "input#{input}.txt"])
end
def input_file(day, input) do
input_file_name(day, input)
|> File.read!()
end
def input_lines(day, input) do
input_file_name(day, input)
|> File.stream!()
|> Enum.map(&String.trim/1)
end
def input_integers(day, input) do
input_lines(day, input)
|> Enum.map(&String.to_integer/1)
end
end

28
2021/mix.exs Normal file
View file

@ -0,0 +1,28 @@
defmodule Aoc2021.MixProject do
use Mix.Project
def project do
[
app: :aoc2021,
version: "0.1.0",
elixir: "~> 1.12",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end
end

4
2022/.formatter.exs Normal file
View file

@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

2
2022/Makefile Normal file
View file

@ -0,0 +1,2 @@
day%:
mix run -e "AOC.Day$*.solve()"

21
2022/README.md Normal file
View file

@ -0,0 +1,21 @@
# Aoc2022
**TODO: Add description**
## Installation
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `aoc2022` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:aoc2022, "~> 0.1.0"}
]
end
```
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at <https://hexdocs.pm/aoc2022>.

41
2022/day10.py Executable file
View file

@ -0,0 +1,41 @@
#!/bin/python3
program = list()
with open('day10.txt', 'r') as f:
for line in f:
line = line.strip()
if line == "noop":
program.append("noop")
else:
[cmd, arg] = line.split(" ")
program.append((cmd, int(arg)))
states = list()
state = 1
for instruction in program:
if instruction == 'noop':
states.append(state)
else:
(cmd, arg) = instruction
states.append(state)
states.append(state)
state += arg
part1 = 0
for i in range(19, len(states), 40):
part1 += (i+1) * states[i]
print(part1)
for y in range(6):
for x in range(40):
index = y * 40 + x
state = states[index]
if x == state or x == state-1 or x == state+1:
print('#', end='')
else:
print('.', end='')
print('')

139
2022/day10.txt Normal file
View file

@ -0,0 +1,139 @@
noop
addx 12
addx -5
addx -1
noop
addx 4
noop
addx 1
addx 4
noop
addx 13
addx -8
noop
addx -19
addx 24
addx 1
noop
addx 4
noop
addx 1
addx 5
addx -1
addx -37
addx 16
addx -13
addx 18
addx -11
addx 2
addx 23
noop
addx -18
addx 9
addx -8
addx 2
addx 5
addx 2
addx -21
addx 26
noop
addx -15
addx 20
noop
addx 3
noop
addx -38
addx 3
noop
addx 26
addx -4
addx -19
addx 3
addx 1
addx 5
addx 3
noop
addx 2
addx 3
noop
addx 2
noop
noop
noop
noop
addx 5
noop
noop
noop
addx 3
noop
addx -30
addx -4
addx 1
addx 18
addx -8
addx -4
addx 2
noop
addx 7
noop
noop
noop
noop
addx 5
noop
noop
addx 5
addx -2
addx -20
addx 27
addx -20
addx 25
addx -2
addx -35
noop
noop
addx 4
addx 3
addx -2
addx 5
addx 2
addx -11
addx 1
addx 13
addx 2
addx 5
addx 6
addx -1
addx -2
noop
addx 7
addx -2
addx 6
addx 1
addx -21
addx 22
addx -38
addx 5
addx 3
addx -1
noop
noop
addx 5
addx 1
addx 4
addx 3
addx -2
addx 2
noop
addx 7
addx -1
addx 2
addx 4
addx -10
addx -19
addx 35
addx -1
noop
noop
noop

146
2022/day10test.txt Normal file
View file

@ -0,0 +1,146 @@
addx 15
addx -11
addx 6
addx -3
addx 5
addx -1
addx -8
addx 13
addx 4
noop
addx -1
addx 5
addx -1
addx 5
addx -1
addx 5
addx -1
addx 5
addx -1
addx -35
addx 1
addx 24
addx -19
addx 1
addx 16
addx -11
noop
noop
addx 21
addx -15
noop
noop
addx -3
addx 9
addx 1
addx -3
addx 8
addx 1
addx 5
noop
noop
noop
noop
noop
addx -36
noop
addx 1
addx 7
noop
noop
noop
addx 2
addx 6
noop
noop
noop
noop
noop
addx 1
noop
noop
addx 7
addx 1
noop
addx -13
addx 13
addx 7
noop
addx 1
addx -33
noop
noop
noop
addx 2
noop
noop
noop
addx 8
noop
addx -1
addx 2
addx 1
noop
addx 17
addx -9
addx 1
addx 1
addx -3
addx 11
noop
noop
addx 1
noop
addx 1
noop
noop
addx -13
addx -19
addx 1
addx 3
addx 26
addx -30
addx 12
addx -1
addx 3
addx 1
noop
noop
noop
addx -9
addx 18
addx 1
addx 2
noop
noop
addx 9
noop
noop
noop
addx -1
addx 2
addx -37
addx 1
addx 3
noop
addx 15
addx -21
addx 22
addx -6
addx 1
noop
addx 2
addx 1
noop
addx -10
noop
noop
addx 20
addx 1
addx 2
addx 2
addx -6
addx -11
noop
noop
noop

104
2022/day12.py Executable file
View file

@ -0,0 +1,104 @@
#!/bin/python3
import sys
sys.setrecursionlimit(1500)
hmap = list()
with open('day12.txt', 'r') as f:
for line in f:
hmap.append(line.strip())
h = len(hmap)
w = len(hmap[0])
for y in range(h):
for x in range(w):
if hmap[y][x] == 'S':
start = (x, y)
if hmap[y][x] == 'E':
end = (x, y)
def get_elevation(char):
if char == 'S':
return ord('a')
if char == 'E':
return ord('z')
return ord(char)
def get_adjacents(pos):
(x, y) = pos
return [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]
def in_bounds(pos):
(x, y) = pos
return x >= 0 and x < w and y >= 0 and y < h
def get_char(hmap, pos):
(x, y) = pos
return hmap[y][x]
def valid_jump(hmap, pos, adj):
poschar = get_char(hmap, pos)
adjchar = get_char(hmap, adj)
poselev = get_elevation(poschar)
adjelev = get_elevation(adjchar)
return poselev + 1 >= adjelev
best_cost = {}
def find_path(hmap, path, pos):
if get_char(hmap, pos) == 'E':
return [path]
paths = list()
for adj in get_adjacents(pos):
if adj not in path and in_bounds(adj) and valid_jump(hmap, pos, adj):
if adj not in best_cost or best_cost[adj] > len(path):
best_cost[adj] = len(path)
new_path = set.copy(path)
new_path.add(adj)
paths.extend(find_path(hmap, new_path, adj))
return paths
shortest = None
paths = find_path(hmap, set([start]), start)
for path in paths:
if not shortest or len(path) < shortest:
shortest = len(path)
print('part1', shortest - 1)
trail_lengths = {}
def valid_jump2(hmap, pos, adj):
poschar = get_char(hmap, pos)
adjchar = get_char(hmap, adj)
poselev = get_elevation(poschar)
adjelev = get_elevation(adjchar)
return adjelev + 1 >= poselev
def find_trail(hmap, trail, pos):
for adj in get_adjacents(pos):
if adj not in trail and in_bounds(adj) and valid_jump2(hmap, pos, adj):
trail_length = len(trail) + 1
if adj not in trail_lengths or trail_lengths[adj] > trail_length:
trail_lengths[adj] = trail_length
new_trail = list.copy(trail)
new_trail.append(adj)
find_trail(hmap, new_trail, adj)
find_trail(hmap, [end], end)
shortest = None
for y in range(h):
for x in range(w):
if (x, y) in trail_lengths:
if get_elevation(get_char(hmap, (x, y))) == ord('a'):
trail_length = trail_lengths[(x, y)]
if not shortest or trail_length < shortest:
shortest = trail_length
print('part2', shortest - 1)

41
2022/day12.txt Normal file
View file

@ -0,0 +1,41 @@
abacccaaaacccccccccccaaaaaacccccaaaaaaccccaaacccccccccccccccccccccccccccccccccccccccccccaaaaa
abaaccaaaacccccccccccaaaaaaccccccaaaaaaaaaaaaaccccccccccccccccccccccccccccccccccccccccccaaaaa
abaaccaaaacccccccccccaaaaacccccaaaaaaaaaaaaaaaccccccccccccccccccccccccccccccccccccccccccaaaaa
abccccccccccccccccccccaaaaacccaaaaaaaaaaaaaaaacccccccccccccccccccccccccccaaaccccccccccccaaaaa
abccccccccccccccccccccaacaacccaaaaaaaaccaaaaaccccccccccccccccccccccccccccaaaccccccccccccaccaa
abcccccccccccccaacccaaaccccccaaaaaaaaaccaaaaaccccccccccccccccccccccccccccccacccccccccccccccca
abcccccccccccaaaaaaccaaaccacccccaaaaaaacccccccccccccccccccccccccciiiicccccccddddddccccccccccc
abcccccccccccaaaaaaccaaaaaaaccccaaaaaacccccaacccccccaaaccccccccciiiiiiiicccdddddddddacaaccccc
abccccccccccccaaaaaaaaaaaaacccccaaaaaaacaaaacccccccaaaacccccccchhiiiiiiiiicddddddddddaaaccccc
abcccccccccccaaaaaaaaaaaaaacccccccaaacccaaaaaacccccaaaaccccccchhhipppppiiiijjjjjjjddddaaccccc
abcccccccccccaaaaaaaaaaaaaaccccccccccccccaaaaaccccccaaaccccccchhhpppppppiijjjjjjjjjddeeaccccc
abcccccccccccccccccaaaaaaaacccccccccccccaaaaaccccccccccccccccchhppppppppppjjqqqjjjjjeeeaacccc
abccccccccccccccccccaaaaaaaacccccccccccccccaacccccccccccccccchhhpppuuuupppqqqqqqqjjjeeeaacccc
abcccccccccccccccccccaacccacccccccccccccccccccccccccccccccccchhhopuuuuuuppqqqqqqqjjjeeecccccc
abacccccccccccccaaacaaaccccccccccccccccccccccccccccaaccccccchhhhoouuuuuuuqvvvvvqqqjkeeecccccc
abaccccccccccccaaaaaacccccaaccccccccccccccccccccccaaaccccccchhhooouuuxxxuvvvvvvqqqkkeeecccccc
abaccccccccccccaaaaaacccaaaaaaccccccccccccccccccaaaaaaaaccchhhhooouuxxxxuvyyyvvqqqkkeeecccccc
abcccccccccccccaaaaacccaaaaaaaccccccccccccccccccaaaaaaaaccjjhooooouuxxxxyyyyyvvqqqkkeeecccccc
abccccccccccccccaaaaaacaaaaaaaccccccccaaaccccccccaaaaaaccjjjooootuuuxxxxyyyyyvvqqkkkeeecccccc
abccccccccccccccaaaaaaaaaaaaacccccccccaaaacccccccaaaaaacjjjooootttuxxxxxyyyyvvrrrkkkeeecccccc
SbccccccccccccccccccaaaaaaaaacccccccccaaaacccccccaaaaaacjjjoootttxxxEzzzzyyvvvrrrkkkfffcccccc
abcccccccccccaaacccccaaaaaaacaaaccccccaaaccccccccaaccaacjjjoootttxxxxxyyyyyyvvvrrkkkfffcccccc
abcccccccccaaaaaacccaaaaaacccaaacacccaacccccccccccccccccjjjoootttxxxxyxyyyyyywvvrrkkkfffccccc
abcccccccccaaaaaacccaaaaaaaaaaaaaaaccaaacaaacccccaacccccjjjnnnttttxxxxyyyyyyywwwrrkkkfffccccc
abcaacacccccaaaaacccaaacaaaaaaaaaaaccaaaaaaacccccaacaaacjjjnnnntttttxxyywwwwwwwwrrrlkfffccccc
abcaaaaccccaaaaacccccccccaacaaaaaaccccaaaaaacccccaaaaacccjjjnnnnnttttwwywwwwwwwrrrrllfffccccc
abaaaaaccccaaaaaccccccaaaaaccaaaaacaaaaaaaaccccaaaaaaccccjjjjinnnntttwwwwwsssrrrrrllllffccccc
abaaaaaaccccccccccccccaaaaacaaaaaacaaaaaaaaacccaaaaaaacccciiiiinnnntswwwwssssrrrrrlllfffccccc
abacaaaaccccccccccccccaaaaaacaaccccaaaaaaaaaaccccaaaaaaccccciiiinnnssswwsssssllllllllfffccccc
abccaaccccccccccccccccaaaaaaccccccccccaaacaaaccccaaccaacccccciiiinnsssssssmmllllllllfffaacccc
abccccccccccccccccccccaaaaaaccccccccccaaaccccccccaaccccccccccciiinnmsssssmmmmlllllgggffaacccc
abcccccccccccccccaccccccaaacccccccccccaaccccccccccccccccccccccciiimmmsssmmmmmgggggggggaaacccc
abcccccccccaaaaaaaaccccccccccccccccccccccccccccaaaaaccccccccccciiimmmmmmmmmgggggggggaaacccccc
abccccccccccaaaaaaccccccccccccccccccaacccccccccaaaaacccccccccccciiimmmmmmmhhggggcaaaaaaaccccc
abccccccccccaaaaaacccccccccccccccccaacccccccccaaaaaacccccccccccciihhmmmmhhhhgccccccccaacccccc
abccccaacaaaaaaaaaaccccccccccccccccaaaccccccccaaaaaaccccccccccccchhhhhhhhhhhaaccccccccccccccc
abccccaaaaaaaaaaaaaaccccccccccaaccaaaaccccccccaaaaaacccaaacccccccchhhhhhhhaaaaccccccccccccccc
abcccaaaaaaaaaaaaaaaccccccccaaaaaacaaaacacaccccaaaccccaaaacccccccccchhhhccccaaccccccccccaaaca
abcccaaaaaacacaaacccccccccccaaaaaaaaaaaaaaacccccccccccaaaacccccccccccaaaccccccccccccccccaaaaa
abcccccaaaacccaaaccccccccccaaaaaaaaaaaaaaaaccccccccccccaaacccccccccccaaacccccccccccccccccaaaa
abcccccaacccccaacccccccccccaaaaaaaaaaaaaccccccccccccccccccccccccccccccccccccccccccccccccaaaaa

5
2022/day12test.txt Normal file
View file

@ -0,0 +1,5 @@
Sabqponm
abcryxxl
accszExk
acctuvwj
abdefghi

89
2022/day14.py Executable file
View file

@ -0,0 +1,89 @@
#!/bin/python3
from collections import defaultdict
from enum import Enum
from itertools import pairwise
class Tile(Enum):
AIR = 1
ROCK = 2
SOURCE = 3
SAND = 4
grid = defaultdict(lambda: Tile.AIR)
with open('inputs/day14.txt', 'r') as f:
for line in f:
for (start, end) in pairwise(line.strip().split(' -> ')):
[sx, sy] = map(int, start.split(','))
[ex, ey] = map(int, end.split(','))
dx = 0
dy = 0
if ex > sx:
dx = 1
elif ex < sx:
dx = -1
if ey > sy:
dy = 1
elif ey < sy:
dy = -1
curx = sx
cury = sy
grid[(curx, cury)] = Tile.ROCK
while curx != ex or cury != ey:
curx += dx
cury += dy
grid[(curx, cury)] = Tile.ROCK
highest_y = -1
for (x, y), tile in grid.items():
if y > highest_y:
highest_y = y
def query_grid(x, y):
if y == highest_y + 2:
return Tile.ROCK
return grid[(x, y)]
(sourcex, sourcey) = (500, 0)
def abyss_underneath(x, y):
for (gridx, gridy), tile in grid.items():
if gridy > y and gridx == x and tile != Tile.AIR:
return False
return True
# voided = False
blocked = False
while True:
(x, y) = (sourcex, sourcey)
while True:
# if abyss_underneath(x, y):
# voided = True
# break
if query_grid(x, y+1) == Tile.AIR:
y += 1
elif query_grid(x-1, y+1) == Tile.AIR:
y += 1
x -= 1
elif query_grid(x+1, y+1) == Tile.AIR:
y += 1
x += 1
else:
if (x, y) == (sourcex, sourcey):
blocked = True
break
# if voided:
# break
if blocked:
break
grid[(x, y)] = Tile.SAND
rest_count = 0
for (x, y), tile in grid.items():
if tile == Tile.SAND:
rest_count += 1
print(rest_count + 1)

101
2022/day15.py Executable file
View file

@ -0,0 +1,101 @@
#!/bin/bash
# thanks github.com/bernadetten
import sys
import re
from itertools import pairwise
test = bool(int(sys.argv[1]))
file_path = ""
data = ""
prodata = []
given_y = [int(sys.argv[2])]
absent_points = []
part1 = bool(int(sys.argv[3]))
max_y = int(sys.argv[4])
if test:
file_path = "test_day_15.txt"
else:
file_path = "input_day_15.txt"
with open(file_path, "r") as f:
data = f.read().split("\n")
# The anhatten distance
def md(x1, y1, x2, y2):
return abs(x1 - x2) + abs(y1 - y2)
# Processing the data.
for line in data:
if line != "":
m = re.match(
r"Sensor at x=(?P<sx>-?\d+), y=(?P<sy>-?\d+): closest beacon is at x=(?P<bx>-?\d+), y=(?P<by>-?\d+)",
line.strip(),
)
x_s = int(m.group("sx"))
y_s = int(m.group("sy"))
x_b = int(m.group("bx"))
y_b = int(m.group("by"))
dis = md(x_s, y_s, x_b, y_b)
prodata += [((x_s, y_s), (x_b, y_b), dis)]
# All y-values we want to loop over if part 2
if not part1:
given_y = [x for x in range(0, max_y + 1)]
# Merge all ranges
def mergeranges(ranges):
super_range = ranges[0]
ranges = ranges[1:]
for (xl, xh) in ranges:
# print('super', super_range)
#print('comparing to', xl, ' ', xh)
if not (xl - 1 <= super_range[1] and xl >= super_range[0]):
return xl - 1
if xh > super_range[1]:
super_range = (super_range[0], xh)
return None
# Now we calculate the impossible ranges
for y in given_y:
if part1:
beacon_on_y = [b[0] for _, b, _ in prodata if b[1] == y]
absent_points = []
#print(y)
# We need to add the ranges of points that are not available.
for source, beacon, dis in prodata:
height_diff = abs(source[1] - y)
remain_dist = dis - height_diff
if remain_dist >= 0:
# print('Source ', source, ' y ', y, ' dis ', dis, ' diff ', height_diff)
lower_x = source[0] - remain_dist
higher_x = source[0] + remain_dist
if part1:
absent_points += [
x for x in range(lower_x, higher_x + 1) if x not in beacon_on_y
]
else:
absent_points += [(lower_x, higher_x)]
# If we are doing part two we need to post process the output per line.
if not part1:
# print(absent_points)
absent_points = sorted(absent_points)
#print(absent_points)
result = mergeranges(absent_points)
if result != None:
print('part2, x:', result, 'y:', y, 'output:', result *4000000 +y)
sys.exit()
if part1:
print('part1', len(set(absent_points)))

103
2022/day16.py Executable file
View file

@ -0,0 +1,103 @@
#!/bin/python3
import re
from dijkstar import Graph, find_path
import numpy as np
from itertools import combinations
import itertools as it
from tqdm import tqdm
valves = list()
with open('inputs/day16.txt', 'r') as f:
for line in f:
m = re.match(r"Valve (?P<name>[A-Z]{2}) has flow rate=(?P<rate>\d+); tunnels? leads? to valves? (?P<tunnels>.*)", line.strip())
name = m.group("name")
rate = int(m.group("rate"))
tunnels = m.group("tunnels").split(", ")
valves.append({"name": name, "rate": rate, "tunnels": tunnels})
indices = {}
for i, valve in enumerate(valves):
indices[valve["name"]] = i
graph = Graph()
for v1 in valves:
for v2 in v1["tunnels"]:
graph.add_edge(v1["name"], v2, 1)
graph.add_edge(v2, v1["name"], 1)
adjs = np.zeros((len(valves), len(valves)))
for v1, v2 in combinations(map(lambda v: v["name"], valves), 2):
cost = find_path(graph, v1, v2).total_cost
adjs[indices[v1], indices[v2]] = cost
adjs[indices[v2], indices[v1]] = cost
class Valve:
def __init__(self, name, rate):
self.name = name
self.rate = rate
def value(self, start, time_left):
cost = adjs[indices[start], indices[self.name]] + 1
return (self.rate * (time_left - cost), cost) # one off?
valve_map = dict()
valve_set = set()
for valve in valves:
if valve["rate"] > 0:
valve_set.add(valve["name"])
valve_map[valve["name"]] = Valve(valve["name"], valve["rate"])
def search(valve_set, current, time_left, visited):
to_visit_set = valve_set.difference(visited)
best_score = 0
for to_visit in to_visit_set:
# print("time left:", time_left)
# print("current:", current)
# print("going to visit:", to_visit)
visited_copy = visited.copy()
visited_copy.add(to_visit)
score, dtime = valve_map[to_visit].value(current, time_left)
# print("+score:", score, "+time", dtime)
if time_left - dtime >= 0:
score = score + search(valve_set, to_visit, time_left - dtime, visited_copy)
if not best_score or score > best_score:
best_score = score
return best_score
# print('part1', search(valve_set, "AA", 30, set()))
# part2 idea
# BIGBRAIN
# divide valve set in two disjoint sets
# apply same search algorithm to both sets.
# sum the scores of the sets to get total score
# brute force set distribution
def partition(pred, iterable):
t1, t2 = it.tee(iterable)
return it.filterfalse(pred, t1), filter(pred, t2)
def partitions(l):
return list(filter(lambda x: [] not in x, [[[x[1] for x in f] for f in partition(lambda x: x[0], zip(pattern, l))] for pattern in it.product([True, False], repeat=len(l))]))
# for [lhs, rhs] in parts:
# if (set(lhs), set(rhs)) not in result and (set(rhs), set(lhs)) not in result:
# result.append((set(lhs), set(rhs)))
# return result
best_score = 0
for part in tqdm(partitions(list(valve_set))):
[part1, part2] = part
part1 = set(part1)
score1 = search(part1, 'AA', 26, set())
part2 = set(part2)
score2 = search(part2, 'AA', 26, set())
grand_score = score1 + score2
if grand_score > best_score:
best_score = grand_score
print('part2', best_score)

311
2022/day17.py Executable file
View file

@ -0,0 +1,311 @@
#!/bin/python3
from enum import Enum
from collections import defaultdict
from itertools import pairwise, combinations
class Move(Enum):
LEFT = 1
RIGHT = 2
DOWN = 3
moves = list()
with open('inputs/day17.txt', 'r') as f:
for line in f:
for char in line.strip():
if char == '<':
moves.append(Move.LEFT)
elif char == '>':
moves.append(Move.RIGHT)
def move_stream():
while True:
for i, d in enumerate(moves):
yield (i, d)
yield (i, Move.DOWN)
move_map = {Move.LEFT: (-1, 0), Move.RIGHT: (1, 0), Move.DOWN: (0, -1)}
class Rock():
def __init__(self, shape):
self.blocks = shape
def init_position(self, y_top):
self.blocks = list(map(lambda pos: (pos[0] + 2, pos[1] + y_top + 4), self.blocks))
def move(self, chamber, move):
new_blocks = self.move_blocks(move)
if self.check_valid(chamber, new_blocks):
self.blocks = new_blocks
return True
else:
return False
def move_blocks(self, move):
(movex, movey) = move_map[move]
return list(map(lambda block: (block[0] + movex, block[1] + movey), self.blocks))
def check_valid(self, chamber, blocks):
for (x, y) in blocks:
if x > 6 or x < 0 or chamber[y][x]:
return False
return True
shapes = [
[(0, 0), (1, 0), (2, 0), (3, 0)],
[(0, 1), (1, 1), (2, 1), (1, 0), (1, 2)],
[(0, 0), (1, 0), (2, 0), (2, 1), (2, 2)],
[(0, 0), (0, 1), (0, 2), (0, 3)],
[(0, 0), (1, 0), (0, 1), (1, 1)]
]
def rock_stream():
while True:
for i, shape in enumerate(shapes):
yield (i, Rock(shape.copy()))
chamber = defaultdict(lambda: defaultdict(lambda: False))
for i in range(7):
chamber[-1][i] = True
def print_chamber(chamber, rock, print_index):
keys = list(reversed(sorted(chamber.keys())))
for key in keys:
if print_index:
print(f'{key}\t', end='')
for i in range(7):
if chamber[key][i]:
print('#', end='')
elif rock and (i, key) in rock.blocks:
print('@', end='')
else:
print('.', end='')
print('')
def prune_chamber(chamber):
ys = list(reversed(sorted(chamber.keys())))
prune_height = None
for y_high, y_low in pairwise(ys):
prunable = True
for x in range(7):
if not chamber[y_high][x] and not chamber[y_low][x]:
prunable = False
break
if prunable:
prune_height = y_low
break
if prune_height:
for y in ys:
if y < prune_height:
del chamber[y]
return prune_height != None
def row_to_mask(row):
mask = 0
bit = 1
for x in range(6, -1, -1):
if row[x]:
mask = mask | bit
bit = bit << 1
return mask
barrier_fingerprints = defaultdict(lambda: list())
rock_count = 20220
prune_freq = 100
y_top = -1
moves_gen = move_stream()
rocks_gen = rock_stream()
rocks_fallen = 0
rock_idx = None
for rock_idx, rock in rocks_gen:
rock.init_position(y_top)
for move_idx, move in moves_gen:
moved = rock.move(chamber, move)
if not moved and move == Move.DOWN:
for (x, y) in rock.blocks:
if y > y_top:
y_top = y
chamber[y][x] = True
rocks_fallen += 1
break
ys = set(map(lambda x: x[1], rock.blocks))
for y in ys:
all_filled = True
for x in range(7):
if not chamber[y][x] and not chamber[y-1][x]:
all_filled = False
break
if all_filled:
mask_high = row_to_mask(chamber[y])
mask_low = row_to_mask(chamber[y-1])
fingerprint = (rock_idx, move_idx, mask_high, mask_low)
barrier_fingerprints[fingerprint].append((rocks_fallen, y))
if rocks_fallen == rock_count:
break
print('part1', y_top + 1)
candidate_fp = None
candidate_ys_count = 0
for fp, ys in barrier_fingerprints.items():
l = len(ys)
if l > candidate_ys_count:
candidate_ys_count = l
candidate_fp = fp
# print('candidate FP:', candidate_fp)
first_occ = barrier_fingerprints[candidate_fp][0]
second_occ = barrier_fingerprints[candidate_fp][1]
height_cycle = second_occ[1] - first_occ[1]
rock_cycle = second_occ[0] - first_occ[0]
# print('first occurance:', 'height', first_occ[1], 'fallen', first_occ[0])
# print('second occurance:', 'height', second_occ[1], 'fallen', second_occ[0])
# print('height cycle:', second_occ[1] - first_occ[1])
# print('rock cycle:', second_occ[0] - first_occ[0])
rocks_left = 1000000000000 - first_occ[0]
superheight = first_occ[1]
superheight += (rocks_left // rock_cycle) * height_cycle
rocks_left %= rock_cycle
print(rocks_left, superheight)
# We just need $rocks_left rocks more!
# Move to the next cycle point
# Then simulate $rocks_left movements to get the height this generates.
# Add this to superheight then subtract one height_cycle.
for rock_idx, rock in rocks_gen:
rock.init_position(y_top)
for move_idx, move in moves_gen:
moved = rock.move(chamber, move)
if not moved and move == Move.DOWN:
for (x, y) in rock.blocks:
if y > y_top:
y_top = y
chamber[y][x] = True
rocks_fallen += 1
break
ys = set(map(lambda x: x[1], rock.blocks))
cycle_start = False
for y in ys:
all_filled = True
for x in range(7):
if not chamber[y][x] and not chamber[y-1][x]:
all_filled = False
break
if all_filled:
mask_high = row_to_mask(chamber[y])
mask_low = row_to_mask(chamber[y-1])
fingerprint = (rock_idx, move_idx, mask_high, mask_low)
if fingerprint == candidate_fp:
cycle_start = True
break
if cycle_start:
break
start_height = y_top
for rock_idx, rock in rocks_gen:
rock.init_position(y_top)
for move_idx, move in moves_gen:
moved = rock.move(chamber, move)
if not moved and move == Move.DOWN:
for (x, y) in rock.blocks:
if y > y_top:
y_top = y
chamber[y][x] = True
rocks_left -= 1
break
if rocks_left == 0:
break
end_height = y_top
superheight += end_height - start_height
print('part2', superheight + 3)
# for fp, ys in barrier_fingerprints.items():
# print('fingerprint:', fp)
# print('count:', len(ys))
# NEW IDEA
# Find a cycle.
# A cycle can be characterized by: rock rotation, direction rotation and rock formation.
# Problem is, we need to save a lot of the rock formation, because new rocks can fall down a long while.
# Additionally, we cannot just save the height of each column, because rocks can move underneath hanging arches.
# Possible solution: find lines that block this.
# Possibly in one line, definitely in two lines.
# IDEA:
# Create bitmap.
# Easily compare bitmaps with eachother to find cycle
# def print_mask(mask):
# bit = 1 << 6
# for i in range(7):
# if mask & (bit >> i):
# print('1', end='')
# else:
# print('0', end='')
# print('')
# def print_bitmap(bitmap):
# for row in bitmap:
# print_mask(row)
# bitmap = []
# ys = list(reversed(sorted(chamber.keys())))
# y_min = min(ys)
# y_max = max(ys)
# for y in range(y_min + 1, y_max + 1):
# mask = 0
# bit = 1
# for x in range(6, -1, -1):
# if chamber[y][x]:
# mask = mask | bit
# bit = bit << 1
# print_mask(mask)
# bitmap.append(mask)
# def in_order(l):
# last = None
# for x in l:
# if last == None or x > last:
# last = x
# else:
# return False
# return True
# def same_distance(l):
# [y1, y2, y3] = l
# return y2 - y1 == y3 - y2
# def is_cycle(bitmap, l):
# [y1, y2, y3] = l
# distance = y3 - y2
# for i in range(distance + 1):
# if bitmap[y1+i] != bitmap[y2]+i:
# return False
# return True
# Now try to find the cycle!
# We loop over every row.
# We find all indices of this row in the whole chamber
# checked = []
# print('finding cycle')
# for row in bitmap:
# print('row:', row)
# if row not in checked:
# checked.append(row)
# indices = [i for i, x in enumerate(bitmap) if x == row]
# if len(indices) >= 3:
# for maybe_cycle in combinations(indices, 3):
# if in_order(maybe_cycle) and same_distance(maybe_cycle):
# if is_cycle(bitmap, maybe_cycle):
# print('FOUND CYCLE:', maybe_cycle)
# # print_bitmap(bitmap)

113
2022/day18.py Executable file
View file

@ -0,0 +1,113 @@
#!/bin/python3
from collections import defaultdict
from queue import Queue
cubes = set()
with open('inputs/day18.txt', 'r') as f:
for line in f:
[x, y, z] = line.split(',')
cubes.add((int(x), int(y), int(z)))
def ordered(pos1, pos2):
if pos1 > pos2:
return (pos1, pos2)
else:
return (pos2, pos1)
sides = defaultdict(lambda: 0)
for cube in cubes:
(x, y, z) = cube
cube_sides = []
cube_sides.append(ordered(cube, (x+1, y, z)))
cube_sides.append(ordered(cube, (x-1, y, z)))
cube_sides.append(ordered(cube, (x, y+1, z)))
cube_sides.append(ordered(cube, (x, y-1, z)))
cube_sides.append(ordered(cube, (x, y, z+1)))
cube_sides.append(ordered(cube, (x, y, z-1)))
for side in cube_sides:
sides[side] += 1
outer_sides = set()
for side, count in sides.items():
if count == 1:
outer_sides.add(side)
print("part1", len(outer_sides))
# Determine max and min coords
x_min = min(map(lambda a: a[0], cubes))
x_max = max(map(lambda a: a[0], cubes))
y_min = min(map(lambda a: a[1], cubes))
y_max = max(map(lambda a: a[1], cubes))
z_min = min(map(lambda a: a[2], cubes))
z_max = max(map(lambda a: a[2], cubes))
# Increase bounds by 1 in all directions
x_min -= 1
x_max += 1
y_min -= 1
y_max += 1
z_min -= 1
z_max += 1
# Flood fill from 1 corner to find all reachable cubes.
class SetQueue(Queue):
def _init(self, maxsize):
self.queue = set()
def _put(self, item):
self.queue.add(item)
def _get(self):
return self.queue.pop()
cube_queue = SetQueue()
cube_queue.put((x_min, y_min, z_min))
reachable_cubes = set()
max_cubes = (x_max - x_min) * (y_max - y_min) * (z_max - z_min)
while True:
if cube_queue.empty():
break
cube = cube_queue.get()
(x, y, z) = cube
reachable_cubes.add(cube)
neighbors = []
neighbors.append((x+1, y, z))
neighbors.append((x-1, y, z))
neighbors.append((x, y+1, z))
neighbors.append((x, y-1, z))
neighbors.append((x, y, z+1))
neighbors.append((x, y, z-1))
for neighbor in neighbors:
(nx, ny, nz) = neighbor
if nx < x_min or nx > x_max or ny < y_min or ny > y_max or nz < z_min or nz > z_max:
continue
if neighbor in reachable_cubes or neighbor in cubes:
continue
# Found a new empty cube!
cube_queue.put(neighbor)
# Okay, found all empty cube outside the droplet.
surface_sides = set()
for empty in reachable_cubes:
(x, y, z) = empty
cube_sides = []
cube_sides.append(ordered(empty, (x+1, y, z)))
cube_sides.append(ordered(empty, (x-1, y, z)))
cube_sides.append(ordered(empty, (x, y+1, z)))
cube_sides.append(ordered(empty, (x, y-1, z)))
cube_sides.append(ordered(empty, (x, y, z+1)))
cube_sides.append(ordered(empty, (x, y, z-1)))
for side in cube_sides:
if side in outer_sides:
surface_sides.add(side)
print("part2", len(surface_sides))

54
2022/day8.py Executable file
View file

@ -0,0 +1,54 @@
#!/bin/python3
forest = []
with open('day8.txt', 'r') as f:
for line in f:
forest.append(list(map(int, list(line.strip()))))
height = len(forest)
width = len(forest[0])
heighest = -1
heighest_x = -1
heighest_y = -1
for y in range(height):
for x in range(width):
h = forest[x][y]
tree_count = 1
tree_count_cur = 0
for cur_x in range(x+1, width):
tree_count_cur += 1
if forest[cur_x][y] >= h:
break
tree_count *= tree_count_cur
tree_count_cur = 0
for cur_x in range(x-1, -1, -1):
tree_count_cur += 1
if forest[cur_x][y] >= h:
break
tree_count *= tree_count_cur
tree_count_cur = 0
for cur_y in range(y+1, height):
tree_count_cur += 1
if forest[x][cur_y] >= h:
break
tree_count *= tree_count_cur
tree_count_cur = 0
for cur_y in range(y-1, -1, -1):
tree_count_cur += 1
if forest[x][cur_y] >= h:
break
tree_count *= tree_count_cur
if tree_count > heighest:
heighest = tree_count
heighest_x = x
heighest_y = y
print(x, y, heighest)

99
2022/day8.txt Normal file
View file

@ -0,0 +1,99 @@
113003322412033102023303501444545044215232525401341546163452453404402234201151432242402140110220101
332001304022012142421445502213221330453061535265122314201352335233021055055200345412200440033322200
011113132214324432134325045311145402450516101640412524056254134552334050434552541351100000142223210
120100233011423423144030334144351644642605521663331053414601341464201040045104150001214204243212330
032313022420343002352401031112122630544621450306410014210122655033613410314450242104133332033433110
330133431221024552500405304311611205251454505525065601244143364343441153320511500334525320443331122
232021314224321045040222145130205324423110304256225426345644345334310200416004113133521143332200422
312322022143422250013255366221252062135020112327134227764002156152041134323314242255102200014240004
212411010402324310541162616440606266620317315234166112525535542054554446314636025435501101142314410
130420010020500305012262532345565125253527765422533261626735742433241362062404452514044512024131310
241211034142224054050344306633445512263575724527746635663111434536510100261040501431453540340134211
241313213114241230212646636605641533121654131662127125143714342377771455431346140255405303533314030
200214302143123545226333105604234323144236661442633717414531213335635263423430225510502553055320124
432210433113545424321340236152364457166745737761176472274142327714574465315263302246430530531052340
044321111115013046066155407144655275272121513224325736736453741437462322257332111603344504052313220
423214232334431334032453034121465736632235428586864276787383246667147623517713521254056250023050122
341124205512002021001520535463145337475482376656634323542842654415315313467514115356311404235042224
132001402100660310301501776141144746672773424257875288227677277663442356545463514004411150412531212
001052001350350313612735275534436625275423778573334245773528222523563225127612470242660400232440014
000112513501320042013743116251356437388536835723273464367352632733656224242323651012010230151310024
432343513243516355144362617334462875826626872624526547773732534284688857151541627654520220114445210
030155000415201011165562424113226826748747748853864385358746645352362468546644524342115335322112153
521354124325146425431532157187775456325686557739354768338786565328828884835715454276200630310531024
453541003326165663116714725533384334462564846638857736639973473868246353547315725644665433532024310
550412430051564655211263423273445384473677893666497965987545884578247877687261326676604334421513240
413054444206603631433161684337566624388758573363447988796769799695582635658423643315241325425634024
215150330040102563666211553675525355868889739969438648979533595459347577832874756321426443250541325
421424650534663421741533522275548697677937396576933765698789956783468276533784535453223333266121254
422144151564541614312463257866683347483647399747895987469373443743399762878755625665635533442122100
142126413036631514413457664863683937946499766465555784756389698779343558673226534437441452602242233
305201320636671251145832252388563746733774564949748445664654449965453936743822654651524764154313443
011300622102111771164477857675385967936859964787497949987577437799784855267278677674646432241223234
340321113267666756754785648366853336456946997569954774746449465943647534953257556352535151305025463
541411012547643576586448655984493857478575997945994447954587596973768677885376565465523461502535643
444321100654632152854364424757747839747855469574958798776977549543479354379242483435267721134026240
020626205154575316847673866764644374748789977457499575788744688854499953995222366237635424744520350
335506510045711628565868794334457797677874456886875779795697459467453749364727248672726163736041204
500111603536263112863778287468558998649869948858895979757648556554566675849574438477347434571054505
122000100243546685578334388934875844674864976796788677978555975645687865954363424837536471770452415
141414215752566148738527647673948945657599775586897776875597686768689334698832463748744764733053124
100340653262173232623746876388947885855898958859977856795865855466954797947557362275815142426540331
466303032723142355554844869739456445889568997967558595977567767954454556686589744843263767635404425
004613266772514623473428884775998765955988667675865595697667595999549844548767382824562175546612214
223062321176322437826876799485789855749797897795766857786556556466469876653886288833557467773301562
413332261232125275243773533956777794896856665777776697967896558687464977634963578724434267752313063
552404621241274462672869963657657685959857786696669988675856559577744587934439473355436162566631240
435165353647675322378767844955594694568958979668688889986755769858696479453833942343873533447232052
244432367557727222376845574654778567657966566799677789797957677969848457379553465846862364131450331
500160365677454526747395979487899988575755756767767688698968968964795455975647975338665645777505164
102431235675118652565457756594548744578555576979976998997755878856465958937486343448585657465615526
246165542416756587676444776898888956766578897997878779867867799995588485976853457557557151277215635
001643325345324464653748985776747945569696578767779897778688898756644945899654857626437342132540232
012101664761176266736346897839595848575598988867686699987969655574844656549763626542283366457311330
561504075335422826822483989945889874569866596668697889889787698578564685356683642368537236162426203
352203514134651772748288733934776699589795768989986896977876655856647995457449532883535245357460413
033642404423741338448747543456567587875878659898696769778857567974989696766857638532623516361132200
616444206117715325587799743549596679896878996579778797758659755584898985549986338256726477267555103
520455143625244274365846334377848464679657799659996799959789655886895549885388585227864441542440633
301346217675555884462648646383444656479799855995796958569776779656497648598636775768426556776465212
520404231326621664428744458384498945886755796967559979558788575647874897993564426835362551773515204
316242511662326327222423774658467889697656957595795766869586965778777639684376585246752671616104436
415146426112762185773325386754349955694758878879858887885879799994465943455896555866711732413133541
355625411617227324663526785865944884474696755859788678978799585984575877863878686426651623174052622
250022125746424524625262754995697689898769757895898887999798967686567449959582647242127737515510342
525264040416627662865878845844435466984695749789657699584976867495646849545456285287242646554654353
036123646424431555263267827839763498876769495677697448449595455554764947373454763645727333510646146
204566364235641316654753765445963394466448895664985649465498769864394998376778764453573662441355520
220335031661255773663868585338574847865979585777445874888879656858779783486746544464161776603563641
222513656331342447187422756294679343838685457555849784967456454674489536467765228571211235451313300
420041535613636672654268683685394696895377789594449696975655499485443388622338663537334646443120355
525056224212611227113776876877874646779895859895448998785578796984395868862632743546145340000633644
404314430546135313471247434875543567783736878545548779967377554684776373253726223752325712616213051
353422360566111142127744587245868774578548754579967945935667489466386244448265471714226610251556141
240135510612042471674334266253242658953336636546539684393847584358732442564537232411555541300234143
555204024234655515726125842362866243634643845579964798949797638778425653264527614711662106606433551
203524350135524444622315434263233285368993457879757738399643368354787234632745135155274525361620440
340532455653452155645722264385685523579545388464998647475936784423755683487133452753535123313604354
352152244221611331745526617386458872637865488449639856654753583624523335337272114515341203461045505
312033003454166053225452625154365544367483828667456379835556776344278883841652574422331646601235245
354330514213011046317425234714582372762675574834484437275552425744868747672133251365644033361512332
044021444522010141412515121117476227878457643873272338756238823637528547351444752605411146631314215
232413442230001100251223172352214643455635846823657522575345326788747411734266577565251164231145220
131504320306315625216346311325345143883224276853882277427888248757813625336722630560555630113015013
024451223151264563630623162617513241445834482436236846786748364751551471325535132540104323422105400
124420553125506323053405346614111134556285246233525828237347884315614217572766434350535521515101401
130200351112000250166105345316513263244676855323883356633222244252121772667652426014110503513555221
400241412230012102424516231766252561312255446621244373337355416351623124213640652213520151043110444
322440423504102454033133351036544434155137522762124773455775324625526553424524313460144053442544330
324303335402501236440552111053234114555641277255456252443511634243752643304353256666504353255522122
241434204225354100532033205000145461776516534477176114531271372735543451231303326454043352113013420
334124213300015522546105345511323376357312632521613774424256342133105114520414061451141133554301031
211304431150451251125020043053260563634374764226536222654742522421115640025331113215553523303422011
123324243323523142132445503461621106650437431517676417742653314226115466013230223030345414021112341
100121244242050431353422620202033056213213561562676642451361622463016135301034322504250003434240420
202331344430130314251310046312513630614136423111235233115234253411664210435541154434125202004300041
311142442400021052335032430131001522121243633355511015105456130306054020525345400331240114301233431
303333210333101445104545232532514231420245342044224564606555504302423403203123103211431303412444103
322112022033322224210512330414230625446520203533135512231066520423212314402311345154232414213413203
210220340333424334214524143431005502542403323230305103516410534415015522312221415410344021130000212

106
2022/day9.py Executable file
View file

@ -0,0 +1,106 @@
#!/bin/python3
moves = []
with open('day9.txt', 'r') as f:
for line in f:
[direc, count] = line.split(' ')
count = int(count)
for i in range(count):
moves.append(direc)
hlocs = []
hloc = (0, 0)
for move in moves:
if move == 'U':
hloc = (hloc[0], hloc[1]-1)
if move == 'D':
hloc = (hloc[0], hloc[1]+1)
if move == 'R':
hloc = (hloc[0]+1, hloc[1])
if move == 'L':
hloc = (hloc[0]-1, hloc[1])
hlocs.append(hloc)
tlocs = set([(0, 0)])
tloc = (0, 0)
for hloc in hlocs:
if abs(hloc[0] - tloc[0]) > 1 or abs(hloc[1] - tloc[1]) > 1:
if hloc[0] < tloc[0]:
tloc = (tloc[0]-1, tloc[1])
elif hloc[0] > tloc[0]:
tloc = (tloc[0]+1, tloc[1])
if hloc[1] < tloc[1]:
tloc = (tloc[0], tloc[1]-1)
elif hloc[1] > tloc[1]:
tloc = (tloc[0], tloc[1]+1)
else:
if hloc[0] == tloc[0]+2:
tloc = (tloc[0]+1, tloc[1])
elif hloc[0] == tloc[0]-2:
tloc = (tloc[0]-1, tloc[1])
elif hloc[1] == tloc[1]+2:
tloc = (tloc[0], tloc[1]+1)
elif hloc[1] == tloc[1]-2:
tloc = (tloc[0], tloc[1]-1)
tlocs.add(tloc)
print("part1", len(tlocs))
def print_state(n, parts):
for y in range(-n, n):
for x in range(-n, n):
printed = False
for i in range(10):
if parts[i][0] == x and parts[i][1] == y:
printed = True
print(str(i), end='')
break
if not printed:
print('#', end='')
print('')
print('')
parts = []
visited = set([(0, 0)])
for i in range(10):
parts.append((0, 0))
for move in moves:
print(move)
for i in range(10):
if i == 0:
if move == 'R':
parts[0] = (parts[0][0]+1, parts[0][1])
if move == 'L':
parts[0] = (parts[0][0]-1, parts[0][1])
if move == 'U':
parts[0] = (parts[0][0], parts[0][1]-1)
if move == 'D':
parts[0] = (parts[0][0], parts[0][1]+1)
else:
(prevx, prevy) = parts[i-1]
if abs(prevx - parts[i][0]) > 1 or abs(prevy - parts[i][1]) > 1:
if prevx < parts[i][0]:
parts[i] = (parts[i][0]-1, parts[i][1])
elif prevx > parts[i][0]:
parts[i] = (parts[i][0]+1, parts[i][1])
if prevy < parts[i][1]:
parts[i] = (parts[i][0], parts[i][1]-1)
elif prevy > parts[i][1]:
parts[i] = (parts[i][0], parts[i][1]+1)
else:
if prevx == parts[i][0]+2:
parts[i] = (parts[i][0]+1, parts[i][1])
elif prevx == parts[i][0]-2:
parts[i] = (parts[i][0]-1, parts[i][1])
elif prevy == parts[i][1]+2:
parts[i] = (parts[i][0], parts[i][1]+1)
elif prevy == parts[i][1]-2:
parts[i] = (parts[i][0], parts[i][1]-1)
if i == 9:
visited.add(parts[-1])
print_state(5, parts)
print('part2', len(visited))

2000
2022/day9.txt Normal file

File diff suppressed because it is too large Load diff

8
2022/day9test.txt Normal file
View file

@ -0,0 +1,8 @@
R 4
U 4
L 3
D 1
R 4
D 1
L 5
R 2

46
2022/lib/day.ex Normal file
View file

@ -0,0 +1,46 @@
defmodule AOC.Day do
defmacro __using__(opts) do
day = Keyword.get(opts, :day)
debug = Keyword.get(opts, :debug, false)
trim = Keyword.get(opts, :trim, true)
input_file = Keyword.get(opts, :input, nil)
quote do
def solve do
input =
AOC.Day.input_lines(unquote(day), unquote(trim), unquote(input_file))
|> parse_input()
if unquote(debug) do
IO.inspect(input)
end
part1_solution = part1(input)
IO.puts("Part 1: #{part1_solution}")
part2_solution = part2(input)
IO.puts("Part 2: #{part2_solution}")
end
end
end
def input_lines(day, trim, input_file) do
lines =
input_file_name(day, input_file)
|> File.stream!()
if trim do
Enum.map(lines, &String.trim/1)
else
lines
end
end
def input_file_name(day, input_file) do
if input_file do
Path.join([File.cwd!(), "inputs", "day#{day}_#{input_file}.txt"])
else
Path.join([File.cwd!(), "inputs", "day#{day}.txt"])
end
end
end

24
2022/lib/days/day1.ex Normal file
View file

@ -0,0 +1,24 @@
defmodule AOC.Day1 do
use AOC.Day, day: 1
def parse_input(lines) do
lines
|> Enum.chunk_by(&(&1 == ""))
|> Enum.reject(&(&1 == [""]))
|> Enum.map(fn l -> Enum.map(l, &String.to_integer/1) end)
end
def part1(input) do
input
|> Enum.map(&Enum.sum/1)
|> Enum.max()
end
def part2(input) do
input
|> Enum.map(&Enum.sum/1)
|> Enum.sort(:desc)
|> Enum.take(3)
|> Enum.sum()
end
end

93
2022/lib/days/day11.ex Normal file
View file

@ -0,0 +1,93 @@
defmodule AOC.Day11 do
use AOC.Day, day: 11
alias AOC.Day11.{MonkeyRegistry, Monkey}
def parse_input(lines) do
monkeys =
lines
|> Enum.chunk_by(&(&1 == ""))
|> Enum.reject(&(&1 == [""]))
|> Enum.map(&parse_monkey/1)
supermod =
monkeys
|> Enum.map(& &1.modulo)
|> Enum.reduce(&Kernel.*/2)
{:ok, _} = Registry.start_link(keys: :unique, name: MonkeyRegistry)
Enum.each(monkeys, fn %{id: id} = monkey ->
GenServer.start_link(Monkey, Map.put(monkey, :supermod, supermod),
name: {:via, Registry, {MonkeyRegistry, id}}
)
end)
Enum.count(monkeys)
end
def parse_monkey([
"Monkey " <> monkey_id,
"Starting items: " <> items,
"Operation: " <> operation,
"Test: divisible by " <> modulo,
"If true: throw to monkey " <> true_monkey_id,
"If false: throw to monkey " <> false_monkey_id
]) do
%{
id: monkey_id |> String.slice(0..-2) |> String.to_integer(),
items: items |> String.split(", ") |> Enum.map(&String.to_integer/1),
operation: parse_operation(operation),
modulo: String.to_integer(modulo),
true_monkey_id: String.to_integer(true_monkey_id),
false_monkey_id: String.to_integer(false_monkey_id)
}
end
def parse_operation(operation) do
["new", "=", lhs, op, rhs] = String.split(operation)
fn old ->
lhs = if lhs == "old", do: old, else: String.to_integer(lhs)
rhs = if rhs == "old", do: old, else: String.to_integer(rhs)
op =
case op do
"*" -> &Kernel.*/2
"+" -> &Kernel.+/2
end
op.(lhs, rhs)
end
end
def part1(monkey_count) do
# monkey_business(monkey_count, 20, false)
end
def part2(monkey_count) do
monkey_business(monkey_count, 10000, true)
end
def monkey_business(monkey_count, rounds, ridiculous) do
execute_rounds(monkey_count, rounds, ridiculous)
Enum.map(0..(monkey_count - 1), fn id ->
[{pid, _}] = Registry.lookup(MonkeyRegistry, id)
Monkey.get_activeness(pid)
end)
|> Enum.sort(:desc)
|> Enum.take(2)
|> Enum.reduce(&Kernel.*/2)
end
def execute_rounds(monkey_count, rounds, ridiculous) do
Enum.each(0..(rounds - 1), fn _ -> execute_round(monkey_count, ridiculous) end)
end
def execute_round(monkey_count, ridiculous) do
Enum.each(0..(monkey_count - 1), fn id ->
[{pid, _}] = Registry.lookup(MonkeyRegistry, id)
Monkey.execute_turn(pid, ridiculous)
end)
end
end

View file

@ -0,0 +1,63 @@
defmodule AOC.Day11.Monkey do
use GenServer
alias AOC.Day11.{MonkeyRegistry, Monkey}
@impl true
def init(state) do
{:ok, Map.put(state, :activeness, 0)}
end
def execute_turn(pid, ridiculous) do
GenServer.call(pid, {:execute_turn, ridiculous}, :infinity)
end
def throw(pid, item) do
GenServer.call(pid, {:throw, item})
end
def get_items(pid) do
GenServer.call(pid, :get_items)
end
def get_activeness(pid) do
GenServer.call(pid, :get_activeness)
end
@impl true
def handle_call(
{:execute_turn, ridiculous},
_from,
%{
items: items,
operation: operation,
modulo: modulo,
true_monkey_id: true_monkey_id,
false_monkey_id: false_monkey_id,
activeness: activeness,
supermod: supermod
} = state
) do
Enum.each(items, fn item ->
item = operation.(item)
item = if ridiculous, do: item, else: Integer.floor_div(item, 3)
item = Integer.mod(item, supermod)
recipient = if Integer.mod(item, modulo) == 0, do: true_monkey_id, else: false_monkey_id
[{pid, _}] = Registry.lookup(MonkeyRegistry, recipient)
Monkey.throw(pid, item)
end)
{:reply, :ok, %{state | items: [], activeness: activeness + length(items)}}
end
def handle_call({:throw, item}, _from, %{items: items} = state) do
{:reply, :ok, Map.put(state, :items, items ++ [item])}
end
def handle_call(:get_items, _from, %{items: items} = state) do
{:reply, items, state}
end
def handle_call(:get_activeness, _from, %{activeness: activeness} = state) do
{:reply, activeness, state}
end
end

67
2022/lib/days/day13.ex Normal file
View file

@ -0,0 +1,67 @@
defmodule AOC.Day13 do
use AOC.Day, day: 13
alias AOC.Day13.Packet
defmodule Packet do
def compare({p1, p2}) do
compare(p1, p2)
end
def compare([], []), do: :eq
def compare([], _l), do: :lt
def compare(_l, []), do: :gt
def compare(x, l) when is_number(x) and is_list(l), do: compare([x], l)
def compare(l, x) when is_number(x) and is_list(l), do: compare(l, [x])
def compare([h1 | tl1], [h2 | tl2]) do
case compare(h1, h2) do
:eq -> compare(tl1, tl2)
x -> x
end
end
def compare(x, y) when x < y, do: :lt
def compare(x, y) when x == y, do: :eq
def compare(x, y) when x > y, do: :gt
end
def parse_input(lines) do
lines
|> Enum.chunk_by(&(&1 == ""))
|> Enum.reject(&(&1 == [""]))
|> Enum.map(fn [p1, p2] ->
{parse_packet(p1), parse_packet(p2)}
end)
end
def parse_packet(packet) do
packet
|> String.to_charlist()
|> Code.string_to_quoted()
|> elem(1)
end
def part1(pairs) do
pairs
|> Enum.map(&Packet.compare/1)
|> Enum.with_index()
|> Enum.filter(&(elem(&1, 0) == :lt))
|> Enum.map(&elem(&1, 1))
|> Enum.map(&Kernel.+(&1, 1))
|> Enum.sum()
end
@divider_packets [[[2]], [[6]]]
def part2(pairs) do
pairs
|> Enum.flat_map(fn {p1, p2} -> [p1, p2] end)
|> Kernel.++(@divider_packets)
|> Enum.sort(Packet)
|> Enum.with_index()
|> Enum.filter(&(elem(&1, 0) in @divider_packets))
|> Enum.map(&elem(&1, 1))
|> Enum.map(&Kernel.+(&1, 1))
|> Enum.reduce(&Kernel.*/2)
end
end

81
2022/lib/days/day16.ex Normal file
View file

@ -0,0 +1,81 @@
defmodule AOC.Day16 do
use AOC.Day, day: 16, debug: true, input: "example"
alias AOC.Day16.{ValveRegistry, Valve}
defmodule Valve do
use GenServer
@impl true
def init(state) do
state = Map.put(state, :released, 0)
state = Map.put(state, :open?, false)
{:ok, state}
end
def get_rate(valve) do
GenServer.call(valve, :get_rate)
end
def tick(valve) do
GenServer.call(valve, :tick)
end
def open(valve) do
GenServer.call(valve, :open)
end
@impl true
def handle_call(:get_rate, _from, %{rate: rate} = state) do
{:reply, rate, state}
end
def handle_call(:tick, _from, %{open?: open?, released: released, rate: rate} = state) do
released = if open?, do: released + rate, else: released
{:reply, :ok, %{state | released: released}}
end
def handle_call(:open, _from, state) do
{:reply, :ok, %{state | open?: true}}
end
end
@line_regex ~r/Valve (?<name>[A-Z]{2}) has flow rate=(?<rate>\d+); tunnels? leads? to valves? (?<tunnels>.*)/
def parse_input(lines) do
{:ok, _} = Registry.start_link(keys: :unique, name: ValveRegistry)
lines
|> Enum.map(fn line ->
%{"name" => name, "rate" => rate, "tunnels" => tunnels} =
Regex.named_captures(@line_regex, line)
%{name: name, rate: String.to_integer(rate), tunnels: String.split(tunnels, ", ")}
end)
|> Enum.into(%{}, fn %{name: name} = valve ->
{:ok, pid} =
GenServer.start_link(Valve, valve, name: {:via, Registry, {ValveRegistry, name}})
{name, pid}
end)
end
def part1(valves) do
Enum.map(valves, fn {name, valve} ->
rate = Valve.get_rate(valve)
{name, rate}
end)
|> Enum.sort_by(&elem(&1, 1), :desc)
|> IO.inspect()
:ok
end
def tick(valves) do
Enum.each(valves, fn {_, valve} ->
Valve.tick(valve)
end)
end
def part2(_input) do
end
end

68
2022/lib/days/day2.ex Normal file
View file

@ -0,0 +1,68 @@
defmodule AOC.Day2 do
use AOC.Day, day: 2
def parse_input(lines) do
Enum.map(lines, fn line ->
[move1, move2] =
line
|> String.split(" ")
|> Enum.map(fn c ->
c
|> String.to_charlist()
|> hd()
end)
{move1, move2}
end)
end
def part1(input) do
input
|> Enum.map(fn {move1, move2} ->
score =
case move2 do
?X -> 1
?Y -> 2
?Z -> 3
end
score +
case {move1, move2} do
{?A, ?Y} -> 6
{?B, ?Z} -> 6
{?C, ?X} -> 6
{?A, ?X} -> 3
{?B, ?Y} -> 3
{?C, ?Z} -> 3
_ -> 0
end
end)
|> Enum.sum()
end
def part2(input) do
input
|> Enum.map(fn {move1, result} ->
score =
case result do
?X -> 0
?Y -> 3
?Z -> 6
end
score +
case {move1, result} do
{?A, ?X} -> 3
{?A, ?Y} -> 1
{?A, ?Z} -> 2
{?B, ?X} -> 1
{?B, ?Y} -> 2
{?B, ?Z} -> 3
{?C, ?X} -> 2
{?C, ?Y} -> 3
{?C, ?Z} -> 1
end
end)
|> Enum.sum()
end
end

39
2022/lib/days/day3.ex Normal file
View file

@ -0,0 +1,39 @@
defmodule AOC.Day3 do
use AOC.Day, day: 3
def parse_input(lines), do: lines
def part1(input) do
input
|> Enum.map(fn line ->
comp_size = line |> String.length() |> div(2)
{comp1, comp2} = line |> String.to_charlist() |> Enum.split(comp_size)
comp1 = MapSet.new(comp1)
comp2 = MapSet.new(comp2)
MapSet.intersection(comp1, comp2)
|> MapSet.to_list()
|> hd()
|> get_priority()
end)
|> Enum.sum()
end
def part2(input) do
input
|> Enum.chunk_every(3)
|> Enum.map(fn group ->
group
|> Enum.map(&String.to_charlist/1)
|> Enum.map(&MapSet.new/1)
|> Enum.reduce(&MapSet.intersection/2)
|> MapSet.to_list()
|> hd()
|> get_priority()
end)
|> Enum.sum()
end
def get_priority(char) when char >= ?a, do: char - 96
def get_priority(char), do: char - 38
end

38
2022/lib/days/day4.ex Normal file
View file

@ -0,0 +1,38 @@
defmodule AOC.Day4 do
use AOC.Day, day: 4
def parse_input(lines) do
Enum.map(lines, fn line ->
[assign1, assign2] =
line
|> String.split(",")
|> Enum.map(fn assign ->
[from, to] =
assign
|> String.split("-")
|> Enum.map(&String.to_integer/1)
MapSet.new(from..to)
end)
{assign1, assign2}
end)
end
def part1(input) do
input
|> Enum.map(fn {set1, set2} ->
MapSet.subset?(set1, set2) or MapSet.subset?(set2, set1)
end)
|> Enum.count(& &1)
end
def part2(input) do
input
|> Enum.map(fn {set1, set2} ->
MapSet.intersection(set1, set2)
|> Enum.any?()
end)
|> Enum.count(& &1)
end
end

70
2022/lib/days/day5.ex Normal file
View file

@ -0,0 +1,70 @@
defmodule AOC.Day5 do
use AOC.Day, day: 5, trim: false
def parse_input(lines) do
[init, ops] =
lines
|> Enum.chunk_by(&(&1 == "\n"))
|> Enum.reject(&(&1 == ["\n"]))
{parse_init(init), parse_ops(ops)}
end
def parse_init(init) do
init
|> Enum.split(-1)
|> elem(0)
|> Enum.map(fn line ->
line
|> String.to_charlist()
|> tl()
|> Enum.take_every(4)
end)
|> Enum.zip_with(&Function.identity/1)
|> Enum.map(fn stack ->
Enum.reject(stack, &(&1 == ?\s))
end)
end
def parse_ops(ops) do
Enum.map(ops, fn op ->
%{"count" => count, "from" => from, "to" => to} =
Regex.named_captures(~r/move (?<count>\d+) from (?<from>\d+) to (?<to>\d+)\n/, op)
%{
count: String.to_integer(count),
from: String.to_integer(from) - 1,
to: String.to_integer(to) - 1
}
end)
end
def part1(input) do
move(input, true)
end
def part2(input) do
move(input, false)
end
def move({init, ops}, reverse) do
ops
|> Enum.reduce(init, fn %{count: count, from: from, to: to}, acc ->
{acc, removed} = remove(acc, from, count)
removed = if reverse, do: Enum.reverse(removed), else: removed
add(acc, to, removed)
end)
|> Enum.map(&hd/1)
end
def remove(stacks, from, count) do
{removed, new} = Enum.split(Enum.at(stacks, from), count)
stacks = List.update_at(stacks, from, fn _ -> new end)
{stacks, removed}
end
def add(stacks, to, removed) do
added = Enum.concat(removed, Enum.at(stacks, to))
List.update_at(stacks, to, fn _ -> added end)
end
end

29
2022/lib/days/day6.ex Normal file
View file

@ -0,0 +1,29 @@
defmodule AOC.Day6 do
use AOC.Day, day: 6
def parse_input(lines), do: lines |> hd() |> String.to_charlist()
def part1(input) do
find_marker(input, 0, 4)
end
def part2(input) do
find_marker(input, 0, 14)
end
def find_marker(signal, index, length) do
distinct =
signal
|> Enum.take(length)
|> MapSet.new()
|> Enum.count()
if distinct == length do
index + length
else
signal
|> tl()
|> find_marker(index + 1, length)
end
end
end

82
2022/lib/days/day7.ex Normal file
View file

@ -0,0 +1,82 @@
defmodule AOC.Day7 do
use AOC.Day, day: 7
def parse_input(lines) do
Enum.map(lines, fn
"$ cd " <> arg ->
{:cd, arg}
"$ ls" ->
:ls
"dir " <> arg ->
{:dir, arg}
line ->
[size, file] = String.split(line)
{:file, String.to_integer(size), file}
end)
end
def part1(input) do
input
|> get_file_sizes()
|> get_directory_sizes()
|> Enum.map(fn {_, size} -> size end)
|> Enum.filter(&(&1 <= 100_000))
|> Enum.sum()
end
def part2(input) do
file_sizes = get_file_sizes(input)
total_size =
file_sizes
|> Enum.map(&elem(&1, 1))
|> Enum.sum()
size_needed = total_size - 40_000_000
file_sizes
|> get_directory_sizes()
|> Enum.map(&elem(&1, 1))
|> Enum.filter(fn size -> size >= size_needed end)
|> Enum.min()
end
def get_file_sizes(input) do
Enum.reduce(input, {[], []}, fn
{:cd, "/"}, {_, sizes} ->
{["/"], sizes}
{:cd, ".."}, {[_ | path], sizes} ->
{path, sizes}
{:cd, dir}, {path, sizes} ->
{[dir | path], sizes}
{:file, size, file}, {path, sizes} ->
{path, [{[file | path], size} | sizes]}
_, acc ->
acc
end)
|> elem(1)
end
def get_directory_sizes(file_sizes) do
file_sizes
|> Enum.reduce(%{}, fn {[_ | path], size}, acc ->
path = Enum.reverse(path)
update_directory_size(acc, size, path)
end)
end
def update_directory_size(sizes, file_size, file_path) do
Enum.reduce(file_path, {sizes, []}, fn dir, {sizes, cur_path} ->
cur_path = [dir | cur_path]
{Map.update(sizes, cur_path, file_size, &(&1 + file_size)), cur_path}
end)
|> elem(0)
end
end

53
2022/lib/days/day8.ex Normal file
View file

@ -0,0 +1,53 @@
defmodule AOC.Day8 do
use AOC.Day, day: 8, debug: true
def parse_input(lines) do
Enum.map(lines, fn line ->
line
|> String.split("", trim: true)
|> Enum.map(&String.to_integer/1)
end)
end
def part1(rows) do
rows = with_index(rows)
cols = Enum.zip(rows) |> Enum.map(&Tuple.to_list/1)
rrows = Enum.map(rows, &Enum.reverse/1)
rcols = Enum.map(cols, &Enum.reverse/1)
[rows, cols, rrows, rcols]
|> Enum.map(&count_visible/1)
|> Enum.reduce(&MapSet.union/2)
|> Enum.count()
end
def part2(rows) do
rows
end
def with_index(rows) do
Enum.with_index(rows, fn row, y ->
Enum.with_index(row, fn el, x ->
%{height: el, x: x, y: y}
end)
end)
end
def count_visible(rows) do
rows
|> Enum.map(&count_visible_row/1)
|> Enum.map(&elem(&1, 0))
|> Enum.reduce(&MapSet.union/2)
end
def count_visible_row(row) do
Enum.reduce(row, {MapSet.new(), -1}, fn
%{height: h, x: x, y: y}, {trees, highest} when h > highest ->
{MapSet.put(trees, {x, y}), h}
_, acc ->
acc
end)
end
end

28
2022/mix.exs Normal file
View file

@ -0,0 +1,28 @@
defmodule Aoc2022.MixProject do
use Mix.Project
def project do
[
app: :aoc2022,
version: "0.1.0",
elixir: "~> 1.14",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end
end

3
README.md Normal file
View file

@ -0,0 +1,3 @@
# aoc
Collection of my Advent of Code solutions.