diff --git a/Advent of Code 2020.csproj b/Advent of Code 2020.csproj
new file mode 100644
index 0000000..ffb5507
--- /dev/null
+++ b/Advent of Code 2020.csproj
@@ -0,0 +1,68 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {D017CB45-4695-4C39-9312-9A1599E5EF7D}
+ Exe
+ Advent_of_Code_2020
+ Advent of Code 2020
+ v4.8
+ 512
+ true
+ true
+
+
+ true
+ bin\Debug\
+ DEBUG;TRACE
+ full
+ x64
+ none
+
+
+ bin\
+
+
+ true
+ none
+ x64
+ none
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Day1.cs b/Day1.cs
new file mode 100644
index 0000000..5764934
--- /dev/null
+++ b/Day1.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+class Day1 {
+ public static int Solution1() {
+ HashSet solutions = new HashSet();
+
+ foreach (int number in Array.ConvertAll(File.ReadAllLines("input1.txt"), int.Parse)) {
+ int other = 2020 - number;
+
+ if (solutions.Contains(number)) {
+ return other * number;
+ }
+ solutions.Add(other);
+ }
+
+ return -1;
+ }
+
+ public static int Solution2() {
+ Dictionary solutions = new Dictionary();
+ int[] numbers = Array.ConvertAll(File.ReadAllLines("input1.txt"), int.Parse);
+
+ foreach (int number1 in numbers) {
+ if (solutions.TryGetValue(number1, out int product)) {
+ return product * number1;
+ }
+
+ foreach (int number2 in numbers) {
+ if (number1 == number2) {
+ continue;
+ }
+
+ int sum = number1 + number2;
+ if (sum < 2020) {
+ solutions[2020 - sum] = number1 * number2;
+ }
+ }
+ }
+
+ return -1;
+ }
+}
diff --git a/Day10.cs b/Day10.cs
new file mode 100644
index 0000000..8d58fd7
--- /dev/null
+++ b/Day10.cs
@@ -0,0 +1,46 @@
+using System;
+using System.IO;
+
+class Day10 {
+ public static int Solution1() {
+ int[] adapters = Array.ConvertAll(File.ReadAllLines("input10.txt"), int.Parse);
+ Array.Sort(adapters);
+
+ int diff1 = adapters[0] == 1 ? 1 : 0;
+ int diff3 = adapters[0] == 3 ? 2 : 1;
+ for (int i = adapters.Length - 1; i > 0;) {
+ int diff = adapters[i--] - adapters[i];
+ if (diff == 1) {
+ diff1++;
+ } else if (diff == 3) {
+ diff3++;
+ }
+ }
+
+ return diff1 * diff3;
+ }
+
+ public static int Solution2() {
+ int[] adapters = Array.ConvertAll(File.ReadAllLines("input10.txt"), int.Parse);
+ Array.Sort(adapters);
+ long[] arrangements = new long[adapters.Length];
+
+ //Count the ways from each adapter to your phone
+ arrangements[arrangements.Length - 1] = 1;
+ arrangements[arrangements.Length - 2] = 1;
+ arrangements[arrangements.Length - 3] = 2;
+ for (int i = adapters.Length - 4; i >= 0; i--) {
+ arrangements[i] = arrangements[i + 1];
+
+ if (adapters[i + 2] - adapters[i] <= 3) {
+ arrangements[i] += arrangements[i + 2];
+ if (adapters[i + 3] - adapters[i] <= 3) {
+ arrangements[i] += arrangements[i + 3];
+ }
+ }
+ }
+
+ Console.WriteLine(arrangements[0] + arrangements[1] + arrangements[2]);
+ return 0;
+ }
+}
diff --git a/Day11.cs b/Day11.cs
new file mode 100644
index 0000000..ff0cd74
--- /dev/null
+++ b/Day11.cs
@@ -0,0 +1,192 @@
+using System.Collections.Generic;
+using System.IO;
+
+class Day11 {
+ public static int Solution1() {
+ string[] input = File.ReadAllLines("input11.txt");
+ int width = input[0].Length + 2;
+ int height = input.Length + 2;
+ int[] seats1 = new int[width * height];
+ for (int y = 0; y < input.Length; y++) {
+ int i = (y + 1) * width + 1;
+ for (int x = 0; x < input[0].Length; x++) {
+ if (input[y][x] == 'L') {
+ seats1[i + x] = 1;
+ }
+ }
+ }
+ int[] seats2 = (int[])seats1.Clone();
+
+ int[] offsets = new int[8] { -width - 1, -width, -width + 1, -1, 1, width - 1, width, width + 1 };
+ for (int round = 1;; round++) {
+ bool change = false;
+ int[] from = round % 2 == 0 ? seats1 : seats2;
+ int[] to = round % 2 == 0 ? seats2 : seats1;
+
+ for (int i = 0; i < seats1.Length; i++) {
+ if (from[i] == 1) {
+ int result = 2;
+ foreach (int offset in offsets) {
+ if (from[i + offset] == 2) {
+ result = 1;
+ break;
+ }
+ }
+ change = change || result == 2;
+ to[i] = result;
+ } else if (from[i] == 2) {
+ int count = 0;
+ foreach (int offset in offsets) {
+ if (from[i + offset] == 2) {
+ count++;
+ }
+ }
+ change = change || count >= 4;
+ to[i] = count >= 4 ? 1 : 2;
+ }
+ }
+
+ if (!change) {
+ int count = 0;
+ foreach (int seat in to) {
+ if (seat == 2) {
+ count++;
+ }
+ }
+ return count;
+ }
+ }
+ }
+
+ public static int Solution2() {
+ string[] map = File.ReadAllLines("input11.txt");
+ int width = map[0].Length;
+ int height = map.Length;
+
+ int count = 0;
+ int[,] indexMap = new int[map.Length, map[0].Length];
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ indexMap[y, x] = map[y][x] == 'L' ? count++ : -1;
+ }
+ }
+
+ int[][] adjacencyMap = new int[count][];
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ if (indexMap[y, x] == -1) {
+ continue;
+ }
+ List adjacent = new List(8);
+ //Top left
+ for (int y2 = y - 1, x2 = x - 1; y2 >= 0 && x2 >= 0; y2--, x2--) {
+ int i = indexMap[y2, x2];
+ if (i != -1) {
+ adjacent.Add(i);
+ break;
+ }
+ }
+ //Top
+ for (int y2 = y - 1; y2 >= 0; y2--) {
+ int i = indexMap[y2, x];
+ if (i != -1) {
+ adjacent.Add(i);
+ break;
+ }
+ }
+ //Top right
+ for (int y2 = y - 1, x2 = x + 1; y2 >= 0 && x2 < width; y2--, x2++) {
+ int i = indexMap[y2, x2];
+ if (i != -1) {
+ adjacent.Add(i);
+ break;
+ }
+ }
+ //Left
+ for (int x2 = x - 1; x2 >= 0; x2--) {
+ int i = indexMap[y, x2];
+ if (i != -1) {
+ adjacent.Add(i);
+ break;
+ }
+ }
+ //Right
+ for (int x2 = x + 1; x2 < width; x2++) {
+ int i = indexMap[y, x2];
+ if (i != -1) {
+ adjacent.Add(i);
+ break;
+ }
+ }
+ //Bottom left
+ for (int y2 = y + 1, x2 = x - 1; y2 < height && x2 >= 0; y2++, x2--) {
+ int i = indexMap[y2, x2];
+ if (i != -1) {
+ adjacent.Add(i);
+ break;
+ }
+ }
+ //Bottom
+ for (int y2 = y + 1; y2 < height; y2++) {
+ int i = indexMap[y2, x];
+ if (i != -1) {
+ adjacent.Add(i);
+ break;
+ }
+ }
+ //Bottom right
+ for (int y2 = y + 1, x2 = x + 1; y2 < height && x2 < width; y2++, x2++) {
+ int i = indexMap[y2, x2];
+ if (i != -1) {
+ adjacent.Add(i);
+ break;
+ }
+ }
+
+ adjacencyMap[indexMap[y, x]] = adjacent.ToArray();
+ }
+ }
+
+ bool[] seats1 = new bool[count];
+ bool[] seats2 = new bool[count];
+
+ for (int round = 1; ; round++) {
+ bool change = false;
+ bool[] from = round % 2 == 0 ? seats1 : seats2;
+ bool[] to = round % 2 == 0 ? seats2 : seats1;
+
+ for (int i = 0; i < seats1.Length; i++) {
+ if (from[i]) {
+ int seen = 0;
+ foreach (int adjacent in adjacencyMap[i]) {
+ if (from[adjacent]) {
+ seen++;
+ }
+ }
+ change = change || seen >= 5;
+ to[i] = seen < 5;
+ } else {
+ bool result = true;
+ foreach (int adjacent in adjacencyMap[i]) {
+ if (from[adjacent]) {
+ result = false;
+ break;
+ }
+ }
+ change = change || result;
+ to[i] = result;
+ }
+ }
+
+ if (!change) {
+ int total = 0;
+ foreach (bool seat in to) {
+ if (seat) {
+ total++;
+ }
+ }
+ return total;
+ }
+ }
+ }
+}
diff --git a/Day12.cs b/Day12.cs
new file mode 100644
index 0000000..7f167ac
--- /dev/null
+++ b/Day12.cs
@@ -0,0 +1,84 @@
+using System;
+using System.IO;
+
+class Day12 {
+ public static int Solution1() {
+ int x = 0;
+ int y = 0;
+ int rot = 0;
+
+ foreach (string line in File.ReadLines("input12.txt")) {
+ char action = line[0];
+ int amount = int.Parse(line.Substring(1));
+
+ if (action == 'N') {
+ y += amount;
+ } else if (action == 'S') {
+ y -= amount;
+ } else if (action == 'E') {
+ x += amount;
+ } else if (action == 'W') {
+ x -= amount;
+ } else if (action == 'L') {
+ rot = (rot - amount / 90 + 4) % 4;
+ } else if (action == 'R') {
+ rot = (rot + amount / 90) % 4;
+ } else if (action == 'F') {
+ if (rot == 0) {
+ x += amount;
+ } else if (rot == 1) {
+ y -= amount;
+ } else if (rot == 2) {
+ x -= amount;
+ } else {
+ y += amount;
+ }
+ }
+ }
+
+ return Math.Abs(x) + Math.Abs(y);
+ }
+
+ public static int Solution2() {
+ int x = 10;
+ int y = 1;
+ int xPos = 0;
+ int yPos = 0;
+
+ foreach (string line in File.ReadLines("input12.txt")) {
+ char action = line[0];
+ int amount = int.Parse(line.Substring(1));
+
+ if (action == 'N') {
+ y += amount;
+ } else if (action == 'S') {
+ y -= amount;
+ } else if (action == 'E') {
+ x += amount;
+ } else if (action == 'W') {
+ x -= amount;
+ } else if (action == 'L') {
+ action = 'R';
+ amount = 360 - amount;
+ } if (action == 'R') {
+ if (amount == 90) {
+ int t = x;
+ x = y;
+ y = -t;
+ } else if (amount == 180) {
+ x = -x;
+ y = -y;
+ } else if (amount == 270) {
+ int t = x;
+ x = -y;
+ y = t;
+ }
+ } else if (action == 'F') {
+ xPos += x * amount;
+ yPos += y * amount;
+ }
+ }
+
+ return Math.Abs(xPos) + Math.Abs(yPos);
+ }
+}
diff --git a/Day13.cs b/Day13.cs
new file mode 100644
index 0000000..6581538
--- /dev/null
+++ b/Day13.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+class Day13 {
+ public static int Solution1() {
+ string[] input = File.ReadAllLines("input13.txt");
+ int target = int.Parse(input[0]);
+ int earliest = int.MaxValue;
+ int earliestId = -1;
+
+ foreach (string str in input[1].Split(',')) {
+ if (int.TryParse(str, out int id)) {
+ int time = (target / id + (target % id == 0 ? 0 : 1)) * id;
+ if (time < earliest) {
+ earliest = time;
+ earliestId = id;
+ }
+ }
+ }
+
+ return (earliest - target) * earliestId;
+ }
+
+ public static int Solution2() {
+ string[] input = File.ReadAllLines("input13.txt")[1].Split(',');
+ Dictionary ids = new Dictionary();
+ for (int i = 0; i < input.Length; i++) {
+ if (int.TryParse(input[i], out int id)) {
+ ids[id] = i % id;
+ }
+ }
+
+ long answer = 0;
+ long mult = 1;
+ foreach (KeyValuePair i in ids) {
+ int id = i.Key;
+ int offset = i.Value;
+
+ for (long x = answer + offset + mult; ; x += mult) {
+ if (x % id == 0) {
+ answer = x - offset;
+ break;
+ }
+ }
+
+ mult *= id;
+ }
+
+ Console.WriteLine(answer);
+ return 0;
+ }
+}
diff --git a/Day14.cs b/Day14.cs
new file mode 100644
index 0000000..196d41f
--- /dev/null
+++ b/Day14.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+class Day14 {
+ public static int Solution1() {
+ Dictionary memory = new Dictionary();
+ string mask = "";
+
+ foreach (string line in File.ReadLines("input14.txt")) {
+ string[] instruction = line.Split(new[] { " = " }, StringSplitOptions.None);
+ if (instruction[0] == "mask") {
+ mask = instruction[1];
+ } else {
+ long value = long.Parse(instruction[1]);
+ for (int i = 0; i < 36; i++) {
+ char bit = mask[i];
+ if (bit == '0') {
+ value &= 262144L * 262144L - 1 - (1L << (35 - i));
+ } else if (bit == '1') {
+ value |= 1L << (35 - i);
+ }
+ }
+ memory[int.Parse(instruction[0].Substring(4, instruction[0].Length - 5))] = value;
+ }
+ }
+
+ long sum = 0;
+ foreach (long value in memory.Values) {
+ sum += value;
+ }
+
+ Console.WriteLine(sum);
+ return 0;
+ }
+
+ public static int Solution2() {
+ Dictionary memory = new Dictionary();
+ string mask = "";
+
+ foreach (string line in File.ReadLines("input14.txt")) {
+ string[] instruction = line.Split(new[] { " = " }, StringSplitOptions.None);
+ if (instruction[0] == "mask") {
+ mask = instruction[1];
+ } else {
+ int value = int.Parse(instruction[1]);
+ int baseAddress = int.Parse(instruction[0].Substring(4, instruction[0].Length - 5));
+
+ void WriteToMemory(char[] address, int i) {
+ if (i == 36) {
+ memory[Convert.ToInt64(new string(address), 2)] = value;
+ return;
+ }
+
+ if (address[i] == 'X') {
+ address[i] = '0';
+ WriteToMemory((char[])address.Clone(), i + 1);
+ address[i] = '1';
+ }
+ WriteToMemory(address, i + 1);
+ }
+
+ char[] masterAddress = mask.ToCharArray();
+ for (int i = 35; i >= 20; i--) {
+ if (masterAddress[i] == '0') {
+ masterAddress[i] = (char)(((baseAddress >> (35 - i)) & 1) + '0');
+ }
+ }
+
+ WriteToMemory(masterAddress, 0);
+ }
+ }
+
+ long sum = 0;
+ foreach (int value in memory.Values) {
+ sum += value;
+ }
+
+ Console.WriteLine(sum);
+ return 0;
+ }
+}
diff --git a/Day15.cs b/Day15.cs
new file mode 100644
index 0000000..744273c
--- /dev/null
+++ b/Day15.cs
@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+
+class Day15 {
+ static readonly int[] input = new[] { 20, 9, 11, 0, 1, 2 };
+
+ public static int Solution1() => Solution(2020);
+
+ public static int Solution2() => Solution(30000000);
+
+ static int Solution(int n) {
+ Dictionary numbers = new Dictionary();
+ for (int turn = 0; turn < input.Length;) {
+ numbers[input[turn++]] = (turn, turn);
+ }
+ int last = input[input.Length - 1];
+ (int penultimate, int ultimate) = numbers[last];
+
+ for (int turn = input.Length + 1; turn <= n; turn++) {
+ last = ultimate - penultimate;
+ penultimate = numbers.TryGetValue(last, out (int _, int value) ult) ? ult.value : turn;
+ ultimate = turn;
+ numbers[last] = (penultimate, ultimate);
+ }
+
+ return last;
+ }
+}
diff --git a/Day16.cs b/Day16.cs
new file mode 100644
index 0000000..b984112
--- /dev/null
+++ b/Day16.cs
@@ -0,0 +1,97 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+class Day16 {
+ public static int Solution1() {
+ string[] input = File.ReadAllText("input16.txt").Split(new[] { "\n\n" }, StringSplitOptions.None);
+
+ bool[] rules = new bool[1000];
+ foreach (string[] ranges in Array.ConvertAll(input[0].Split('\n'), rule => rule.Split(new[] { ": " }, StringSplitOptions.None)[1].Split(new[] { " or " }, StringSplitOptions.None))) {
+ foreach (string[] range in Array.ConvertAll(ranges, range => range.Split('-'))) {
+ int start = int.Parse(range[0]);
+ int end = int.Parse(range[1]);
+ for (int i = start; i <= end; i++) {
+ rules[i] = true;
+ }
+ }
+ }
+
+ int sum = 0;
+ foreach (int rule in Array.ConvertAll(input[2].Split(new[] { '\n' }, 2)[1].Split(new[] { '\n', ',' }, StringSplitOptions.RemoveEmptyEntries), int.Parse)) {
+ if (!rules[rule]) {
+ sum += rule;
+ }
+ }
+
+ return sum;
+ }
+
+ public static int Solution2() {
+ string[] input = File.ReadAllText("input16.txt").Split(new[] { "\n\n" }, StringSplitOptions.None);
+
+ Dictionary rules = new Dictionary();
+ foreach (string[] rule in Array.ConvertAll(input[0].Split('\n'), rule => rule.Split(new[] { ": " }, StringSplitOptions.None))) {
+ bool[] validValues = new bool[1000];
+ rules[rule[0]] = validValues;
+
+ foreach (string[] range in Array.ConvertAll(rule[1].Split(new[] { " or " }, StringSplitOptions.None), range => range.Split('-'))) {
+ int start = int.Parse(range[0]);
+ int end = int.Parse(range[1]);
+ for (int i = start; i <= end; i++) {
+ validValues[i] = true;
+ }
+ }
+ }
+
+ int[] myTicket = Array.ConvertAll(input[1].Split('\n')[1].Split(','), int.Parse);
+ List validTickets = new List { myTicket };
+ foreach (int[] ticket in Array.ConvertAll(input[2].Split(new[] { '\n' }, 2)[1].Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries), line => Array.ConvertAll(line.Split(','), int.Parse))) {
+ if (Array.TrueForAll(ticket, value => {
+ foreach (bool[] validValues in rules.Values) {
+ if (validValues[value]) {
+ return true;
+ }
+ }
+ return false;
+ })) {
+ validTickets.Add(ticket);
+ }
+ }
+
+ HashSet[] possibilities = new HashSet[validTickets[0].Length];
+ for (int i = 0; i < possibilities.Length; i++) {
+ possibilities[i] = new HashSet(rules.Keys);
+ }
+ foreach (int[] ticket in validTickets) {
+ for (int i = 0; i < ticket.Length; i++) {
+ foreach (KeyValuePair rule in rules) {
+ if (!rule.Value[ticket[i]]) {
+ possibilities[i].Remove(rule.Key);
+ }
+ }
+ }
+ }
+
+ Dictionary fieldNames = new Dictionary(20);
+ int[] order = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 };
+ Array.Sort(possibilities, order, Comparer>.Create((a, b) => a.Count - b.Count));
+ for (int i = 0; i < possibilities.Length; i++) {
+ HashSet.Enumerator enumerator = possibilities[i].GetEnumerator();
+ enumerator.MoveNext();
+ string name = enumerator.Current;
+ fieldNames[name] = order[i];
+ for (int j = i + 1; j < possibilities.Length; j++) {
+ possibilities[j].Remove(name);
+ }
+ }
+
+ long product = 1;
+ foreach (string field in new[] { "departure location", "departure station", "departure platform", "departure track", "departure date", "departure time" }) {
+ product *= myTicket[fieldNames[field]];
+ }
+
+ Console.WriteLine(product);
+ return 0;
+ }
+}
diff --git a/Day17.cs b/Day17.cs
new file mode 100644
index 0000000..5697416
--- /dev/null
+++ b/Day17.cs
@@ -0,0 +1,147 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+class Day17 {
+ //Speedup: Dictionary for getting new active squares - each square increments their neighbors (and decrements themselves)
+
+ public static int Solution1() {
+ HashSet active = new HashSet();
+ char[][] input = Array.ConvertAll(File.ReadAllLines("input17.txt"), line => line.ToCharArray());
+ for (int x = 0; x < input[0].Length; x++) {
+ for (int y = 0; y < input.Length; y++) {
+ if (input[y][x] == '#') {
+ active.Add(new Vector3(x, y, 0));
+ }
+ }
+ }
+
+ for (int i = 0; i < 6; i++) {
+ HashSet toCheck = new HashSet();
+ foreach (Vector3 coord in active) {
+ foreach (Vector3 neighbor in coord.GetAllNeighbors()) {
+ toCheck.Add(neighbor);
+ }
+ }
+
+ HashSet newActive = new HashSet();
+ foreach (Vector3 coord in toCheck) {
+ int count = 0;
+
+ foreach (Vector3 neighbor in coord.GetAllNeighbors()) {
+ if (active.Contains(neighbor)) {
+ count++;
+ if (count > 4) {
+ break;
+ }
+ }
+ }
+
+ if (count == 3 || count == 4 && active.Contains(coord)) {
+ newActive.Add(coord);
+ }
+ }
+
+ active = newActive;
+ }
+
+ return active.Count;
+ }
+
+ public static int Solution2() {
+ HashSet active = new HashSet();
+ char[][] input = Array.ConvertAll(File.ReadAllLines("input17.txt"), line => line.ToCharArray());
+ for (int x = 0; x < input[0].Length; x++) {
+ for (int y = 0; y < input.Length; y++) {
+ if (input[y][x] == '#') {
+ active.Add(new Vector4(x, y, 0, 0));
+ }
+ }
+ }
+
+ for (int i = 0; i < 6; i++) {
+ HashSet toCheck = new HashSet();
+ foreach (Vector4 coord in active) {
+ foreach (Vector4 neighbor in coord.GetAllNeighbors()) {
+ toCheck.Add(neighbor);
+ }
+ }
+
+ HashSet newActive = new HashSet();
+ foreach (Vector4 coord in toCheck) {
+ int count = 0;
+
+ foreach (Vector4 neighbor in coord.GetAllNeighbors()) {
+ if (active.Contains(neighbor)) {
+ count++;
+ if (count > 4) {
+ break;
+ }
+ }
+ }
+
+ if (count == 3 || count == 4 && active.Contains(coord)) {
+ newActive.Add(coord);
+ }
+ }
+
+ active = newActive;
+ }
+
+ return active.Count;
+ }
+
+ struct Vector3 {
+ public readonly int x, y, z;
+
+ public Vector3(int x, int y, int z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ public IEnumerable GetAllNeighbors() {
+ int xTo = x + 1;
+ int yTo = y + 1;
+ int zTo = z + 1;
+ for (int x = this.x - 1; x <= xTo; x++) {
+ for (int y = this.y - 1; y <= yTo; y++) {
+ for (int z = this.z - 1; z <= zTo; z++) {
+ yield return new Vector3(x, y, z);
+ }
+ }
+ }
+ }
+
+ public override int GetHashCode() => (x << 20) ^ (y << 10) ^ z;
+ }
+
+ struct Vector4 {
+ public readonly int x, y, z, w;
+
+ public Vector4(int x, int y, int z, int w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ public IEnumerable GetAllNeighbors() {
+ int xTo = x + 1;
+ int yTo = y + 1;
+ int zTo = z + 1;
+ int wTo = w + 1;
+ for (int x = this.x - 1; x <= xTo; x++) {
+ for (int y = this.y - 1; y <= yTo; y++) {
+ for (int z = this.z - 1; z <= zTo; z++) {
+ for (int w = this.w - 1; w <= wTo; w++) {
+ yield return new Vector4(x, y, z, w);
+ }
+ }
+ }
+ }
+ }
+
+ public override int GetHashCode() => (x << 24) ^ (y << 16) ^ (z << 8) ^ w;
+ }
+}
diff --git a/Day18.cs b/Day18.cs
new file mode 100644
index 0000000..830f4c6
--- /dev/null
+++ b/Day18.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+class Day18 {
+ public static int Solution1() {
+ long sum = 0;
+
+ foreach (string line in File.ReadLines("input18.txt")) {
+ Stack values = new Stack();
+ Stack operators = new Stack();
+
+ foreach (char c in line) {
+ switch (c) {
+ case ' ':
+ break;
+ case '(':
+ operators.Push(c);
+ break;
+ case ')':
+ char op;
+ while ((op = operators.Pop()) != '(') {
+ values.Push(Calc(values.Pop(), values.Pop(), op));
+ }
+ break;
+ case '+':
+ case '*':
+ if (operators.Count > 0 && operators.Peek() != '(') {
+ values.Push(Calc(values.Pop(), values.Pop(), operators.Pop()));
+ }
+ operators.Push(c);
+ break;
+ default:
+ values.Push(c - '0');
+ break;
+ }
+ }
+
+ while (operators.Count > 0) {
+ values.Push(Calc(values.Pop(), values.Pop(), operators.Pop()));
+ }
+ sum += values.Pop();
+ }
+
+ Console.WriteLine(sum);
+ return 0;
+ }
+
+ public static int Solution2() {
+ long sum = 0;
+
+ foreach (string line in File.ReadLines("input18.txt")) {
+ Stack values = new Stack();
+ Stack operators = new Stack();
+
+ foreach (char c in line) {
+ switch (c) {
+ case ' ':
+ break;
+ case '(':
+ operators.Push(c);
+ break;
+ case ')':
+ char op;
+ while ((op = operators.Pop()) != '(') {
+ values.Push(Calc(values.Pop(), values.Pop(), op));
+ }
+ break;
+ case '+':
+ if (operators.Count > 0 && operators.Peek() == '+') {
+ values.Push(Calc(values.Pop(), values.Pop(), operators.Pop()));
+ }
+ operators.Push(c);
+ break;
+ case '*':
+ while (operators.Count > 0 && operators.Peek() != '(') {
+ values.Push(Calc(values.Pop(), values.Pop(), operators.Pop()));
+ }
+ operators.Push(c);
+ break;
+ default:
+ values.Push(c - '0');
+ break;
+ }
+ }
+
+ while (operators.Count > 0) {
+ values.Push(Calc(values.Pop(), values.Pop(), operators.Pop()));
+ }
+ sum += values.Pop();
+ }
+
+ Console.WriteLine(sum);
+ return 0;
+ }
+
+ static long Calc(long a, long b, char op) => op == '+' ? a + b : a * b;
+}
diff --git a/Day19.cs b/Day19.cs
new file mode 100644
index 0000000..4d727e1
--- /dev/null
+++ b/Day19.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+class Day19 {
+ public static int Solution1() => Solution((rules, line) => rules[0].Contains(line));
+
+ public static int Solution2() => Solution((rules, line) => {
+ int Count(int rule) {
+ int count = 0;
+
+ while (true) {
+ bool matched = false;
+ foreach (string start in rules[rule]) {
+ if (line.StartsWith(start)) {
+ line = line.Substring(start.Length);
+ count++;
+ matched = true;
+ break;
+ }
+ }
+ if (!matched) {
+ return count;
+ }
+ }
+ }
+
+ int count42 = Count(42);
+ if (count42 < 2) {
+ return false;
+ }
+
+ int count31 = Count(31);
+ return count31 >= 1 && count42 > count31 && line.Length == 0;
+ });
+
+ static int Solution(Func>, string, bool> counter) {
+ string[] input = File.ReadAllText("input19.txt").Split(new[] { "\n\n" }, StringSplitOptions.None);
+
+ Dictionary rules = new Dictionary();
+ foreach (string[] rule in Array.ConvertAll(input[0].Split('\n'), rule => rule.Split(new[] { ": " }, StringSplitOptions.None))) {
+ rules[int.Parse(rule[0])] = rule[1] == "\"a\"" ? new[] { new int[] { -'a' } } : rule[1] == "\"b\"" ? new[] { new int[] { -'b' } } : Array.ConvertAll(rule[1].Split(new[] { " | " }, StringSplitOptions.None), result => Array.ConvertAll(result.Split(' '), int.Parse));
+ }
+
+ Dictionary> ruleResults = new Dictionary>();
+ HashSet GetResult(int rule) {
+ if (!ruleResults.TryGetValue(rule, out HashSet result)) {
+ result = new HashSet();
+ foreach (int[] option in rules[rule]) {
+ result.UnionWith(Array.ConvertAll(option, x => x < 0 ? new HashSet { new string((char)-x, 1) } : GetResult(x)).Aggregate(Combine));
+ }
+ ruleResults[rule] = result;
+ }
+ return result;
+ }
+
+ HashSet Combine(HashSet first, HashSet second) {
+ HashSet cartesian = new HashSet();
+
+ foreach (string a in first) {
+ foreach (string b in second) {
+ cartesian.Add(a + b);
+ }
+ }
+
+ return cartesian;
+ }
+
+ HashSet validWords = GetResult(0);
+
+ int count = 0;
+ foreach (string line in input[1].Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)) {
+ if (counter(ruleResults, line)) {
+ count++;
+ }
+ }
+
+ return count;
+ }
+}
diff --git a/Day2.cs b/Day2.cs
new file mode 100644
index 0000000..d40f933
--- /dev/null
+++ b/Day2.cs
@@ -0,0 +1,43 @@
+using System.Collections.Generic;
+using System.IO;
+
+class Day2 {
+ public static int Solution1() {
+ int answer = 0;
+ foreach ((int lowBound, int highBound, char c, string pass) in ReadInput()) {
+ int count = 0;
+ foreach (char letter in pass) {
+ if (letter == c) {
+ count++;
+ }
+ }
+
+ if (lowBound <= count && highBound >= count) {
+ answer++;
+ }
+ }
+
+ return answer;
+ }
+
+ public static int Solution2() {
+ int answer = 0;
+ foreach ((int index1, int index2, char c, string pass) in ReadInput()) {
+ if (pass[index1 - 1] == c != (pass[index2 - 1] == c)) {
+ answer++;
+ }
+ }
+
+ return answer;
+ }
+
+ static IEnumerable<(int, int, char, string)> ReadInput() {
+ foreach (string line in File.ReadLines("input2.txt")) {
+ string[] parts = line.Split(' ');
+ string[] bounds = parts[0].Split('-');
+ char c = parts[1][0];
+
+ yield return (int.Parse(bounds[0]), int.Parse(bounds[1]), c, parts[2]);
+ }
+ }
+}
diff --git a/Day20.cs b/Day20.cs
new file mode 100644
index 0000000..ee48833
--- /dev/null
+++ b/Day20.cs
@@ -0,0 +1,225 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+class Day20 {
+ public static int Solution1() {
+ (int id, int orientation)[,] tiles = FitTiles();
+ Console.WriteLine((long)tiles[0, 0].id * tiles[0, 11].id * tiles[11, 0].id * tiles[11, 11].id);
+ return 0;
+ }
+
+ public static int Solution2() {
+ bool[,] Rotate(bool[,] image, int amount) {
+ int height = image.GetLength(0);
+ int width = image.GetLength(1);
+ bool[,] newImage = new bool[amount == 2 ? height : width, amount == 2 ? width : height];
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ if (amount == 1) {
+ newImage[x, height - y - 1] = image[y, x];
+ } else if (amount == 2) {
+ newImage[height - y - 1, width - x - 1] = image[y, x];
+ } else if (amount == 3) {
+ newImage[width - x - 1, y] = image[y, x];
+ } else {
+ throw new ArgumentException("Wrong rotation", nameof(amount));
+ }
+ }
+ }
+
+ return newImage;
+ }
+
+ bool[,] Mirror(bool[,] image) {
+ int height = image.GetLength(0);
+ int width = image.GetLength(1);
+ bool[,] newImage = new bool[height, width];
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ newImage[y, width - x - 1] = image[y, x];
+ }
+ }
+
+ return newImage;
+ }
+
+ (int id, int orientation)[,] tileIDs = FitTiles();
+
+ Dictionary tiles = new Dictionary();
+ foreach (string[] lines in Array.ConvertAll(File.ReadAllText("input20.txt").Split(new[] { "\n\n" }, StringSplitOptions.RemoveEmptyEntries), tile => tile.Split('\n'))) {
+ bool[,] tile = new bool[8, 8];
+
+ for (int y = 0; y < 8; y++) {
+ for (int x = 0; x < 8; x++) {
+ tile[y, x] = lines[y + 2][x + 1] == '#';
+ }
+ }
+
+ tiles[int.Parse(lines[0].Substring(5, 4))] = tile;
+ }
+
+ bool[,] photo = new bool[8 * 12, 8 * 12];
+ for (int tileY = 0; tileY < 12; tileY++) {
+ for (int tileX = 0; tileX < 12; tileX++) {
+ (int id, int orientation) = tileIDs[tileY, tileX];
+ bool[,] tile = tiles[id];
+ if (orientation > 3) {
+ tile = Mirror(tile);
+ }
+ if (orientation % 4 != 0) {
+ tile = Rotate(tile, orientation % 4);
+ }
+
+ for (int y = 0; y < 8; y++) {
+ for (int x = 0; x < 8; x++) {
+ photo[tileY * 8 + y, tileX * 8 + x] = tile[y, x];
+ }
+ }
+ }
+ }
+
+ int FindSubImage(bool[,] subImage) {
+ bool[,] newImage = (bool[,])photo.Clone();
+ int height = subImage.GetLength(0);
+ int width = subImage.GetLength(1);
+
+ for (int y = 0; y < 8 * 12 - height; y++) {
+ for (int x = 0; x < 8 * 12 - width; x++) {
+ bool isMonster = true;
+ for (int yOffset = 0; yOffset < height; yOffset++) {
+ for (int xOffset = 0; xOffset < width; xOffset++) {
+ if (subImage[yOffset, xOffset] && !photo[y + yOffset, x + xOffset]) {
+ isMonster = false;
+ break;
+ }
+ }
+ if (!isMonster) {
+ break;
+ }
+ }
+
+ if (isMonster) {
+ for (int yOffset = 0; yOffset < height; yOffset++) {
+ for (int xOffset = 0; xOffset < width; xOffset++) {
+ if (subImage[yOffset, xOffset]) {
+ newImage[y + yOffset, x + xOffset] = false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ int count = 0;
+ foreach (bool square in newImage) {
+ if (square) {
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ bool[,] monster = new bool[3, 20] {
+ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false },
+ { true, false, false, false, false, true, true, false, false, false, false, true, true, false, false, false, false, true, true, true },
+ { false, true, false, false, true, false, false, true, false, false, true, false, false, true, false, false, true, false, false, false }
+ };
+
+ return Math.Min(FindSubImage(monster),
+ Math.Min(FindSubImage(Rotate(monster, 1)),
+ Math.Min(FindSubImage(Rotate(monster, 2)),
+ Math.Min(FindSubImage(Rotate(monster, 3)),
+ Math.Min(FindSubImage(Mirror(monster)),
+ Math.Min(FindSubImage(Rotate(Mirror(monster), 1)),
+ Math.Min(FindSubImage(Rotate(Mirror(monster), 2)),
+ FindSubImage(Rotate(Mirror(monster), 3)))))))));
+ }
+
+ static (int, int)[,] FitTiles() {
+ int Mirror(int x) =>
+ ((x & 1) << 9)
+ | ((x & 2) << 7)
+ | ((x & 4) << 5)
+ | ((x & 8) << 3)
+ | ((x & 16) << 1)
+ | ((x & 32) >> 1)
+ | ((x & 64) >> 3)
+ | ((x & 128) >> 5)
+ | ((x & 256) >> 7)
+ | ((x & 512) >> 9);
+
+ List> tiles = new List>();
+ foreach (string[] lines in Array.ConvertAll(File.ReadAllText("input20.txt").Split(new[] { "\n\n" }, StringSplitOptions.RemoveEmptyEntries), tile => tile.Split('\n'))) {
+ int[][] orientations = new int[8][];
+
+ int[] sides = new int[4];
+ for (int i = 0; i < 10; i++) {
+ if (lines[1][i] == '#') {
+ sides[0] |= 1 << i;
+ }
+ if (lines[i + 1][9] == '#') {
+ sides[1] |= 1 << i;
+ }
+ if (lines[10][i] == '#') {
+ sides[2] |= 512 >> i;
+ }
+ if (lines[i + 1][0] == '#') {
+ sides[3] |= 512 >> i;
+ }
+ }
+ orientations[0] = sides;
+ orientations[1] = new[] { sides[3], sides[0], sides[1], sides[2] };
+ orientations[2] = new[] { sides[2], sides[3], sides[0], sides[1] };
+ orientations[3] = new[] { sides[1], sides[2], sides[3], sides[0] };
+
+ sides = new[] { Mirror(sides[0]), Mirror(sides[3]), Mirror(sides[2]), Mirror(sides[1]) };
+ orientations[4] = sides;
+ orientations[5] = new[] { sides[3], sides[0], sides[1], sides[2] };
+ orientations[6] = new[] { sides[2], sides[3], sides[0], sides[1] };
+ orientations[7] = new[] { sides[1], sides[2], sides[3], sides[0] };
+
+ int[] sides2 = Array.ConvertAll(sides, Mirror);
+
+ tiles.Add(new KeyValuePair(int.Parse(lines[0].Substring(5, 4)), orientations));
+ }
+
+ HashSet placedTiles = new HashSet();
+ int[,][] image = new int[12, 12][];
+ (int, int)[,] imageTiles = new (int, int)[12, 12];
+ bool PlaceTile(int row, int col) {
+ if (row == 12) {
+ return true;
+ }
+
+ foreach (KeyValuePair tile in tiles) {
+ if (placedTiles.Contains(tile.Key)) {
+ continue;
+ }
+
+ for (int i = 0; i < 8; i++) {
+ int[] orientation = tile.Value[i];
+ if (row > 0 && image[row - 1, col][2] != Mirror(orientation[0]) || col > 0 && image[row, col - 1][1] != Mirror(orientation[3])) {
+ continue;
+ }
+
+ placedTiles.Add(tile.Key);
+ image[row, col] = orientation;
+ imageTiles[row, col] = (tile.Key, i);
+ if (PlaceTile(row + (col == 11 ? 1 : 0), (col + 1) % 12)) {
+ return true;
+ }
+ placedTiles.Remove(tile.Key);
+ }
+ }
+
+ return false;
+ }
+
+ PlaceTile(0, 0);
+ return imageTiles;
+ }
+}
diff --git a/Day21.cs b/Day21.cs
new file mode 100644
index 0000000..18d14be
--- /dev/null
+++ b/Day21.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+class Day21 {
+ public static int Solution1() {
+ Dictionary allIngredients = new Dictionary();
+ Dictionary> allergenMap = new Dictionary>();
+
+ foreach (string line in File.ReadLines("input21.txt")) {
+ int allergenIndex = line.IndexOf('(');
+ string[] allergens = line.Substring(allergenIndex + 10, line.Length - allergenIndex - 11).Split(new[] { ", " }, StringSplitOptions.None);
+ string[] ingredients = line.Substring(0, allergenIndex - 1).Split(' ');
+
+ foreach (string ingredient in ingredients) {
+ allIngredients[ingredient] = allIngredients.TryGetValue(ingredient, out int count) ? count + 1 : 1;
+ }
+
+ foreach (string allergen in allergens) {
+ if (allergenMap.TryGetValue(allergen, out HashSet possibilities)) {
+ possibilities.IntersectWith(ingredients);
+ } else {
+ allergenMap[allergen] = new HashSet(ingredients);
+ }
+ }
+ }
+
+ foreach (HashSet possibilities in allergenMap.Values) {
+ foreach (string possibility in possibilities) {
+ allIngredients.Remove(possibility);
+ }
+ }
+
+ int total = 0;
+ foreach (int amount in allIngredients.Values) {
+ total += amount;
+ }
+
+ return total;
+ }
+
+ public static int Solution2() {
+ Dictionary> allergenMap = new Dictionary>();
+
+ foreach (string line in File.ReadLines("input21.txt")) {
+ int allergenIndex = line.IndexOf('(');
+ string[] allergens = line.Substring(allergenIndex + 10, line.Length - allergenIndex - 11).Split(new[] { ", " }, StringSplitOptions.None);
+ string[] ingredients = line.Substring(0, allergenIndex - 1).Split(' ');
+
+ foreach (string allergen in allergens) {
+ if (allergenMap.TryGetValue(allergen, out HashSet possibilities)) {
+ possibilities.IntersectWith(ingredients);
+ } else {
+ allergenMap[allergen] = new HashSet(ingredients);
+ }
+ }
+ }
+
+ while (true) {
+ bool changed = false;
+ foreach (HashSet possibilities in allergenMap.Values) {
+ if (possibilities.Count == 1) {
+ foreach (HashSet other in allergenMap.Values) {
+ if (other.Count != 1) {
+ other.ExceptWith(possibilities);
+ changed = true;
+ }
+ }
+ }
+ }
+
+ if (!changed) {
+ break;
+ }
+ }
+
+ string[] finalAllergens = new string[allergenMap.Count];
+ allergenMap.Keys.CopyTo(finalAllergens, 0);
+ string[] finalIngredients = new string[allergenMap.Count];
+ for (int i = 0; i < finalAllergens.Length; i++) {
+ HashSet.Enumerator ingredient = allergenMap[finalAllergens[i]].GetEnumerator();
+ ingredient.MoveNext();
+ finalIngredients[i] = ingredient.Current;
+ }
+
+ Array.Sort(finalAllergens, finalIngredients);
+ Console.WriteLine(string.Join(",", finalIngredients));
+
+ return 0;
+ }
+}
diff --git a/Day22.cs b/Day22.cs
new file mode 100644
index 0000000..9bcaaff
--- /dev/null
+++ b/Day22.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+class Day22 {
+ public static int Solution1() {
+ GetDecks(out Queue deck1, out Queue deck2);
+
+ while (deck1.Count > 0 && deck2.Count > 0) {
+ int card1 = deck1.Dequeue();
+ int card2 = deck2.Dequeue();
+
+ if (card1 > card2) {
+ deck1.Enqueue(card1);
+ deck1.Enqueue(card2);
+ } else {
+ deck2.Enqueue(card2);
+ deck2.Enqueue(card1);
+ }
+ }
+
+ int sum = 0;
+ Queue winningDeck = deck1.Count > 0 ? deck1 : deck2;
+ while (winningDeck.Count > 0) {
+ sum += winningDeck.Count * winningDeck.Dequeue();
+ }
+
+ return sum;
+ }
+
+ public static int Solution2() {
+ GetDecks(out Queue deck1, out Queue deck2);
+ PlayGame(deck1, deck2);
+
+ int sum = 0;
+ Queue winningDeck = deck1.Count > 0 ? deck1 : deck2;
+ while (winningDeck.Count > 0) {
+ sum += winningDeck.Count * winningDeck.Dequeue();
+ }
+
+ return sum;
+ }
+
+ static void GetDecks(out Queue deck1, out Queue deck2) {
+ string[][] playerInputs = Array.ConvertAll(File.ReadAllText("input22.txt").Split(new[] { "\n\n" }, StringSplitOptions.None), input => input.Substring(10).Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries));
+ deck1 = new Queue(Array.ConvertAll(playerInputs[0], int.Parse));
+ deck2 = new Queue(Array.ConvertAll(playerInputs[1], int.Parse));
+ }
+
+ static bool PlayGame(Queue deck1, Queue deck2) {
+ HashSet stateMemory = new HashSet();
+
+ while (deck1.Count > 0 && deck2.Count > 0) {
+ if (!stateMemory.Add(new GameState(deck1.ToArray(), deck2.ToArray()))) {
+ return true;
+ }
+
+ int card1 = deck1.Dequeue();
+ int card2 = deck2.Dequeue();
+
+ bool winnerIs1 = deck1.Count >= card1 && deck2.Count >= card2 ? PlayGame(new Queue(deck1.Take(card1)), new Queue(deck2.Take(card2))) : card1 > card2;
+
+ if (winnerIs1) {
+ deck1.Enqueue(card1);
+ deck1.Enqueue(card2);
+ } else {
+ deck2.Enqueue(card2);
+ deck2.Enqueue(card1);
+ }
+ }
+
+ return deck1.Count > 0;
+ }
+
+ class GameState : IEquatable {
+ readonly int[] deck1, deck2;
+
+ public GameState(int[] deck1, int[] deck2) {
+ this.deck1 = deck1;
+ this.deck2 = deck2;
+ }
+
+ public override bool Equals(object other) => other is GameState state && Equals(state);
+ public bool Equals(GameState other) => deck1.Length == other.deck1.Length && deck1.SequenceEqual(other.deck1) && deck2.SequenceEqual(other.deck2);
+
+ public override int GetHashCode() {
+ int hash = deck1.Length;
+ for (int i = 0; i < deck1.Length; i++) {
+ hash ^= deck1[i] << (i % 30);
+ }
+ return hash;
+ }
+ }
+}
diff --git a/Day23.cs b/Day23.cs
new file mode 100644
index 0000000..5861ccc
--- /dev/null
+++ b/Day23.cs
@@ -0,0 +1,86 @@
+using System;
+
+class Day23 {
+ const string input = "198753462";
+
+ public static int Solution1() {
+ int[] cups = Array.ConvertAll(input.ToCharArray(), c => c - '0');
+ int[] carry = new int[4];
+
+ for (int i = 0; i < 100; i++) {
+ Array.Copy(cups, carry, 4);
+ int search = cups[0];
+ do {
+ search -= 1;
+ if (search == 0) {
+ search = 9;
+ }
+ } while (Array.Exists(carry, c => c == search));
+ int dst = Array.IndexOf(cups, search);
+ int count = dst - 3;
+ Array.Copy(cups, 4, cups, 0, count);
+ Array.Copy(carry, 1, cups, count, 3);
+ Array.Copy(cups, dst + 1, cups, dst, 8 - dst);
+ cups[8] = carry[0];
+ }
+
+ int answer = 0;
+ int start = Array.IndexOf(cups, 1);
+ for (int i = 1; i <= 8; i++) {
+ answer = answer * 10 + cups[(start + i) % 9];
+ }
+ return answer;
+ }
+
+ public static int Solution2() {
+ Node[] nodes = new Node[1000001];
+ for (int i = 1; i <= 1000000; i++) {
+ nodes[i] = new Node(i);
+ }
+
+ Node first = nodes[input[0] - '0'];
+ Node last = first;
+ for (int i = 1; i < 9; i++) {
+ last.next = nodes[input[i] - '0'];
+ last = last.next;
+ }
+ for (int i = 10; i <= 1000000; i++) {
+ last.next = nodes[i];
+ last = last.next;
+ }
+ last.next = first;
+
+ for (int i = 0; i < 10000000; i++) {
+ Node carryStart = first.next;
+ Node carryEnd = carryStart.next.next;
+
+ int dstVal = first.value;
+ do {
+ dstVal -= 1;
+ if (dstVal == 0) {
+ dstVal = 1000000;
+ }
+ } while (carryStart.value == dstVal || carryStart.next.value == dstVal || carryEnd.value == dstVal);
+ Node dst = nodes[dstVal];
+
+ Node dstNext = dst.next;
+ dst.next = carryStart;
+ first.next = carryEnd.next;
+ carryEnd.next = dstNext;
+
+ first = first.next;
+ }
+
+ Console.WriteLine((long)nodes[1].next.value * nodes[1].next.next.value);
+ return 0;
+ }
+
+ class Node {
+ public readonly T value;
+ public Node next;
+
+ public Node(T value) {
+ this.value = value;
+ }
+ }
+}
diff --git a/Day24.cs b/Day24.cs
new file mode 100644
index 0000000..542dfcd
--- /dev/null
+++ b/Day24.cs
@@ -0,0 +1,81 @@
+using System.Collections.Generic;
+using System.IO;
+
+class Day24 {
+ public static int Solution1() => GetTiles().Count;
+
+ public static int Solution2() {
+ IEnumerable<(int, int)> AdjacentTiles(int x, int y) {
+ yield return (x - 1, y);
+ yield return (x + 1, y);
+ yield return (x, y - 1);
+ yield return (x + 1, y - 1);
+ yield return (x - 1, y + 1);
+ yield return (x, y + 1);
+ }
+
+ HashSet<(int, int)> tiles = GetTiles();
+
+ for (int i = 0; i < 100; i++) {
+ HashSet<(int, int)> tilesToCheck = new HashSet<(int, int)>();
+ foreach ((int x, int y) in tiles) {
+ foreach ((int, int) tile in AdjacentTiles(x, y)) {
+ tilesToCheck.Add(tile);
+ }
+ }
+
+ HashSet<(int, int)> newTiles = new HashSet<(int, int)>();
+ foreach ((int x, int y) tile in tilesToCheck) {
+ int adjacentBlacks = 0;
+ foreach ((int, int) adjacent in AdjacentTiles(tile.x, tile.y)) {
+ if (tiles.Contains(adjacent)) {
+ adjacentBlacks++;
+ }
+ }
+ if (adjacentBlacks == 2 || tiles.Contains(tile) && adjacentBlacks == 1) {
+ newTiles.Add(tile);
+ }
+ }
+ tiles = newTiles;
+ }
+
+ return tiles.Count;
+ }
+
+ static HashSet<(int, int)> GetTiles() {
+ Dictionary<(int, int), bool> tiles = new Dictionary<(int, int), bool>();
+
+ foreach (string line in File.ReadLines("input24.txt")) {
+ int x = 0;
+ int y = 0;
+ for (int i = 0; i < line.Length; i++) {
+ if (line[i] == 'e') {
+ x++;
+ } else if (line[i] == 'w') {
+ x--;
+ } else if (line[i] == 'n') {
+ y++;
+ if (line[++i] == 'w') {
+ x--;
+ }
+ } else {
+ y--;
+ if (line[++i] == 'e') {
+ x++;
+ }
+ }
+ }
+
+ tiles[(x, y)] = !(tiles.TryGetValue((x, y), out bool isBlack) && isBlack);
+ }
+
+ HashSet<(int, int)> blackTiles = new HashSet<(int, int)>();
+ foreach (KeyValuePair<(int, int), bool> tile in tiles) {
+ if (tile.Value) {
+ blackTiles.Add(tile.Key);
+ }
+ }
+
+ return blackTiles;
+ }
+}
diff --git a/Day25.cs b/Day25.cs
new file mode 100644
index 0000000..8e510c1
--- /dev/null
+++ b/Day25.cs
@@ -0,0 +1,32 @@
+using System;
+using System.IO;
+
+class Day25 {
+ public static int Solution1() {
+ string[] keys = File.ReadAllLines("input25.txt");
+ int key1 = int.Parse(keys[0]);
+ int key2 = int.Parse(keys[1]);
+ int loopSize;
+
+ int value = 1;
+ int loops = 0;
+ while (true) {
+ loops++;
+ value = value * 7 % 20201227;
+ if (value == key2) {
+ loopSize = loops;
+ break;
+ }
+ }
+
+ long keyEnc = 1;
+ for (int i = 0; i < loopSize; i++) {
+ keyEnc = keyEnc * key1 % 20201227;
+ }
+
+ Console.WriteLine(keyEnc);
+ return 0;
+ }
+
+ public static int Solution2() => -1;
+}
diff --git a/Day3.cs b/Day3.cs
new file mode 100644
index 0000000..bdcca2b
--- /dev/null
+++ b/Day3.cs
@@ -0,0 +1,37 @@
+using System.Collections.Generic;
+using System.IO;
+
+class Day3 {
+ public static int Solution1() => Solution(File.ReadAllLines("input3.txt"), 3);
+
+ public static int Solution2() {
+ string[] map = File.ReadAllLines("input3.txt");
+
+ int answer = Solution(map, 1, 1);
+ foreach (int increment in new[] { 1, 3, 5, 7 }) {
+ answer *= Solution(map, increment);
+ }
+
+ return answer;
+ }
+
+ static int Solution(IEnumerable map, int increment, int alternate = 0) {
+ int pos = 0;
+ int answer = 0;
+
+ foreach (string line in map) {
+ if (alternate > 0) {
+ if (alternate++ % 2 == 0) {
+ continue;
+ }
+ }
+
+ if (line[pos] == '#') {
+ answer++;
+ }
+ pos = (pos + increment) % line.Length;
+ }
+
+ return answer;
+ }
+}
diff --git a/Day4.cs b/Day4.cs
new file mode 100644
index 0000000..4e3e797
--- /dev/null
+++ b/Day4.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+class Day4 {
+ static readonly Dictionary> requiredFields = new Dictionary> {
+ { "byr", value => int.TryParse(value, out int year) && year >= 1920 && year <= 2002 },
+ { "iyr", value => int.TryParse(value, out int year) && year >= 2010 && year <= 2020 },
+ { "eyr", value => int.TryParse(value, out int year) && year >= 2020 && year <= 2030 },
+ { "hgt", height => height.EndsWith("cm") && int.TryParse(height.Substring(0, height.Length - 2), out int value) && value >= 150 && value <= 193 || height.EndsWith("in") && int.TryParse(height.Substring(0, height.Length - 2), out value) && value >= 59 && value <= 76 },
+ { "hcl", color => color.Length == 7 && color.TrimEnd('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f') == "#" },
+ { "ecl", color => color == "amb" || color == "blu" || color == "brn" || color == "gry" || color == "grn" || color == "hzl" || color == "oth" },
+ { "pid", id => id.Length == 9 && int.TryParse(id, out _) }
+ };
+
+ public static int Solution1() => Solution((passport, fieldName) => passport.ContainsKey(fieldName));
+
+ public static int Solution2() => Solution((passport, fieldName) => passport.ContainsKey(fieldName) && requiredFields[fieldName](passport[fieldName]));
+
+ static int Solution(Func, string, bool> validate) {
+ int answer = 0;
+
+ foreach (string passport in File.ReadAllText("input4.txt").Split(new[] { "\n\n" }, StringSplitOptions.None)) {
+ Dictionary fields = new Dictionary();
+ foreach (string field in passport.Split(new[] { ' ', '\n' }, StringSplitOptions.RemoveEmptyEntries)) {
+ string[] keyValue = field.Split(':');
+ fields[keyValue[0]] = keyValue[1];
+ }
+
+ bool isValid = true;
+ foreach (string fieldName in requiredFields.Keys) {
+ if (!validate(fields, fieldName)) {
+ isValid = false;
+ break;
+ }
+ }
+
+ if (isValid) {
+ answer++;
+ }
+ }
+
+ return answer;
+ }
+}
diff --git a/Day5.cs b/Day5.cs
new file mode 100644
index 0000000..a1a5ddc
--- /dev/null
+++ b/Day5.cs
@@ -0,0 +1,53 @@
+using System.Collections.Generic;
+using System.IO;
+
+class Day5 {
+ public static int Solution1() {
+ int max = 0;
+
+ foreach (int id in GetIDs()) {
+ if (id > max) {
+ max = id;
+ }
+ }
+
+ return max;
+ }
+
+ public static int Solution2() {
+ int min = int.MaxValue;
+ int max = 0;
+ int sum = 0;
+
+ foreach (int id in GetIDs()) {
+ if (id > max) {
+ max = id;
+ } else if (id < min) {
+ min = id;
+ }
+ sum += id;
+ }
+
+ return (max + min) * (max - min + 1) / 2 - sum;
+ }
+
+ static IEnumerable GetIDs() {
+ foreach (string seat in File.ReadLines("input5.txt")) {
+ int id = 0;
+
+ for (int i = 0; i < 7; i++) {
+ if (seat[i] == 'B') {
+ id |= 1 << (9 - i);
+ }
+ }
+
+ for (int i = 7; i < 10; i++) {
+ if (seat[i] == 'R') {
+ id |= 1 << (9 - i);
+ }
+ }
+
+ yield return id;
+ }
+ }
+}
diff --git a/Day6.cs b/Day6.cs
new file mode 100644
index 0000000..de4b5f9
--- /dev/null
+++ b/Day6.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+class Day6 {
+ public static int Solution1() => Solution(new HashSet(), (answers, person) => answers.UnionWith(person));
+
+ public static int Solution2() => Solution(new HashSet("abcdefghijklmnopqrstuvwxyz"), (answers, person) => answers.IntersectWith(person));
+
+ static int Solution(HashSet startSet, Action, string> setOp) {
+ int answer = 0;
+
+ foreach (string group in File.ReadAllText("input6.txt").Split(new[] { "\n\n" }, StringSplitOptions.None)) {
+ HashSet answers = new HashSet(startSet);
+ foreach (string person in group.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)) {
+ setOp(answers, person);
+ }
+ answer += answers.Count;
+ }
+
+ return answer;
+ }
+}
diff --git a/Day7.cs b/Day7.cs
new file mode 100644
index 0000000..59a1d55
--- /dev/null
+++ b/Day7.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+class Day7 {
+ public static int Solution1() {
+ Dictionary rules = GetRules();
+ Dictionary> reverseRules = new Dictionary>();
+
+ foreach (KeyValuePair rule in rules) {
+ foreach ((string content, _) in rule.Value) {
+ if (reverseRules.TryGetValue(content, out List containers)) {
+ containers.Add(rule.Key);
+ } else {
+ reverseRules[content] = new List { rule.Key };
+ }
+ }
+ }
+
+ HashSet potentialContainers = new HashSet();
+ Stack checkStack = new Stack();
+ checkStack.Push("shiny gold");
+
+ while (checkStack.Count > 0) {
+ string bag = checkStack.Pop();
+ foreach (string container in reverseRules.TryGetValue(bag, out List containers) ? containers : (IEnumerable)new string[0]) {
+ if (potentialContainers.Add(container)) {
+ checkStack.Push(container);
+ }
+ }
+ }
+
+ return potentialContainers.Count;
+ }
+
+ public static int Solution2() {
+ Dictionary rules = GetRules();
+
+ int answer = 0;
+
+ Dictionary toCheck = new Dictionary { { "shiny gold", 1 } };
+ while (toCheck.Count > 0) {
+ Dictionary.Enumerator enumerator = toCheck.GetEnumerator();
+ enumerator.MoveNext();
+ string container = enumerator.Current.Key;
+ int containerCount = enumerator.Current.Value;
+ toCheck.Remove(container);
+
+ foreach ((string bag, int count) in rules[container]) {
+ int additionalCount = count * containerCount;
+ toCheck[bag] = additionalCount + (toCheck.TryGetValue(bag, out int currentCount) ? currentCount : 0);
+ answer += additionalCount;
+ }
+ }
+
+ return answer;
+ }
+
+ static Dictionary GetRules() {
+ Dictionary rules = new Dictionary();
+
+ foreach (string line in File.ReadLines("input7.txt")) {
+ string[] rule = line.Split(new[] { " bags contain " }, StringSplitOptions.None);
+
+ rules[rule[0]] = rule[1] == "no other bags." ? new (string, int)[0] : Array.ConvertAll(rule[1].Split(new[] { ", " }, StringSplitOptions.None), bag => {
+ string[] pieces = bag.Split(' ');
+ return ($"{pieces[1]} {pieces[2]}", int.Parse(pieces[0]));
+ });
+ }
+
+ return rules;
+ }
+}
diff --git a/Day8.cs b/Day8.cs
new file mode 100644
index 0000000..8d49a79
--- /dev/null
+++ b/Day8.cs
@@ -0,0 +1,88 @@
+using System;
+using System.IO;
+
+class Day8 {
+ enum OpCode {
+ nop,
+ acc,
+ jmp
+ }
+
+ public static int Solution1() {
+ LoadProgram(out OpCode[] opCodes, out int[] opValues);
+ return -Run(0, 0, opCodes, opValues, new bool[opCodes.Length], -1);
+ }
+
+ public static int Solution2() {
+ int acc = 0;
+ int ptr = 0;
+ LoadProgram(out OpCode[] opCodes, out int[] opValues);
+ bool[] visited = new bool[opCodes.Length];
+
+ while (true) {
+ if (opCodes[ptr] == OpCode.nop || opCodes[ptr] == OpCode.jmp) {
+ int result = Run(acc, ptr, opCodes, opValues, (bool[])visited.Clone(), ptr);
+ if (result >= 0) {
+ return result;
+ }
+ }
+
+ visited[ptr] = true;
+ switch (opCodes[ptr]) {
+ case OpCode.nop:
+ ptr++;
+ break;
+ case OpCode.acc:
+ acc += opValues[ptr];
+ ptr++;
+ break;
+ case OpCode.jmp:
+ ptr += opValues[ptr];
+ break;
+ }
+ }
+ }
+
+ static void LoadProgram(out OpCode[] opCodes, out int[] opValues) {
+ string[] input = File.ReadAllLines("input8.txt");
+ opCodes = new OpCode[input.Length];
+ opValues = new int[input.Length];
+
+ for (int i = 0; i < input.Length; i++) {
+ string[] command = input[i].Split(' ');
+ Enum.TryParse(command[0], out opCodes[i]);
+ opValues[i] = int.Parse(command[1]);
+ }
+ }
+
+ static int Run(int acc, int ptr, OpCode[] opCodes, int[] opValues, bool[] visited, int opSwap) {
+ if (opSwap >= 0) {
+ opCodes[opSwap] = 2 - opCodes[opSwap];
+ }
+
+ while (ptr < opCodes.Length) {
+ if (visited[ptr]) {
+ if (opSwap >= 0) {
+ opCodes[opSwap] = 2 - opCodes[opSwap];
+ }
+ return -acc;
+ }
+ visited[ptr] = true;
+
+ switch (opCodes[ptr]) {
+ case OpCode.nop:
+ ptr++;
+ break;
+ case OpCode.acc:
+ acc += opValues[ptr];
+ ptr++;
+ break;
+ case OpCode.jmp:
+ ptr += opValues[ptr];
+ break;
+ }
+ }
+
+ return acc;
+ }
+}
diff --git a/Day9.cs b/Day9.cs
new file mode 100644
index 0000000..d2dc965
--- /dev/null
+++ b/Day9.cs
@@ -0,0 +1,76 @@
+using System.Collections.Generic;
+using System.IO;
+
+class Day9 {
+ public static int Solution1() {
+ StreamReader input = File.OpenText("input9.txt");
+ Queue previous = new Queue(25);
+ Dictionary sums = new Dictionary();
+
+ for (int i = 0; i < 25; i++) {
+ int next = int.Parse(input.ReadLine());
+
+ foreach (int existing in previous) {
+ int sum = existing + next;
+ sums[sum] = sums.TryGetValue(sum, out int count) ? count + 1 : 1;
+ }
+
+ previous.Enqueue(next);
+ }
+
+ while (true) {
+ int next = int.Parse(input.ReadLine());
+ if (!sums.ContainsKey(next)) {
+ input.Close();
+ return next;
+ }
+
+ int first = previous.Dequeue();
+ foreach (int existing in previous) {
+ int sum = existing + next;
+ sums[sum] = sums.TryGetValue(sum, out int count) ? count + 1 : 1;
+
+ sum = first + existing;
+ count = sums[sum];
+ if (count > 1) {
+ sums[sum] = count - 1;
+ } else {
+ sums.Remove(sum);
+ }
+ }
+ previous.Enqueue(next);
+ }
+ }
+
+ public static int Solution2() {
+ const int target = 258585477;
+ Queue window = new Queue();
+ int sum = 0;
+
+ foreach (string line in File.ReadLines("input9.txt")) {
+ int n = int.Parse(line);
+ window.Enqueue(n);
+ sum += n;
+
+ while (sum > target) {
+ n = window.Dequeue();
+ sum -= n;
+ }
+
+ if (sum == target) {
+ int smallest = int.MaxValue;
+ int largest = int.MinValue;
+ foreach (int num in window) {
+ if (num > largest) {
+ largest = num;
+ } else if (num < smallest) {
+ smallest = num;
+ }
+ }
+ return smallest + largest;
+ }
+ }
+
+ return -1;
+ }
+}
diff --git a/Picker.cs b/Picker.cs
new file mode 100644
index 0000000..a276e34
--- /dev/null
+++ b/Picker.cs
@@ -0,0 +1,28 @@
+using System;
+
+class Picker {
+ static readonly Func[] solutions = new Func[] { Day1.Solution1, Day1.Solution2, Day2.Solution1, Day2.Solution2, Day3.Solution1, Day3.Solution2, Day4.Solution1, Day4.Solution2, Day5.Solution1, Day5.Solution2, Day6.Solution1, Day6.Solution2, Day7.Solution1, Day7.Solution2, Day8.Solution1, Day8.Solution2, Day9.Solution1, Day9.Solution2, Day10.Solution1, Day10.Solution2, Day11.Solution1, Day11.Solution2, Day12.Solution1, Day12.Solution2, Day13.Solution1, Day13.Solution2, Day14.Solution1, Day14.Solution2, Day15.Solution1, Day15.Solution2, Day16.Solution1, Day16.Solution2, Day17.Solution1, Day17.Solution2, Day18.Solution1, Day18.Solution2, Day19.Solution1, Day19.Solution2, Day20.Solution1, Day20.Solution2, Day21.Solution1, Day21.Solution2, Day22.Solution1, Day22.Solution2, Day23.Solution1, Day23.Solution2, Day24.Solution1, Day24.Solution2, Day25.Solution1, Day25.Solution2 };
+
+ static void Main(string[] args) {
+ int i;
+ if (args.Length > 0) {
+ i = int.Parse(args[0]);
+ } else {
+ Console.WriteLine("Enter day:");
+ i = int.Parse(Console.ReadLine());
+ }
+ i = (i - 1) * 2;
+
+ if (i < 0) {
+ foreach (Func solution in solutions) {
+ Console.WriteLine(solution());
+ }
+ return;
+ }
+
+ Console.WriteLine(solutions[i++]());
+ if (solutions.Length > i) {
+ Console.WriteLine(solutions[i]());
+ }
+ }
+}
\ No newline at end of file