From 8dfe876e6d3f550cd8fefa642350f62a013466a6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 16 Dec 2024 11:34:58 +0000 Subject: [PATCH] Update docs on Mon Dec 16 11:34:58 UTC 2024 --- 2015/1/index.html | 12 +-- 2015/10/index.html | 20 ++--- 2015/11/index.html | 24 +++--- 2015/12/index.html | 18 ++-- 2015/13/index.html | 30 +++---- 2015/14/index.html | 22 ++--- 2015/15/index.html | 26 +++--- 2015/16/index.html | 50 +++++------ 2015/17/index.html | 18 ++-- 2015/18/index.html | 32 +++---- 2015/19/index.html | 22 ++--- 2015/2/index.html | 14 +-- 2015/20/index.html | 10 +-- 2015/21/index.html | 24 +++--- 2015/22/index.html | 46 +++++----- 2015/23/index.html | 32 +++---- 2015/24/index.html | 22 ++--- 2015/25/index.html | 4 +- 2015/3/index.html | 18 ++-- 2015/4/index.html | 18 ++-- 2015/5/index.html | 24 +++--- 2015/6/index.html | 26 +++--- 2015/7/index.html | 34 ++++---- 2015/8/index.html | 12 +-- 2015/9/index.html | 26 +++--- 2016/1/index.html | 16 ++-- 2016/10/index.html | 26 +++--- 2016/11/index.html | 112 ++++++++++++------------ 2016/12/index.html | 28 +++--- 2016/13/index.html | 20 ++--- 2016/14/index.html | 58 ++++++------- 2016/15/index.html | 16 ++-- 2016/16/index.html | 16 ++-- 2016/17/index.html | 34 ++++---- 2016/18/index.html | 30 +++---- 2016/19/index.html | 14 +-- 2016/2/index.html | 24 +++--- 2016/20/index.html | 18 ++-- 2016/21/index.html | 60 ++++++------- 2016/22/index.html | 38 ++++---- 2016/23/index.html | 58 ++++++------- 2016/24/index.html | 38 ++++---- 2016/25/index.html | 26 +++--- 2016/3/index.html | 26 +++--- 2016/4/index.html | 20 ++--- 2016/5/index.html | 30 +++---- 2016/6/index.html | 14 +-- 2016/7/index.html | 50 +++++------ 2016/8/index.html | 30 +++---- 2016/9/index.html | 10 +-- 2017/1/index.html | 6 +- 2017/10/index.html | 16 ++-- 2017/11/index.html | 24 +++--- 2017/12/index.html | 22 ++--- 2017/13/index.html | 18 ++-- 2017/14/index.html | 50 +++++------ 2017/15/index.html | 24 +++--- 2017/16/index.html | 36 ++++---- 2017/17/index.html | 8 +- 2017/18/index.html | 56 ++++++------ 2017/19/index.html | 20 ++--- 2017/2/index.html | 12 +-- 2017/20/index.html | 32 +++---- 2017/21/index.html | 76 ++++++++-------- 2017/22/index.html | 40 ++++----- 2017/23/index.html | 24 +++--- 2017/24/index.html | 20 ++--- 2017/25/index.html | 34 ++++---- 2017/3/index.html | 16 ++-- 2017/4/index.html | 16 ++-- 2017/5/index.html | 12 +-- 2017/6/index.html | 16 ++-- 2017/7/index.html | 30 +++---- 2017/8/index.html | 32 +++---- 2017/9/index.html | 22 ++--- 2018/1/index.html | 10 +-- 2018/10/index.html | 42 ++++----- 2018/11/index.html | 26 +++--- 2018/12/index.html | 32 +++---- 2018/13/index.html | 48 +++++------ 2018/14/index.html | 20 ++--- 2018/15/index.html | 94 ++++++++++---------- 2018/16/index.html | 72 ++++++++-------- 2018/17/index.html | 52 +++++------ 2018/18/index.html | 44 +++++----- 2018/19/index.html | 46 +++++----- 2018/2/index.html | 16 ++-- 2018/20/index.html | 36 ++++---- 2018/21/index.html | 54 ++++++------ 2018/22/index.html | 44 +++++----- 2018/23/index.html | 54 ++++++------ 2018/24/index.html | 62 ++++++------- 2018/25/index.html | 18 ++-- 2018/3/index.html | 26 +++--- 2018/4/index.html | 46 +++++----- 2018/5/index.html | 12 +-- 2018/6/index.html | 32 +++---- 2018/7/index.html | 28 +++--- 2018/8/index.html | 24 +++--- 2018/9/index.html | 16 ++-- 2019/1/index.html | 10 +-- 2019/10/index.html | 30 +++---- 2019/11/index.html | 32 +++---- 2019/12/index.html | 22 ++--- 2019/13/index.html | 12 +-- 2019/14/index.html | 32 +++---- 2019/15/index.html | 16 ++-- 2019/16/index.html | 26 +++--- 2019/17/index.html | 68 +++++++-------- 2019/18/index.html | 64 +++++++------- 2019/19/index.html | 8 +- 2019/2/index.html | 6 +- 2019/20/index.html | 34 ++++---- 2019/21/index.html | 32 +++---- 2019/22/index.html | 18 ++-- 2019/23/index.html | 28 +++--- 2019/24/index.html | 44 +++++----- 2019/25/index.html | 50 +++++------ 2019/3/index.html | 28 +++--- 2019/4/index.html | 18 ++-- 2019/5/index.html | 6 +- 2019/6/index.html | 20 ++--- 2019/7/index.html | 20 ++--- 2019/8/index.html | 26 +++--- 2019/9/index.html | 6 +- 2020/1/index.html | 6 +- 2020/10/index.html | 20 ++--- 2020/11/index.html | 26 +++--- 2020/12/index.html | 42 ++++----- 2020/13/index.html | 28 +++--- 2020/14/index.html | 44 +++++----- 2020/15/index.html | 12 +-- 2020/16/index.html | 34 ++++---- 2020/17/index.html | 24 +++--- 2020/18/index.html | 40 ++++----- 2020/19/index.html | 48 +++++------ 2020/2/index.html | 20 ++--- 2020/20/index.html | 90 +++++++++---------- 2020/21/index.html | 40 ++++----- 2020/22/index.html | 32 +++---- 2020/23/index.html | 18 ++-- 2020/24/index.html | 40 ++++----- 2020/25/index.html | 8 +- 2020/3/index.html | 12 +-- 2020/4/index.html | 40 ++++----- 2020/5/index.html | 20 ++--- 2020/6/index.html | 12 +-- 2020/7/index.html | 28 +++--- 2020/8/index.html | 38 ++++---- 2020/9/index.html | 14 +-- 2021/1/index.html | 16 ++-- 2021/10/index.html | 38 ++++---- 2021/11/index.html | 24 +++--- 2021/12/index.html | 26 +++--- 2021/13/index.html | 44 +++++----- 2021/14/index.html | 30 +++---- 2021/15/index.html | 36 ++++---- 2021/16/index.html | 42 ++++----- 2021/17/index.html | 20 ++--- 2021/18/index.html | 64 +++++++------- 2021/19/index.html | 44 +++++----- 2021/2/index.html | 30 +++---- 2021/20/index.html | 40 ++++----- 2021/21/index.html | 20 ++--- 2021/22/index.html | 28 +++--- 2021/23/index.html | 210 ++++++++++++++++++++++----------------------- 2021/24/index.html | 26 +++--- 2021/25/index.html | 42 ++++----- 2021/3/index.html | 34 ++++---- 2021/4/index.html | 38 ++++---- 2021/5/index.html | 16 ++-- 2021/6/index.html | 14 +-- 2021/7/index.html | 18 ++-- 2021/8/index.html | 38 ++++---- 2021/9/index.html | 30 +++---- 2022/1/index.html | 12 +-- 2022/10/index.html | 26 +++--- 2022/11/index.html | 54 ++++++------ 2022/12/index.html | 50 +++++------ 2022/13/index.html | 32 +++---- 2022/14/index.html | 30 +++---- 2022/15/index.html | 50 +++++------ 2022/16/index.html | 62 ++++++------- 2022/17/index.html | 68 +++++++-------- 2022/18/index.html | 46 +++++----- 2022/19/index.html | 60 ++++++------- 2022/2/index.html | 40 ++++----- 2022/20/index.html | 24 +++--- 2022/21/index.html | 64 +++++++------- 2022/22/index.html | 110 ++++++++++++------------ 2022/23/index.html | 36 ++++---- 2022/24/index.html | 44 +++++----- 2022/25/index.html | 32 +++---- 2022/3/index.html | 24 +++--- 2022/4/index.html | 26 +++--- 2022/5/index.html | 36 ++++---- 2022/6/index.html | 10 +-- 2022/7/index.html | 24 +++--- 2022/8/index.html | 24 +++--- 2022/9/index.html | 28 +++--- 2023/1/index.html | 36 ++++---- 2023/10/index.html | 50 +++++------ 2023/11/index.html | 26 +++--- 2023/12/index.html | 70 +++++++-------- 2023/13/index.html | 28 +++--- 2023/14/index.html | 54 ++++++------ 2023/15/index.html | 34 ++++---- 2023/16/index.html | 36 ++++---- 2023/17/index.html | 28 +++--- 2023/18/index.html | 48 +++++------ 2023/19/index.html | 64 +++++++------- 2023/2/index.html | 24 +++--- 2023/20/index.html | 52 +++++------ 2023/21/index.html | 20 ++--- 2023/22/index.html | 52 +++++------ 2023/23/index.html | 68 +++++++-------- 2023/24/index.html | 52 +++++------ 2023/25/index.html | 32 +++---- 2023/3/index.html | 30 +++---- 2023/4/index.html | 22 ++--- 2023/5/index.html | 46 +++++----- 2023/6/index.html | 18 ++-- 2023/7/index.html | 38 ++++---- 2023/8/index.html | 28 +++--- 2023/9/index.html | 28 +++--- 2024/1/index.html | 16 ++-- 2024/10/index.html | 26 +++--- 2024/11/index.html | 22 ++--- 2024/12/index.html | 32 +++---- 2024/13/index.html | 22 ++--- 2024/14/index.html | 36 ++++---- 2024/15/index.html | 68 +++++++-------- 2024/16/index.html | 34 ++++---- 2024/2/index.html | 20 ++--- 2024/3/index.html | 18 ++-- 2024/4/index.html | 16 ++-- 2024/5/index.html | 24 +++--- 2024/6/index.html | 28 +++--- 2024/7/index.html | 26 +++--- 2024/8/index.html | 22 ++--- 2024/9/index.html | 18 ++-- 241 files changed, 3898 insertions(+), 3898 deletions(-) diff --git a/2015/1/index.html b/2015/1/index.html index e234d6f7..8a3bd51b 100644 --- a/2015/1/index.html +++ b/2015/1/index.html @@ -284,17 +284,17 @@

Not Quite Lisp

namespace AdventOfCode.Y2015.Day01; -[ProblemName("Not Quite Lisp")] +[ProblemName("Not Quite Lisp")] class Solution : Solver { - public object PartOne(string input) => Levels(input).Last().level; + public object PartOne(string input) => Levels(input).Last().level; - public object PartTwo(string input) => Levels(input).First(p => p.level == -1).idx; + public object PartTwo(string input) => Levels(input).First(p => p.level == -1).idx; - IEnumerable<(int idx, int level)> Levels(string input){ + IEnumerable<(int idx, int level)> Levels(string input){ var level = 0; - for (var i = 0; i < input.Length; i++) { - level += input[i] == '(' ? 1 : -1; + for (var i = 0; i < input.Length; i++) { + level += input[i] == '(' ? 1 : -1; yield return (i+1, level); } } diff --git a/2015/10/index.html b/2015/10/index.html index 4303fcf3..4feb6935 100644 --- a/2015/10/index.html +++ b/2015/10/index.html @@ -285,27 +285,27 @@

Elves Look, Elves Say

namespace AdventOfCode.Y2015.Day10; -[ProblemName("Elves Look, Elves Say")] +[ProblemName("Elves Look, Elves Say")] class Solution : Solver { - public object PartOne(string input) => LookAndSay(input).Skip(39).First().Length; - public object PartTwo(string input) => LookAndSay(input).Skip(49).First().Length; + public object PartOne(string input) => LookAndSay(input).Skip(39).First().Length; + public object PartTwo(string input) => LookAndSay(input).Skip(49).First().Length; - IEnumerable LookAndSay(string input) { + IEnumerable<string> LookAndSay(string input) { while (true) { var sb = new StringBuilder(); var ich = 0; - while (ich < input.Length) { - if (ich < input.Length - 2 && input[ich] == input[ich + 1] && input[ich] == input[ich + 2]) { - sb.Append("3"); + while (ich < input.Length) { + if (ich < input.Length - 2 && input[ich] == input[ich + 1] && input[ich] == input[ich + 2]) { + sb.Append("3"); sb.Append(input[ich]); ich += 3; - } else if (ich < input.Length - 1 && input[ich] == input[ich + 1]) { - sb.Append("2"); + } else if (ich < input.Length - 1 && input[ich] == input[ich + 1]) { + sb.Append("2"); sb.Append(input[ich]); ich += 2; } else { - sb.Append("1"); + sb.Append("1"); sb.Append(input[ich]); ich += 1; } diff --git a/2015/11/index.html b/2015/11/index.html index d7b3f8e8..3c057340 100644 --- a/2015/11/index.html +++ b/2015/11/index.html @@ -285,27 +285,27 @@

Corporate Policy

namespace AdventOfCode.Y2015.Day11; -[ProblemName("Corporate Policy")] +[ProblemName("Corporate Policy")] class Solution : Solver { - public object PartOne(string input) => Passwords(input).First(); - public object PartTwo(string input) => Passwords(input).Skip(1).First(); + public object PartOne(string input) => Passwords(input).First(); + public object PartTwo(string input) => Passwords(input).Skip(1).First(); - IEnumerable Passwords(string pwd) => + IEnumerable<string> Passwords(string pwd) => from word in Words(pwd) - let straigth = Enumerable.Range(0, word.Length - 2).Any(i => word[i] == word[i + 1] - 1 && word[i] == word[i + 2] - 2) - let reserved = "iol".Any(ch => word.Contains(ch)) - let pairs = Enumerable.Range(0, word.Length - 1).Select(i => word.Substring(i, 2)).Where(sword => sword[0] == sword[1]).Distinct() - where straigth && !reserved && pairs.Count() > 1 + let straigth = Enumerable.Range(0, word.Length - 2).Any(i => word[i] == word[i + 1] - 1 && word[i] == word[i + 2] - 2) + let reserved = "iol".Any(ch => word.Contains(ch)) + let pairs = Enumerable.Range(0, word.Length - 1).Select(i => word.Substring(i, 2)).Where(sword => sword[0] == sword[1]).Distinct() + where straigth && !reserved && pairs.Count() > 1 select word; - IEnumerable Words(string word) { + IEnumerable<string> Words(string word) { while (true) { var sb = new StringBuilder(); - for (var i = word.Length - 1; i >= 0; i--) { + for (var i = word.Length - 1; i >= 0; i--) { var ch = word[i] + 1; - if (ch > 'z') { - ch = 'a'; + if (ch > 'z') { + ch = 'a'; sb.Insert(0, (char)ch); } else { sb.Insert(0, (char)ch); diff --git a/2015/12/index.html b/2015/12/index.html index 065d1cc7..9473470a 100644 --- a/2015/12/index.html +++ b/2015/12/index.html @@ -284,22 +284,22 @@

JSAbacusFramework.io

namespace AdventOfCode.Y2015.Day12; -[ProblemName("JSAbacusFramework.io")] +[ProblemName("JSAbacusFramework.io")] class Solution : Solver { - public object PartOne(string input) => Solve(input, false); - public object PartTwo(string input) => Solve(input, true); + public object PartOne(string input) => Solve(input, false); + public object PartTwo(string input) => Solve(input, true); int Solve(string input, bool skipRed) { int Traverse(JsonElement t) { return t.ValueKind switch { - JsonValueKind.Object when skipRed && t.EnumerateObject().Any( - p => p.Value.ValueKind == JsonValueKind.String && p.Value.GetString() == "red") => 0, - JsonValueKind.Object => t.EnumerateObject().Select(p => Traverse(p.Value)).Sum(), - JsonValueKind.Array => t.EnumerateArray().Select(Traverse).Sum(), - JsonValueKind.Number => t.GetInt32(), - _ => 0 + JsonValueKind.Object when skipRed && t.EnumerateObject().Any( + p => p.Value.ValueKind == JsonValueKind.String && p.Value.GetString() == "red") => 0, + JsonValueKind.Object => t.EnumerateObject().Select(p => Traverse(p.Value)).Sum(), + JsonValueKind.Array => t.EnumerateArray().Select(Traverse).Sum(), + JsonValueKind.Number => t.GetInt32(), + _ => 0 }; } diff --git a/2015/13/index.html b/2015/13/index.html index 2409a23b..938638b8 100644 --- a/2015/13/index.html +++ b/2015/13/index.html @@ -285,19 +285,19 @@

Knights of the Dinner Table

namespace AdventOfCode.Y2015.Day13; -[ProblemName("Knights of the Dinner Table")] +[ProblemName("Knights of the Dinner Table")] class Solution : Solver { - public object PartOne(string input) => Happiness(input, false).Max(); - public object PartTwo(string input) => Happiness(input, true).Max(); + public object PartOne(string input) => Happiness(input, false).Max(); + public object PartTwo(string input) => Happiness(input, true).Max(); - IEnumerable Happiness(string input, bool includeMe) { - var dh = new Dictionary<(string, string), int>(); - foreach (var line in input.Split('\n')) { - var m = Regex.Match(line, @"(.*) would (.*) (.*) happiness units by sitting next to (.*)."); + IEnumerable<int> Happiness(string input, bool includeMe) { + var dh = new Dictionary<(string, string), int>(); + foreach (var line in input.Split('\n')) { + var m = Regex.Match(line, @"(.*) would (.*) (.*) happiness units by sitting next to (.*)."); var a = m.Groups[1].Value; var b = m.Groups[4].Value; - var happiness = int.Parse(m.Groups[3].Value) * (m.Groups[2].Value == "gain" ? 1 : -1); + var happiness = int.Parse(m.Groups[3].Value) * (m.Groups[2].Value == "gain" ? 1 : -1); if (!dh.ContainsKey((a, b))) { dh[(a, b)] = 0; dh[(b, a)] = 0; @@ -306,23 +306,23 @@

Knights of the Dinner Table

dh[(b, a)] += happiness; } - var people = dh.Keys.Select(k => k.Item1).Distinct().ToList(); + var people = dh.Keys.Select(k => k.Item1).Distinct().ToList(); if (includeMe) { - people.Add("me"); + people.Add("me"); } - return Permutations(people.ToArray()).Select(order => - order.Zip(order.Skip(1).Append(order[0]), (a, b) => dh.TryGetValue((a, b), out var v) ? v : 0).Sum() + return Permutations(people.ToArray()).Select(order => + order.Zip(order.Skip(1).Append(order[0]), (a, b) => dh.TryGetValue((a, b), out var v) ? v : 0).Sum() ); } - IEnumerable Permutations(T[] rgt) { + IEnumerable<T[]> Permutations<T>(T[] rgt) { - IEnumerable PermutationsRec(int i) { + IEnumerable<T[]> PermutationsRec(int i) { if (i == rgt.Length) { yield return rgt.ToArray(); } - for (var j = i; j < rgt.Length; j++) { + for (var j = i; j < rgt.Length; j++) { (rgt[i], rgt[j]) = (rgt[j], rgt[i]); foreach (var perm in PermutationsRec(i + 1)) { yield return perm; diff --git a/2015/14/index.html b/2015/14/index.html index 8ad19f72..32642abc 100644 --- a/2015/14/index.html +++ b/2015/14/index.html @@ -285,17 +285,17 @@

Reindeer Olympics

namespace AdventOfCode.Y2015.Day14; -[ProblemName("Reindeer Olympics")] +[ProblemName("Reindeer Olympics")] class Solution : Solver { - public object PartOne(string input) => Race(Parse(input)).Skip(2502).First().Max(); - public object PartTwo(string input) => Race2(Parse(input)).Skip(2502).First().Max(); + public object PartOne(string input) => Race(Parse(input)).Skip(2502).First().Max(); + public object PartTwo(string input) => Race2(Parse(input)).Skip(2502).First().Max(); - IEnumerable[] Parse(string input) => input.Split('\n').Select(Reindeer).ToArray(); + IEnumerable<int>[] Parse(string input) => input.Split('\n').Select(Reindeer).ToArray(); - IEnumerable Race(IEnumerable[] reindeers) { + IEnumerable<int[]> Race(IEnumerable<int>[] reindeers) { var res = new int[reindeers.Length]; - var enumarators = reindeers.Select(r => r.GetEnumerator()).ToArray(); + var enumarators = reindeers.Select(r => r.GetEnumerator()).ToArray(); while (true) { yield return (from en in enumarators let _ = en.MoveNext() @@ -303,11 +303,11 @@

Reindeer Olympics

} } - IEnumerable Race2(IEnumerable[] reindeers) { + IEnumerable<int[]> Race2(IEnumerable<int>[] reindeers) { var points = new int[reindeers.Length]; foreach (var step in Race(reindeers)) { var m = step.Max(); - for (var i = 0; i < step.Length; i++) { + for (var i = 0; i < step.Length; i++) { if (step[i] == m) { points[i]++; } @@ -316,8 +316,8 @@

Reindeer Olympics

} } - IEnumerable Reindeer(string line) { - var m = Regex.Match(line, @"(.*) can fly (.*) km/s for (.*) seconds, but then must rest for (.*) seconds."); + IEnumerable<int> Reindeer(string line) { + var m = Regex.Match(line, @"(.*) can fly (.*) km/s for (.*) seconds, but then must rest for (.*) seconds."); var speed = int.Parse(m.Groups[2].Value); var flightTime = int.Parse(m.Groups[3].Value); var restTime = int.Parse(m.Groups[4].Value); @@ -329,7 +329,7 @@

Reindeer Olympics

dist += speed; } t++; - if ((flying && t == flightTime) || (!flying && t == restTime)) { + if ((flying && t == flightTime) || (!flying && t == restTime)) { t = 0; flying = !flying; } diff --git a/2015/15/index.html b/2015/15/index.html index 6880638f..3da5c20c 100644 --- a/2015/15/index.html +++ b/2015/15/index.html @@ -286,11 +286,11 @@

Science for Hungry People

namespace AdventOfCode.Y2015.Day15; -[ProblemName("Science for Hungry People")] +[ProblemName("Science for Hungry People")] class Solution : Solver { - public object PartOne(string input) => Solve(input, null); - public object PartTwo(string input) => Solve(input, 500); + public object PartOne(string input) => Solve(input, null); + public object PartTwo(string input) => Solve(input, 500); long Solve(string input, int? calories) { var ingredients = Parse(input); @@ -299,32 +299,32 @@

Science for Hungry People

var maxValue = 0L; foreach (var amounts in Partition(100, ingredients.Length)) { var props = new int[propsCount]; - for (int ingredient = 0; ingredient < ingredients.Length; ingredient++) { - for (int prop = 0; prop < 5; prop++) { + for (int ingredient = 0; ingredient < ingredients.Length; ingredient++) { + for (int prop = 0; prop < 5; prop++) { props[prop] += ingredients[ingredient][prop] * amounts[ingredient]; } } if (!calories.HasValue || calories.Value == props.Last()) { - var value = props.Take(propsCount - 1).Aggregate(1L, (acc, p) => acc * Math.Max(0, p)); + var value = props.Take(propsCount - 1).Aggregate(1L, (acc, p) => acc * Math.Max(0, p)); maxValue = Math.Max(maxValue, value); } } return maxValue; } - int[][] Parse(string input) => - (from line in input.Split('\n') - let m = Regex.Match(line, @".*: capacity (.*), durability (.*), flavor (.*), texture (.*), calories (.*)") - let nums = m.Groups.Cast().Skip(1).Select(g => int.Parse(g.Value)).ToArray() + int[][] Parse(string input) => + (from line in input.Split('\n') + let m = Regex.Match(line, @".*: capacity (.*), durability (.*), flavor (.*), texture (.*), calories (.*)") + let nums = m.Groups.Cast<Group>().Skip(1).Select(g => int.Parse(g.Value)).ToArray() select nums).ToArray(); - IEnumerable Partition(int n, int k) { + IEnumerable<int[]> Partition(int n, int k) { if (k == 1) { yield return new int[] { n }; } else { - for (var i = 0; i <= n; i++) { + for (var i = 0; i <= n; i++) { foreach (var rest in Partition(n - i, k - 1)) { - yield return rest.Select(x => x).Append(i).ToArray(); + yield return rest.Select(x => x).Append(i).ToArray(); } } } diff --git a/2015/16/index.html b/2015/16/index.html index c896dd4a..e87c068c 100644 --- a/2015/16/index.html +++ b/2015/16/index.html @@ -285,42 +285,42 @@

Aunt Sue

namespace AdventOfCode.Y2015.Day16; -[ProblemName("Aunt Sue")] +[ProblemName("Aunt Sue")] class Solution : Solver { - private Dictionary target = new Dictionary { - ["children"] = 3, - ["cats"] = 7, - ["samoyeds"] = 2, - ["pomeranians"] = 3, - ["akitas"] = 0, - ["vizslas"] = 0, - ["goldfish"] = 5, - ["trees"] = 3, - ["cars"] = 2, - ["perfumes"] = 1, + private Dictionary<string, int> target = new Dictionary<string, int> { + ["children"] = 3, + ["cats"] = 7, + ["samoyeds"] = 2, + ["pomeranians"] = 3, + ["akitas"] = 0, + ["vizslas"] = 0, + ["goldfish"] = 5, + ["trees"] = 3, + ["cars"] = 2, + ["perfumes"] = 1, }; - public object PartOne(string input) => - Parse(input).FindIndex(p => p.Keys.All(k => p[k] == target[k])) + 1; + public object PartOne(string input) => + Parse(input).FindIndex(p => p.Keys.All(k => p[k] == target[k])) + 1; - public object PartTwo(string input) => - Parse(input).FindIndex(p => p.Keys.All(k => { - if (k == "cats" || k == "trees") { - return p[k] > target[k]; - } else if (k == "pomeranians" || k == "goldfish") { - return p[k] < target[k]; + public object PartTwo(string input) => + Parse(input).FindIndex(p => p.Keys.All(k => { + if (k == "cats" || k == "trees") { + return p[k] > target[k]; + } else if (k == "pomeranians" || k == "goldfish") { + return p[k] < target[k]; } else { return p[k] == target[k]; } })) + 1; - List> Parse(string input) => ( - from line in input.Split('\n') - let parts = Regex.Matches(line, @"(\w+): (\d+)") + List<Dictionary<string, int>> Parse(string input) => ( + from line in input.Split('\n') + let parts = Regex.Matches(line, @"(\w+): (\d+)") select parts.ToDictionary( - part => part.Groups[1].Value, - part => int.Parse(part.Groups[2].Value)) + part => part.Groups[1].Value, + part => int.Parse(part.Groups[2].Value)) ).ToList(); } diff --git a/2015/17/index.html b/2015/17/index.html index 495b79dd..4619087a 100644 --- a/2015/17/index.html +++ b/2015/17/index.html @@ -285,27 +285,27 @@

No Such Thing as Too Much

namespace AdventOfCode.Y2015.Day17; -[ProblemName("No Such Thing as Too Much")] +[ProblemName("No Such Thing as Too Much")] class Solution : Solver { - public object PartOne(string input) => Fill(Parse(input)).Count(); + public object PartOne(string input) => Fill(Parse(input)).Count(); public object PartTwo(string input) { var combinations = Fill(Parse(input)).ToArray(); - var shortest = combinations.Select(combination => combination.Count()).Min(); - return combinations.Count(combination => combination.Count() == shortest); + var shortest = combinations.Select(combination => combination.Count()).Min(); + return combinations.Count(combination => combination.Count() == shortest); } - int[] Parse(string input) => input.Split('\n').Select(int.Parse).ToArray(); + int[] Parse(string input) => input.Split('\n').Select(int.Parse).ToArray(); - IEnumerable> Fill(int[] containers) { - IEnumerable> FillRecursive(int i, int amount) { + IEnumerable<ImmutableList<int>> Fill(int[] containers) { + IEnumerable<ImmutableList<int>> FillRecursive(int i, int amount) { if (i == containers.Length) { yield break; } else { if (amount == containers[i]) { - yield return ImmutableList.Create(i); + yield return ImmutableList.Create<int>(i); } - if (amount >= containers[i]) { + if (amount >= containers[i]) { foreach (var v in FillRecursive(i + 1, amount - containers[i])) { yield return v.Add(i); } diff --git a/2015/18/index.html b/2015/18/index.html index f87d61b1..708adba4 100644 --- a/2015/18/index.html +++ b/2015/18/index.html @@ -284,18 +284,18 @@

Like a GIF For Your Yard

namespace AdventOfCode.Y2015.Day18; -[ProblemName("Like a GIF For Your Yard")] +[ProblemName("Like a GIF For Your Yard")] class Solution : Solver { - public object PartOne(string input) => - Enumerable.Range(0, 100).Aggregate(Parse(input), (acc, _) => Step(acc, false)).Select(row => row.Sum()).Sum(); + public object PartOne(string input) => + Enumerable.Range(0, 100).Aggregate(Parse(input), (acc, _) => Step(acc, false)).Select(row => row.Sum()).Sum(); - public object PartTwo(string input) => - Enumerable.Range(0, 100).Aggregate(Parse(input), (acc, _) => Step(acc, true)).Select(row => row.Sum()).Sum(); + public object PartTwo(string input) => + Enumerable.Range(0, 100).Aggregate(Parse(input), (acc, _) => Step(acc, true)).Select(row => row.Sum()).Sum(); int[][] Step(int[][] input, bool stuck) { - var res = new List(); + var res = new List<int[]>(); var (crow, ccol) = (input.Length, input[0].Length); if (stuck) { @@ -304,12 +304,12 @@

Like a GIF For Your Yard

input[0][ccol - 1] = 1; input[crow - 1][ccol - 1] = 1; } - for (var irow = 0; irow < crow; irow++) { - var row = new List(); - for (var icol = 0; icol < ccol; icol++) { - if (stuck && - ((icol == 0 && irow == 0) || (icol == ccol - 1 && irow == 0) || - (icol == 0 && irow == crow - 1) || (icol == ccol - 1 && irow == crow - 1)) + for (var irow = 0; irow < crow; irow++) { + var row = new List<int>(); + for (var icol = 0; icol < ccol; icol++) { + if (stuck && + ((icol == 0 && irow == 0) || (icol == ccol - 1 && irow == 0) || + (icol == 0 && irow == crow - 1) || (icol == ccol - 1 && irow == crow - 1)) ) { row.Add(1); } else { @@ -317,7 +317,7 @@

Like a GIF For Your Yard

(from d in new(int row, int col)[] { (-1, -1), (0, -1), (1, -1), (-1, 0), (1, 0), (-1, 1), (0, 1), (1, 1) } let irowT = irow + d.row let icolT = icol + d.col - where irowT >= 0 && irowT < crow && icolT >= 0 && icolT < ccol && input[irowT][icolT] == 1 + where irowT >= 0 && irowT < crow && icolT >= 0 && icolT < ccol && input[irowT][icolT] == 1 select 1).Sum(); if (input[irow][icol] == 1) { row.Add(new[] { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }[neighbours]); @@ -331,10 +331,10 @@

Like a GIF For Your Yard

return res.ToArray(); } - int[][] Parse(string input) =>( - from line in input.Split('\n') + int[][] Parse(string input) =>( + from line in input.Split('\n') select - (from ch in line select ch == '#' ? 1 : 0).ToArray() + (from ch in line select ch == '#' ? 1 : 0).ToArray() ).ToArray(); } diff --git a/2015/19/index.html b/2015/19/index.html index c83a620f..0f9e5b20 100644 --- a/2015/19/index.html +++ b/2015/19/index.html @@ -285,7 +285,7 @@

Medicine for Rudolph

namespace AdventOfCode.Y2015.Day19; -[ProblemName("Medicine for Rudolph")] +[ProblemName("Medicine for Rudolph")] class Solution : Solver { public object PartOne(string input) { @@ -299,7 +299,7 @@

Medicine for Rudolph

var st = m; var depth = 0; var i = 0; - while (st != "e") { + while (st != "e") { i++; var replacements = Replacements(rules, st, false).ToArray(); if (replacements.Length == 0) { @@ -314,22 +314,22 @@

Medicine for Rudolph

return depth; } - IEnumerable ReplaceAll((string from, string to)[] rules, string m) { + IEnumerable<string> ReplaceAll((string from, string to)[] rules, string m) { foreach (var (from, length, to) in Replacements(rules, m, true)) { yield return Replace(m, from, to, length); } } - string Replace(string m, int from, string to, int length) => m.Substring(0, from) + to + m.Substring(from + length); + string Replace(string m, int from, string to, int length) => m.Substring(0, from) + to + m.Substring(from + length); - IEnumerable<(int from, int length, string to)> Replacements((string from, string to)[] rules, string m, bool forward) { + IEnumerable<(int from, int length, string to)> Replacements((string from, string to)[] rules, string m, bool forward) { var ich = 0; - while (ich < m.Length) { + while (ich < m.Length) { foreach (var (a, b) in rules) { var (from, to) = forward ? (a, b) : (b, a); - if (ich + from.Length <= m.Length) { + if (ich + from.Length <= m.Length) { var i = 0; - while (i < from.Length) { + while (i < from.Length) { if (m[ich + i] != from[i]) { break; } @@ -346,11 +346,11 @@

Medicine for Rudolph

((string from, string to)[] rules, string m) Parse(string input) { var rules = - (from line in input.Split('\n').TakeWhile(line => line.Contains("=>")) - let parts = line.Split(" => ") + (from line in input.Split('\n').TakeWhile(line => line.Contains("=>")) + let parts = line.Split(" => ") select (parts[0], parts[1])) .ToArray(); - var m = input.Split('\n').Last(); + var m = input.Split('\n').Last(); return (rules, m); } } diff --git a/2015/2/index.html b/2015/2/index.html index edb09442..a0abe24d 100644 --- a/2015/2/index.html +++ b/2015/2/index.html @@ -284,23 +284,23 @@

I Was Told There Would Be No Math

namespace AdventOfCode.Y2015.Day02; -[ProblemName("I Was Told There Would Be No Math")] +[ProblemName("I Was Told There Would Be No Math")] class Solution : Solver { - public object PartOne(string input) => ( + public object PartOne(string input) => ( from nums in Parse(input) select 2 * (nums[0] * nums[1] + nums[1] * nums[2] + nums[0] * nums[2]) + nums[0] * nums[1] ).Sum(); - public object PartTwo(string input) => ( + public object PartTwo(string input) => ( from nums in Parse(input) select nums[0] * nums[1] * nums[2] + 2 * (nums[0] + nums[1]) ).Sum(); - IEnumerable Parse(string input) { - return (from line in input.Split('\n') - let parts = line.Split('x') - let nums = parts.Select(int.Parse).OrderBy(x => x).ToArray() + IEnumerable<int[]> Parse(string input) { + return (from line in input.Split('\n') + let parts = line.Split('x') + let nums = parts.Select(int.Parse).OrderBy(x => x).ToArray() select nums); } } diff --git a/2015/20/index.html b/2015/20/index.html index 1cca717a..c9bef61b 100644 --- a/2015/20/index.html +++ b/2015/20/index.html @@ -281,7 +281,7 @@

Infinite Elves and Infinite Houses

namespace AdventOfCode.Y2015.Day20;
 
-[ProblemName("Infinite Elves and Infinite Houses")]
+[ProblemName("Infinite Elves and Infinite Houses")]
 class Solution : Solver {
 
     public object PartOne(string input) {
@@ -296,18 +296,18 @@ 

Infinite Elves and Infinite Houses

int PresentsByHouse(int steps, int mul, int l) { var presents = new int[1000000]; - for (var i = 1; i < presents.Length; i++) { + for (var i = 1; i < presents.Length; i++) { var j = i; var step = 0; - while (j < presents.Length && step < steps) { + while (j < presents.Length && step < steps) { presents[j] += mul * i; j += i; step++; } } - for (var i = 0; i < presents.Length; i++) { - if (presents[i] >= l) { + for (var i = 0; i < presents.Length; i++) { + if (presents[i] >= l) { return i; } } diff --git a/2015/21/index.html b/2015/21/index.html index 28fa8333..8a257558 100644 --- a/2015/21/index.html +++ b/2015/21/index.html @@ -285,7 +285,7 @@

RPG Simulator 20XX

namespace AdventOfCode.Y2015.Day21; -[ProblemName("RPG Simulator 20XX")] +[ProblemName("RPG Simulator 20XX")] class Solution : Solver { public object PartOne(string input) { @@ -311,28 +311,28 @@

RPG Simulator 20XX

} (int damage, int armor, int hp) Parse(string input) { - var lines = input.Split("\n"); - var hp = int.Parse(lines[0].Split(": ")[1]); - var damage = int.Parse(lines[1].Split(": ")[1]); - var armor = int.Parse(lines[2].Split(": ")[1]); + var lines = input.Split("\n"); + var hp = int.Parse(lines[0].Split(": ")[1]); + var damage = int.Parse(lines[1].Split(": ")[1]); + var armor = int.Parse(lines[2].Split(": ")[1]); return (damage, armor, hp); } bool DefeatsBoss((int damage, int armor, int hp) player, (int damage, int armor, int hp) boss) { while (true) { boss.hp -= Math.Max(player.damage - boss.armor, 1); - if (boss.hp <= 0) { + if (boss.hp <= 0) { return true; } player.hp -= Math.Max(boss.damage - player.armor, 1); - if (player.hp <= 0) { + if (player.hp <= 0) { return false; } } } - IEnumerable<(int gold, int damage, int armor)> Buy() { + IEnumerable<(int gold, int damage, int armor)> Buy() { return from weapon in Buy(1, 1, new[] { (8, 4, 0), (10, 5, 0), (25, 6, 0), (40, 7, 0), (74, 8, 0) }) from armor in Buy(0, 1, new[] { (13, 0, 1), (31, 0, 2), (53, 0, 3), (75, 0, 4), (102, 0, 5) }) @@ -340,7 +340,7 @@

RPG Simulator 20XX

select Sum(weapon, armor, ring); } - IEnumerable<(int gold, int damage, int armor)> Buy(int min, int max, (int gold, int damage, int armor)[] items) { + IEnumerable<(int gold, int damage, int armor)> Buy(int min, int max, (int gold, int damage, int armor)[] items) { if (min == 0) { yield return (0, 0, 0); } @@ -350,8 +350,8 @@

RPG Simulator 20XX

} if (max == 2) { - for (int i = 0; i < items.Length; i++) { - for (int j = i + 1; j < items.Length; j++) { + for (int i = 0; i < items.Length; i++) { + for (int j = i + 1; j < items.Length; j++) { yield return Sum(items[i], items[j]); } } @@ -359,7 +359,7 @@

RPG Simulator 20XX

} (int gold, int damage, int armor) Sum(params (int gold, int damage, int armor)[] items) { - return (items.Select(item => item.gold).Sum(), items.Select(item => item.damage).Sum(), items.Select(item => item.armor).Sum()); + return (items.Select(item => item.gold).Sum(), items.Select(item => item.damage).Sum(), items.Select(item => item.armor).Sum()); } } diff --git a/2015/22/index.html b/2015/22/index.html index 0eef45e9..41bf9b3e 100644 --- a/2015/22/index.html +++ b/2015/22/index.html @@ -284,29 +284,29 @@

Wizard Simulator 20XX

namespace AdventOfCode.Y2015.Day22; -[ProblemName("Wizard Simulator 20XX")] +[ProblemName("Wizard Simulator 20XX")] class Solution : Solver { public object PartOne(string input) { var state0 = Parse(input); - return BinarySearch(mana => TrySolve(state0.WithManaLimit(mana), false)); + return BinarySearch(mana => TrySolve(state0.WithManaLimit(mana), false)); } public object PartTwo(string input) { var state0 = Parse(input); - return BinarySearch(mana => TrySolve(state0.WithManaLimit(mana), true)); + return BinarySearch(mana => TrySolve(state0.WithManaLimit(mana), true)); } - int BinarySearch(Func f) { + int BinarySearch(Func<int, bool> f) { var hi = 1; while (!f(hi)) { hi *= 2; } var lo = hi / 2; var first = false; - while (hi - lo > 1) { + while (hi - lo > 1) { var m = (hi + lo) / 2; - if (!first && f(m)) { + if (!first && f(m)) { hi = m; } else { lo = m; @@ -324,7 +324,7 @@

Wizard Simulator 20XX

foreach (var stateT in state.PlayerSteps()) { state = stateT.ApplyEffects(); state = state.BossStep(); - if (state.bossHp <= 0 || state.playerHp > 0 && TrySolve(state, hard)) { + if (state.bossHp <= 0 || state.playerHp > 0 && TrySolve(state, hard)) { return true; } } @@ -332,12 +332,12 @@

Wizard Simulator 20XX

} State Parse(string input){ - var lines = input.Split("\n"); + var lines = input.Split("\n"); return new State { playerHp = 50, playerMana = 500, - bossHp = int.Parse(lines[0].Split(": ")[1]), - bossDamage = int.Parse(lines[1].Split(": ")[1]) + bossHp = int.Parse(lines[0].Split(": ")[1]), + bossDamage = int.Parse(lines[1].Split(": ")[1]) }; } } @@ -372,22 +372,22 @@

Wizard Simulator 20XX

} public State ApplyEffects() { - if (playerHp <= 0 || bossHp <= 0) { + if (playerHp <= 0 || bossHp <= 0) { return this; } var newState = Dup(); - if (newState.poison > 0) { + if (newState.poison > 0) { newState.bossHp -= 3; newState.poison--; } - if (newState.recharge > 0) { + if (newState.recharge > 0) { newState.playerMana += 101; newState.recharge--; } - if (newState.shield > 0) { + if (newState.shield > 0) { newState.shield--; newState.playerArmor = 7; } else { @@ -397,7 +397,7 @@

Wizard Simulator 20XX

} public State Damage(int damage) { - if (playerHp <= 0 || bossHp <= 0) { + if (playerHp <= 0 || bossHp <= 0) { return this; } @@ -407,7 +407,7 @@

Wizard Simulator 20XX

} public State BossStep(){ - if (playerHp <= 0 || bossHp <= 0) { + if (playerHp <= 0 || bossHp <= 0) { return this; } @@ -416,14 +416,14 @@

Wizard Simulator 20XX

return step; } - public IEnumerable PlayerSteps() { + public IEnumerable<State> PlayerSteps() { - if (playerHp <= 0 || bossHp <= 0) { + if (playerHp <= 0 || bossHp <= 0) { yield return this; yield break; } - if (playerMana >= missileMana && missileMana + usedMana <= manaLimit) { + if (playerMana >= missileMana && missileMana + usedMana <= manaLimit) { var c = Dup(); c.playerMana -= missileMana; c.usedMana += missileMana; @@ -431,7 +431,7 @@

Wizard Simulator 20XX

yield return c; } - if (playerMana >= drainMana && drainMana + usedMana <= manaLimit) { + if (playerMana >= drainMana && drainMana + usedMana <= manaLimit) { var c = Dup(); c.playerMana -= drainMana; c.usedMana += drainMana; @@ -440,7 +440,7 @@

Wizard Simulator 20XX

yield return c; } - if (playerMana >= shieldMana && shield == 0 && shieldMana + usedMana <= manaLimit) { + if (playerMana >= shieldMana && shield == 0 && shieldMana + usedMana <= manaLimit) { var c = Dup(); c.playerMana -= shieldMana; c.usedMana += shieldMana; @@ -448,7 +448,7 @@

Wizard Simulator 20XX

yield return c; } - if (playerMana >= poisonMana && poison == 0 && poisonMana + usedMana <= manaLimit) { + if (playerMana >= poisonMana && poison == 0 && poisonMana + usedMana <= manaLimit) { var c = Dup(); c.playerMana -= poisonMana; c.usedMana += poisonMana; @@ -456,7 +456,7 @@

Wizard Simulator 20XX

yield return c; } - if (playerMana >= rechargeMana && recharge == 0 && rechargeMana + usedMana <= manaLimit) { + if (playerMana >= rechargeMana && recharge == 0 && rechargeMana + usedMana <= manaLimit) { var c = Dup(); c.playerMana -= rechargeMana; c.usedMana += rechargeMana; diff --git a/2015/23/index.html b/2015/23/index.html index d443bffd..f3168b3e 100644 --- a/2015/23/index.html +++ b/2015/23/index.html @@ -284,14 +284,14 @@

Opening the Turing Lock

namespace AdventOfCode.Y2015.Day23; -[ProblemName("Opening the Turing Lock")] +[ProblemName("Opening the Turing Lock")] class Solution : Solver { - public object PartOne(string input) => Solve(input, 0); - public object PartTwo(string input) => Solve(input, 1); + public object PartOne(string input) => Solve(input, 0); + public object PartTwo(string input) => Solve(input, 1); long Solve(string input, long a) { - var regs = new Dictionary(); + var regs = new Dictionary<string, long>(); var ip = 0L; long getReg(string reg) { return long.TryParse(reg, out var n) ? n @@ -302,37 +302,37 @@

Opening the Turing Lock

regs[reg] = value; } - setReg("a", a); - var prog = input.Split('\n'); - while (ip >= 0 && ip < prog.Length) { + setReg("a", a); + var prog = input.Split('\n'); + while (ip >= 0 && ip < prog.Length) { var line = prog[ip]; - var parts = line.Replace(",", "").Split(" "); + var parts = line.Replace(",", "").Split(" "); switch (parts[0]) { - case "hlf": + case "hlf": setReg(parts[1], getReg(parts[1]) / 2); ip++; break; - case "tpl": + case "tpl": setReg(parts[1], getReg(parts[1]) * 3); ip++; break; - case "inc": + case "inc": setReg(parts[1], getReg(parts[1]) + 1); ip++; break; - case "jmp": + case "jmp": ip += getReg(parts[1]); break; - case "jie": + case "jie": ip += getReg(parts[1]) % 2 == 0 ? getReg(parts[2]) : 1; break; - case "jio": + case "jio": ip += getReg(parts[1]) == 1 ? getReg(parts[2]) : 1; break; - default: throw new Exception("Cannot parse " + line); + default: throw new Exception("Cannot parse " + line); } } - return getReg("b"); + return getReg("b"); } }
diff --git a/2015/24/index.html b/2015/24/index.html index afc8e80e..e4094eb8 100644 --- a/2015/24/index.html +++ b/2015/24/index.html @@ -286,20 +286,20 @@

It Hangs in the Balance

namespace AdventOfCode.Y2015.Day24; -[ProblemName("It Hangs in the Balance")] +[ProblemName("It Hangs in the Balance")] class Solution : Solver { - public object PartOne(string input) => Solve(Parse(input), 3); + public object PartOne(string input) => Solve(Parse(input), 3); - public object PartTwo(string input) => Solve(Parse(input), 4); + public object PartTwo(string input) => Solve(Parse(input), 4); - int[] Parse(string input) => - input.Split("\n").Select(int.Parse).ToArray(); + int[] Parse(string input) => + input.Split("\n").Select(int.Parse).ToArray(); long Solve(int[] nums, int groups) { - var mul = (ImmutableList l) => l.Aggregate(1L, (m, x) => m*x); + var mul = (ImmutableList<int> l) => l.Aggregate(1L, (m, x) => m*x); - for(var i =0;iIt Hangs in the Balance throw new Exception(); } - IEnumerable> Pick(int[] nums, int count, int i, int sum) { + IEnumerable<ImmutableList<int>> Pick(int[] nums, int count, int i, int sum) { if (sum == 0) { - yield return ImmutableList.Create(); + yield return ImmutableList.Create<int>(); yield break; } - if (count < 0 || sum < 0 || i >= nums.Length) { + if (count < 0 || sum < 0 || i >= nums.Length) { yield break; } - if (nums[i] <= sum) { + if (nums[i] <= sum) { foreach (var x in Pick(nums, count-1, i + 1, sum - nums[i])) { yield return x.Add(nums[i]); } diff --git a/2015/25/index.html b/2015/25/index.html index cc5a5725..9127ed4f 100644 --- a/2015/25/index.html +++ b/2015/25/index.html @@ -283,7 +283,7 @@

Let It Snow

namespace AdventOfCode.Y2015.Day25; -[ProblemName("Let It Snow")] +[ProblemName("Let It Snow")] class Solution : Solver { public object PartOne(string input) { @@ -303,7 +303,7 @@

Let It Snow

} (int irowDst, int icolDst) Parse(string input){ - var m = Regex.Match(input, @"To continue, please consult the code grid in the manual. Enter the code at row (\d+), column (\d+)."); + var m = Regex.Match(input, @"To continue, please consult the code grid in the manual. Enter the code at row (\d+), column (\d+)."); return (int.Parse(m.Groups[1].Value), int.Parse(m.Groups[2].Value)); } } diff --git a/2015/3/index.html b/2015/3/index.html index acf274cc..d9a854d9 100644 --- a/2015/3/index.html +++ b/2015/3/index.html @@ -284,18 +284,18 @@

Perfectly Spherical Houses in a Vacuum

namespace AdventOfCode.Y2015.Day03; -[ProblemName("Perfectly Spherical Houses in a Vacuum")] +[ProblemName("Perfectly Spherical Houses in a Vacuum")] class Solution : Solver { - public object PartOne(string input) => Run(input, 1); + public object PartOne(string input) => Run(input, 1); - public object PartTwo(string input) => Run(input, 2); + public object PartTwo(string input) => Run(input, 2); int Run(string input, int actors) { - var seen = new HashSet<(int, int)>(); + var seen = new HashSet<(int, int)>(); var pos = new(int irow, int icol)[actors]; - for (var i = 0; i < actors; i++) { + for (var i = 0; i < actors; i++) { pos[i] = (0, 0); } seen.Add((0,0)); @@ -303,10 +303,10 @@

Perfectly Spherical Houses in a Vacuum

var actor = 0; foreach (var ch in input) { switch (ch) { - case 'v': pos[actor].irow++; break; - case '<': pos[actor].icol--; break; - case '>': pos[actor].icol++; break; - case '^': pos[actor].irow--; break; + case 'v': pos[actor].irow++; break; + case '<': pos[actor].icol--; break; + case '>': pos[actor].icol++; break; + case '^': pos[actor].irow--; break; } seen.Add(pos[actor]); actor = (actor + 1) % actors; diff --git a/2015/4/index.html b/2015/4/index.html index ddcd7e8f..2b0af2be 100644 --- a/2015/4/index.html +++ b/2015/4/index.html @@ -288,21 +288,21 @@

The Ideal Stocking Stuffer

namespace AdventOfCode.Y2015.Day04; -[ProblemName("The Ideal Stocking Stuffer")] +[ProblemName("The Ideal Stocking Stuffer")] class Solution : Solver { - public object PartOne(string input) => ParallelFind(input, "00000"); - public object PartTwo(string input) => ParallelFind(input, "000000"); + public object PartOne(string input) => ParallelFind(input, "00000"); + public object PartTwo(string input) => ParallelFind(input, "000000"); int ParallelFind(string input, string prefix) { - var q = new ConcurrentQueue(); + var q = new ConcurrentQueue<int>(); Parallel.ForEach( Numbers(), - () => MD5.Create(), - (i, state, md5) => { + () => MD5.Create(), + (i, state, md5) => { var hashBytes = md5.ComputeHash(Encoding.ASCII.GetBytes(input + i)); - var hash = string.Join("", hashBytes.Select(b => b.ToString("x2"))); + var hash = string.Join("", hashBytes.Select(b => b.ToString("x2"))); if (hash.StartsWith(prefix)) { q.Enqueue(i); @@ -310,12 +310,12 @@

The Ideal Stocking Stuffer

} return md5; }, - (_) => {} + (_) => {} ); return q.Min(); } - IEnumerable Numbers() { + IEnumerable<int> Numbers() { for (int i=0; ;i++) { yield return i; } diff --git a/2015/5/index.html b/2015/5/index.html index 877a4120..efe22076 100644 --- a/2015/5/index.html +++ b/2015/5/index.html @@ -283,22 +283,22 @@

Doesn't He Have Intern-Elves For This?

namespace AdventOfCode.Y2015.Day05; -[ProblemName("Doesn't He Have Intern-Elves For This?")] +[ProblemName("Doesn't He Have Intern-Elves For This?")] class Solution : Solver { - public object PartOne(string input) => - input.Split('\n').Count(line => { - var threeVowels = line.Count(ch => "aeiou".Contains(ch)) >= 3; - var duplicate = Enumerable.Range(0, line.Length - 1).Any(i => line[i] == line[i + 1]); - var reserved = "ab,cd,pq,xy".Split(',').Any(line.Contains); - return threeVowels && duplicate && !reserved; + public object PartOne(string input) => + input.Split('\n').Count(line => { + var threeVowels = line.Count(ch => "aeiou".Contains(ch)) >= 3; + var duplicate = Enumerable.Range(0, line.Length - 1).Any(i => line[i] == line[i + 1]); + var reserved = "ab,cd,pq,xy".Split(',').Any(line.Contains); + return threeVowels && duplicate && !reserved; }); - public object PartTwo(string input) => - input.Split('\n').Count(line => { - var appearsTwice = Enumerable.Range(0, line.Length - 1).Any(i => line.IndexOf(line.Substring(i, 2), i+2) >= 0); - var repeats = Enumerable.Range(0, line.Length - 2).Any(i => line[i] == line[i + 2]); - return appearsTwice && repeats; + public object PartTwo(string input) => + input.Split('\n').Count(line => { + var appearsTwice = Enumerable.Range(0, line.Length - 1).Any(i => line.IndexOf(line.Substring(i, 2), i+2) >= 0); + var repeats = Enumerable.Range(0, line.Length - 2).Any(i => line[i] == line[i + 2]); + return appearsTwice && repeats; }); } diff --git a/2015/6/index.html b/2015/6/index.html index 08d262e2..e55f2b21 100644 --- a/2015/6/index.html +++ b/2015/6/index.html @@ -285,19 +285,19 @@

Probably a Fire Hazard

namespace AdventOfCode.Y2015.Day06; -[ProblemName("Probably a Fire Hazard")] +[ProblemName("Probably a Fire Hazard")] class Solution : Solver { - public object PartOne(string input) => Run(input, _ => 1, _ => 0, v => 1 - v); - public object PartTwo(string input) => Run(input, v => v + 1, v => v > 0 ? v - 1 : 0, v => v + 2); + public object PartOne(string input) => Run(input, _ => 1, _ => 0, v => 1 - v); + public object PartTwo(string input) => Run(input, v => v + 1, v => v > 0 ? v - 1 : 0, v => v + 2); - int Run(string input, Func turnOn, Func turnOff, Func toggle) { - int[] apply(int[] grid, string line, string pattern, Func dg) { + int Run(string input, Func<int, int> turnOn, Func<int, int> turnOff, Func<int, int> toggle) { + int[] apply(int[] grid, string line, string pattern, Func<int, int> dg) { var match = Regex.Match(line, pattern); if (match.Success) { - var rect = match.Groups.Cast().Skip(1).Select(g => int.Parse(g.Value)).ToArray(); - for (int irow = rect[0]; irow <= rect[2]; irow++) { - for (int icol = rect[1]; icol <= rect[3]; icol++) { + var rect = match.Groups.Cast<Group>().Skip(1).Select(g => int.Parse(g.Value)).ToArray(); + for (int irow = rect[0]; irow <= rect[2]; irow++) { + for (int icol = rect[1]; icol <= rect[3]; icol++) { grid[irow * 1000 + icol] = dg(grid[irow * 1000 + icol]); } } @@ -306,11 +306,11 @@

Probably a Fire Hazard

return null; } } - return input.Split('\n') - .Aggregate(new int[1000 * 1000], (grid, line) => - apply(grid, line, @"turn on (\d+),(\d+) through (\d+),(\d+)", turnOn) ?? - apply(grid, line, @"turn off (\d+),(\d+) through (\d+),(\d+)", turnOff) ?? - apply(grid, line, @"toggle (\d+),(\d+) through (\d+),(\d+)", toggle) ?? + return input.Split('\n') + .Aggregate(new int[1000 * 1000], (grid, line) => + apply(grid, line, @"turn on (\d+),(\d+) through (\d+),(\d+)", turnOn) ?? + apply(grid, line, @"turn off (\d+),(\d+) through (\d+),(\d+)", turnOff) ?? + apply(grid, line, @"toggle (\d+),(\d+) through (\d+),(\d+)", toggle) ?? throw new Exception(line)) .Sum(); } diff --git a/2015/7/index.html b/2015/7/index.html index ff6ac64a..e8400385 100644 --- a/2015/7/index.html +++ b/2015/7/index.html @@ -286,42 +286,42 @@

Some Assembly Required

namespace AdventOfCode.Y2015.Day07; -[ProblemName("Some Assembly Required")] +[ProblemName("Some Assembly Required")] class Solution : Solver { - class State : Dictionary { } - class Calc : Dictionary> { } + class State : Dictionary<string, int> { } + class Calc : Dictionary<string, Func<State, int>> { } - public object PartOne(string input) => Parse(input)["a"](new State()); + public object PartOne(string input) => Parse(input)["a"](new State()); public object PartTwo(string input) { var calc = Parse(input); - return calc["a"](new State() { ["b"] = calc["a"](new State()) }); + return calc["a"](new State() { ["b"] = calc["a"](new State()) }); } - Calc Parse(string input) => - input.Split('\n').Aggregate(new Calc(), (calc, line) => - Gate(calc, line, @"(\w+) AND (\w+) -> (\w+)", pin => pin[0] & pin[1]) ?? - Gate(calc, line, @"(\w+) OR (\w+) -> (\w+)", pin => pin[0] | pin[1]) ?? - Gate(calc, line, @"(\w+) RSHIFT (\w+) -> (\w+)", pin => pin[0] >> pin[1]) ?? - Gate(calc, line, @"(\w+) LSHIFT (\w+) -> (\w+)", pin => pin[0] << pin[1]) ?? - Gate(calc, line, @"NOT (\w+) -> (\w+)", pin => ~pin[0]) ?? - Gate(calc, line, @"(\w+) -> (\w+)", pin => pin[0]) ?? + Calc Parse(string input) => + input.Split('\n').Aggregate(new Calc(), (calc, line) => + Gate(calc, line, @"(\w+) AND (\w+) -> (\w+)", pin => pin[0] & pin[1]) ?? + Gate(calc, line, @"(\w+) OR (\w+) -> (\w+)", pin => pin[0] | pin[1]) ?? + Gate(calc, line, @"(\w+) RSHIFT (\w+) -> (\w+)", pin => pin[0] >> pin[1]) ?? + Gate(calc, line, @"(\w+) LSHIFT (\w+) -> (\w+)", pin => pin[0] << pin[1]) ?? + Gate(calc, line, @"NOT (\w+) -> (\w+)", pin => ~pin[0]) ?? + Gate(calc, line, @"(\w+) -> (\w+)", pin => pin[0]) ?? throw new Exception(line) ); - Calc Gate(Calc calc, string line, string pattern, Func op) { + Calc Gate(Calc calc, string line, string pattern, Func<int[], int> op) { var match = Regex.Match(line, pattern); if (!match.Success) { return null; } - var parts = match.Groups.Cast().Skip(1).Select(g => g.Value).ToArray(); + var parts = match.Groups.Cast<Group>().Skip(1).Select(g => g.Value).ToArray(); var pinOut = parts.Last(); var pins = parts.Take(parts.Length - 1).ToArray(); - calc[pinOut] = (state) => { + calc[pinOut] = (state) => { if (!state.ContainsKey(pinOut)) { - var args = pins.Select(pin => int.TryParse(pin, out var i) ? i : calc[pin](state)).ToArray(); + var args = pins.Select(pin => int.TryParse(pin, out var i) ? i : calc[pin](state)).ToArray(); state[pinOut] = op(args); } return state[pinOut]; diff --git a/2015/8/index.html b/2015/8/index.html index a60c39bc..d84c8df1 100644 --- a/2015/8/index.html +++ b/2015/8/index.html @@ -284,18 +284,18 @@

Matchsticks

namespace AdventOfCode.Y2015.Day08; -[ProblemName("Matchsticks")] +[ProblemName("Matchsticks")] class Solution : Solver { - public object PartOne(string input) => - (from line in input.Split('\n') + public object PartOne(string input) => + (from line in input.Split('\n') let u = Regex.Unescape(line.Substring(1, line.Length - 2)) select line.Length - u.Length).Sum(); - public object PartTwo(string input) => - (from line in input.Split('\n') - let u = "\"" + line.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"" + public object PartTwo(string input) => + (from line in input.Split('\n') + let u = "\"" + line.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"" select u.Length - line.Length).Sum(); } diff --git a/2015/9/index.html b/2015/9/index.html index 54c8ab32..9ca977a4 100644 --- a/2015/9/index.html +++ b/2015/9/index.html @@ -285,36 +285,36 @@

All in a Single Night

namespace AdventOfCode.Y2015.Day09; -[ProblemName("All in a Single Night")] +[ProblemName("All in a Single Night")] class Solution : Solver { - public object PartOne(string input) => Routes(input).Min(); - public object PartTwo(string input) => Routes(input).Max(); + public object PartOne(string input) => Routes(input).Min(); + public object PartTwo(string input) => Routes(input).Max(); - IEnumerable Routes(string input) { - var distances = input.Split('\n').SelectMany(line => { - var m = Regex.Match(line, @"(.*) to (.*) = (.*)"); + IEnumerable<int> Routes(string input) { + var distances = input.Split('\n').SelectMany(line => { + var m = Regex.Match(line, @"(.*) to (.*) = (.*)"); var (a, b) = (m.Groups[1].Value, m.Groups[2].Value); var d = int.Parse(m.Groups[3].Value); return new[] { (k: (a, b), d), (k: (b, a), d) }; - }).ToDictionary(p => p.k, p => p.d); + }).ToDictionary(p => p.k, p => p.d); - var cities = distances.Keys.Select(k => k.Item1).Distinct().ToArray(); - return Permutations(cities).Select(route => - route.Zip(route.Skip(1), (a, b) => distances[(a, b)]).Sum() + var cities = distances.Keys.Select(k => k.Item1).Distinct().ToArray(); + return Permutations(cities).Select(route => + route.Zip(route.Skip(1), (a, b) => distances[(a, b)]).Sum() ); } - IEnumerable Permutations(T[] rgt) { - IEnumerable PermutationsRec(int i) { + IEnumerable<T[]> Permutations<T>(T[] rgt) { + IEnumerable<T[]> PermutationsRec(int i) { if (i == rgt.Length) { yield return rgt.ToArray(); } - for (var j = i; j < rgt.Length; j++) { + for (var j = i; j < rgt.Length; j++) { (rgt[i], rgt[j]) = (rgt[j], rgt[i]); foreach (var perm in PermutationsRec(i + 1)) { yield return perm; diff --git a/2016/1/index.html b/2016/1/index.html index 56d63b79..a16c5e69 100644 --- a/2016/1/index.html +++ b/2016/1/index.html @@ -286,7 +286,7 @@

No Time for a Taxicab

namespace AdventOfCode.Y2016.Day01; -[ProblemName("No Time for a Taxicab")] +[ProblemName("No Time for a Taxicab")] class Solution : Solver { public object PartOne(string input) { @@ -295,7 +295,7 @@

No Time for a Taxicab

} public object PartTwo(string input) { - var seen = new HashSet<(int, int)>(); + var seen = new HashSet<(int, int)>(); foreach (var pos in Travel(input)) { if (seen.Contains(pos)) { return (pos.icol + pos.irow); @@ -305,21 +305,21 @@

No Time for a Taxicab

throw new Exception(); } - IEnumerable<(int irow, int icol)> Travel(string input) { + IEnumerable<(int irow, int icol)> Travel(string input) { var (irow, icol) = (0, 0); var (drow, dcol) = (-1, 0); yield return (irow, icol); - foreach (var stm in Regex.Split(input, ", ")) { + foreach (var stm in Regex.Split(input, ", ")) { var d = int.Parse(stm.Substring(1)); (drow, dcol) = stm[0] switch { - 'R' => (dcol, -drow), - 'L' => (-dcol, drow), - _ => throw new ArgumentException() + 'R' => (dcol, -drow), + 'L' => (-dcol, drow), + _ => throw new ArgumentException() }; - for (int i = 0; i < d; i++) { + for (int i = 0; i < d; i++) { (irow, icol) = (irow + drow, icol + dcol); yield return (irow, icol); } diff --git a/2016/10/index.html b/2016/10/index.html index 3962d81d..98260e79 100644 --- a/2016/10/index.html +++ b/2016/10/index.html @@ -286,23 +286,23 @@

Balance Bots

namespace AdventOfCode.Y2016.Day10; -[ProblemName("Balance Bots")] +[ProblemName("Balance Bots")] class Solution : Solver { - public object PartOne(string input) => - Execute(Parse(input)).Single(v => v.min == 17 && v.max == 61).id.Split(' ')[1]; + public object PartOne(string input) => + Execute(Parse(input)).Single(v => v.min == 17 && v.max == 61).id.Split(' ')[1]; public object PartTwo(string input) { var m = Execute(Parse(input)).Last().machine; - return m["output 0"].values.Single() * m["output 1"].values.Single() * m["output 2"].values.Single(); + return m["output 0"].values.Single() * m["output 1"].values.Single() * m["output 2"].values.Single(); } - IEnumerable<(Dictionary machine, string id, int min, int max)> Execute(Dictionary machine) { + IEnumerable<(Dictionary<string, Node> machine, string id, int min, int max)> Execute(Dictionary<string, Node> machine) { var any = true; while (any) { any = false; foreach (var node in machine.Values) { - if (node.values.Count == 2 && node.outHigh != null) { + if (node.values.Count == 2 && node.outHigh != null) { any = true; var (min, max) = (node.values.Min(), node.values.Max()); machine[node.outLow].values.Add(min); @@ -314,8 +314,8 @@

Balance Bots

} } - Dictionary Parse(string input) { - var res = new Dictionary(); + Dictionary<string, Node> Parse(string input) { + var res = new Dictionary<string, Node>(); void ensureNodes(params string[] ids) { foreach (var id in ids) { if (!res.ContainsKey(id)) { @@ -323,12 +323,12 @@

Balance Bots

} } } - foreach (var line in input.Split('\n')) { - if (Match(line, @"(.+) gives low to (.+) and high to (.+)", out var m)) { + foreach (var line in input.Split('\n')) { + if (Match(line, @"(.+) gives low to (.+) and high to (.+)", out var m)) { ensureNodes(m); res[m[0]].outLow = m[1]; res[m[0]].outHigh = m[2]; - } else if (Match(line, @"value (\d+) goes to (.+)", out m)) { + } else if (Match(line, @"value (\d+) goes to (.+)", out m)) { ensureNodes(m[1]); res[m[1]].values.Add(int.Parse(m[0])); } else { @@ -342,7 +342,7 @@

Balance Bots

var match = Regex.Match(stm, pattern); m = null; if (match.Success) { - m = match.Groups.Cast().Skip(1).Select(g => g.Value).ToArray(); + m = match.Groups.Cast<Group>().Skip(1).Select(g => g.Value).ToArray(); return true; } else { return false; @@ -352,7 +352,7 @@

Balance Bots

class Node { public string id; - public List values = new List(); + public List<int> values = new List<int>(); public string outLow; public string outHigh; } diff --git a/2016/11/index.html b/2016/11/index.html index bcaa6caf..03a26f48 100644 --- a/2016/11/index.html +++ b/2016/11/index.html @@ -297,19 +297,19 @@

Radioisotope Thermoelectric Generators

Dilithium = 0b1000000 } -[ProblemName("Radioisotope Thermoelectric Generators")] +[ProblemName("Radioisotope Thermoelectric Generators")] class Solution : Solver { - public object PartOne(string input) => Solve(Parse(input)); - public object PartTwo(string input) => Solve(Parse(input) + public object PartOne(string input) => Solve(Parse(input)); + public object PartTwo(string input) => Solve(Parse(input) .AddGenerator(0, Element.Elerium).AddChip(0, Element.Elerium) .AddGenerator(0, Element.Dilithium).AddChip(0, Element.Dilithium) ); int Solve(ulong state){ var steps = 0; - var seen = new HashSet(); - var q = new Queue<(int steps, ulong state)>(); + var seen = new HashSet<ulong>(); + var q = new Queue<(int steps, ulong state)>(); q.Enqueue((0, state)); while (q.Any()) { (steps, state) = q.Dequeue(); @@ -330,26 +330,26 @@

Radioisotope Thermoelectric Generators

ulong Parse(string input) { var nextMask = 1; - var elementToMask = new Dictionary(); + var elementToMask = new Dictionary<string, int>(); int mask(string element) { if (!elementToMask.ContainsKey(element)) { if (elementToMask.Count() == 5) { throw new NotImplementedException(); } elementToMask[element] = nextMask; - nextMask <<= 1; + nextMask <<= 1; } return elementToMask[element]; } ulong state = 0; var floor = 0; - foreach(var line in input.Split('\n')){ - var chips = (from m in Regex.Matches(line, @"(\w+)-compatible") + foreach(var line in input.Split('\n')){ + var chips = (from m in Regex.Matches(line, @"(\w+)-compatible") let element = m.Groups[1].Value select mask(element)).Sum(); - var generators = (from m in Regex.Matches(line, @"(\w+) generator") + var generators = (from m in Regex.Matches(line, @"(\w+) generator") let element = m.Groups[1].Value select mask(element)).Sum(); state = state.SetFloor((ulong)floor, (ulong)chips, (ulong)generators); @@ -377,62 +377,62 @@

Radioisotope Thermoelectric Generators

0b1100000000000000111111111111111111111111111111111111111111 }; - public static ulong SetFloor(this ulong state, ulong floor, ulong chips, ulong generators) => - (state & floorMask[floor]) | - (((chips << elementCount) | (generators << generatorShift)) << floorShift[floor]); + public static ulong SetFloor(this ulong state, ulong floor, ulong chips, ulong generators) => + (state & floorMask[floor]) | + (((chips << elementCount) | (generators << generatorShift)) << floorShift[floor]); - public static ulong GetElevator(this ulong state) => - (ulong)(state >> elevatorShift); + public static ulong GetElevator(this ulong state) => + (ulong)(state >> elevatorShift); - public static ulong SetElevator(this ulong state, ulong elevator) => - (state & elevatorMask) | ((ulong)elevator << elevatorShift); + public static ulong SetElevator(this ulong state, ulong elevator) => + (state & elevatorMask) | ((ulong)elevator << elevatorShift); - public static ulong GetChips(this ulong state, ulong floor) => - (ulong)(((state & ~floorMask[floor]) >> floorShift[floor]) & ~chipMask) >> elementCount; + public static ulong GetChips(this ulong state, ulong floor) => + (ulong)(((state & ~floorMask[floor]) >> floorShift[floor]) & ~chipMask) >> elementCount; - public static ulong GetGenerators(this ulong state, ulong floor) => - (ulong)(((state & ~floorMask[floor]) >> floorShift[floor]) & ~generatorMask) >> generatorShift; + public static ulong GetGenerators(this ulong state, ulong floor) => + (ulong)(((state & ~floorMask[floor]) >> floorShift[floor]) & ~generatorMask) >> generatorShift; - public static ulong AddChip(this ulong state, ulong floor, Element chip) => - state | (((ulong)chip << elementCount) << floorShift[floor]); + public static ulong AddChip(this ulong state, ulong floor, Element chip) => + state | (((ulong)chip << elementCount) << floorShift[floor]); - public static ulong AddGenerator(this ulong state, ulong floor, Element genetator) => - state | (((ulong)genetator << generatorShift) << floorShift[floor]); + public static ulong AddGenerator(this ulong state, ulong floor, Element genetator) => + state | (((ulong)genetator << generatorShift) << floorShift[floor]); public static bool Valid(this ulong state) { - for (int floor = 3; floor >= 0; floor--) { + for (int floor = 3; floor >= 0; floor--) { var chips = state.GetChips((ulong)floor); var generators = state.GetGenerators((ulong)floor); - var pairs = chips & generators; - var unpairedChips = chips & ~pairs; - if (unpairedChips != 0 && generators != 0) { + var pairs = chips & generators; + var unpairedChips = chips & ~pairs; + if (unpairedChips != 0 && generators != 0) { return false; } } return true; } - public static IEnumerable NextStates(this ulong state) { + public static IEnumerable<ulong> NextStates(this ulong state) { var floor = state.GetElevator(); - for (ulong i = 1; i < 0b100000000000000; i <<= 1) { - for (ulong j = 1; j < 0b100000000000000; j <<= 1) { - var iOnFloor = i << floorShift[floor]; - var jOnFloor = j << floorShift[floor]; - if ((state & iOnFloor) != 0 && (state & jOnFloor) != 0) { - if (floor > 0) { - var iOnPrevFloor = i << floorShift[floor - 1]; - var jOnPrevFloor = j << floorShift[floor - 1]; - var elevatorOnPrevFloor = (floor - 1) << elevatorShift; - var stateNext = (state & ~iOnFloor & ~jOnFloor & elevatorMask) | iOnPrevFloor | jOnPrevFloor | elevatorOnPrevFloor; + for (ulong i = 1; i < 0b100000000000000; i <<= 1) { + for (ulong j = 1; j < 0b100000000000000; j <<= 1) { + var iOnFloor = i << floorShift[floor]; + var jOnFloor = j << floorShift[floor]; + if ((state & iOnFloor) != 0 && (state & jOnFloor) != 0) { + if (floor > 0) { + var iOnPrevFloor = i << floorShift[floor - 1]; + var jOnPrevFloor = j << floorShift[floor - 1]; + var elevatorOnPrevFloor = (floor - 1) << elevatorShift; + var stateNext = (state & ~iOnFloor & ~jOnFloor & elevatorMask) | iOnPrevFloor | jOnPrevFloor | elevatorOnPrevFloor; if (stateNext.Valid()) yield return stateNext; } - if (floor < 3) { - var iOnNextFloor = i << floorShift[floor + 1]; - var jOnNextFloor = j << floorShift[floor + 1]; - var elevatorOnNextFloor = (floor + 1) << elevatorShift; - var stateNext = (state & ~iOnFloor & ~jOnFloor & elevatorMask) | iOnNextFloor | jOnNextFloor | elevatorOnNextFloor; + if (floor < 3) { + var iOnNextFloor = i << floorShift[floor + 1]; + var jOnNextFloor = j << floorShift[floor + 1]; + var elevatorOnNextFloor = (floor + 1) << elevatorShift; + var stateNext = (state & ~iOnFloor & ~jOnFloor & elevatorMask) | iOnNextFloor | jOnNextFloor | elevatorOnNextFloor; if (stateNext.Valid()) yield return stateNext; } @@ -441,23 +441,23 @@

Radioisotope Thermoelectric Generators

} } - public static bool Final(this ulong state) => - (state & 0b0000000000000000111111111111111111111111111111111111111111) == 0; + public static bool Final(this ulong state) => + (state & 0b0000000000000000111111111111111111111111111111111111111111) == 0; public static string Tsto(this ulong state){ var sb = new StringBuilder(); - for (int floor = 3; floor >= 0; floor --){ - var e = state.GetElevator() == (ulong)floor ? "E" : " "; + for (int floor = 3; floor >= 0; floor --){ + var e = state.GetElevator() == (ulong)floor ? "E" : " "; var chips = state.GetChips((ulong)floor); var generators =state.GetGenerators((ulong)floor); - sb.Append($"F{(floor + 1)} {e} |"); - for (int i = 0; i < elementCount;i++){ - sb.Append((generators & 1) == 1 ? " #" : " ."); - sb.Append((chips & 1) == 1 ? " #" : " ."); - sb.Append(" |"); - chips >>= 1; - generators >>= 1; + sb.Append($"F{(floor + 1)} {e} |"); + for (int i = 0; i < elementCount;i++){ + sb.Append((generators & 1) == 1 ? " #" : " ."); + sb.Append((chips & 1) == 1 ? " #" : " ."); + sb.Append(" |"); + chips >>= 1; + generators >>= 1; } sb.AppendLine(); } diff --git a/2016/12/index.html b/2016/12/index.html index d47e2bc7..8a658d96 100644 --- a/2016/12/index.html +++ b/2016/12/index.html @@ -285,15 +285,15 @@

Leonardo's Monorail

namespace AdventOfCode.Y2016.Day12; -[ProblemName("Leonardo's Monorail")] +[ProblemName("Leonardo's Monorail")] class Solution : Solver { - public object PartOne(string input) => Solve(input, 0); + public object PartOne(string input) => Solve(input, 0); - public object PartTwo(string input) => Solve(input, 1); + public object PartTwo(string input) => Solve(input, 1); int Solve(string input, int c) { - var regs = new Dictionary(); + var regs = new Dictionary<string, int>(); int ip = 0; int getReg(string reg) { return int.TryParse(reg, out var n) ? n @@ -304,32 +304,32 @@

Leonardo's Monorail

regs[reg] = value; } - setReg("c", c); + setReg("c", c); - var prog = input.Split('\n').ToArray(); - while (ip >= 0 && ip < prog.Length) { + var prog = input.Split('\n').ToArray(); + while (ip >= 0 && ip < prog.Length) { var line = prog[ip]; - var stm = line.Split(' '); + var stm = line.Split(' '); switch (stm[0]) { - case "cpy": + case "cpy": setReg(stm[2], getReg(stm[1])); ip++; break; - case "inc": + case "inc": setReg(stm[1], getReg(stm[1]) + 1); ip++; break; - case "dec": + case "dec": setReg(stm[1], getReg(stm[1]) - 1); ip++; break; - case "jnz": + case "jnz": ip += getReg(stm[1]) != 0 ? getReg(stm[2]) : 1; break; - default: throw new Exception("Cannot parse " + line); + default: throw new Exception("Cannot parse " + line); } } - return getReg("a"); + return getReg("a"); } } diff --git a/2016/13/index.html b/2016/13/index.html index ec2946c9..5fdf0cc3 100644 --- a/2016/13/index.html +++ b/2016/13/index.html @@ -285,23 +285,23 @@

A Maze of Twisty Little Cubicles

namespace AdventOfCode.Y2016.Day13; -[ProblemName("A Maze of Twisty Little Cubicles")] +[ProblemName("A Maze of Twisty Little Cubicles")] class Solution : Solver { - public object PartOne(string input) => + public object PartOne(string input) => Steps(int.Parse(input)) - .First(s => s.icol == 31 && s.irow == 39) + .First(s => s.icol == 31 && s.irow == 39) .steps; - public object PartTwo(string input) => + public object PartTwo(string input) => Steps(int.Parse(input)) - .TakeWhile(s => s.steps <= 50) + .TakeWhile(s => s.steps <= 50) .Count(); - IEnumerable<(int steps, int irow, int icol)> Steps(int input) { - var q = new Queue<(int steps, int irow, int icol)>(); + IEnumerable<(int steps, int irow, int icol)> Steps(int input) { + var q = new Queue<(int steps, int irow, int icol)>(); q.Enqueue((0, 1, 1)); - var seen = new HashSet<(int, int)>(); + var seen = new HashSet<(int, int)>(); seen.Add((1, 1)); var n = ( from drow in new[] { -1, 0, 1 } @@ -317,9 +317,9 @@

A Maze of Twisty Little Cubicles

foreach (var (drow, dcol) in n) { var (irowT, icolT) = (irow + drow, icol + dcol); - if (irowT >= 0 && icolT >= 0) { + if (irowT >= 0 && icolT >= 0) { var w = icolT * icolT + 3 * icolT + 2 * icolT * irowT + irowT + irowT * irowT + input; - if (Convert.ToString(w, 2).Count(ch => ch == '1') % 2 == 0) { + if (Convert.ToString(w, 2).Count(ch => ch == '1') % 2 == 0) { if (!seen.Contains((irowT, icolT))) { q.Enqueue((steps + 1, irowT, icolT)); seen.Add((irowT, icolT)); diff --git a/2016/14/index.html b/2016/14/index.html index 7ca7e535..61ac6ed7 100644 --- a/2016/14/index.html +++ b/2016/14/index.html @@ -289,30 +289,30 @@

One-Time Pad

namespace AdventOfCode.Y2016.Day14; -[ProblemName("One-Time Pad")] +[ProblemName("One-Time Pad")] class Solution : Solver { - public object PartOne(string input) => Solve(Hashes(input, 0)); - public object PartTwo(string input) => Solve(Hashes(input, 2016)); + public object PartOne(string input) => Solve(Hashes(input, 0)); + public object PartTwo(string input) => Solve(Hashes(input, 2016)); - int Solve(IEnumerable hashes) { + int Solve(IEnumerable<string> hashes) { var found = 0; - var nextIdx = Enumerable.Range(0, 16).Select(_ => new Queue()).ToArray(); + var nextIdx = Enumerable.Range(0, 16).Select(_ => new Queue<int>()).ToArray(); var res = 0; - var hashQueue = new Queue(); + var hashQueue = new Queue<string>(); var idx = 0; var idxEnd = 0; foreach (var hashEnd in hashes) { hashQueue.Enqueue(hashEnd); - for (int i = 0; i < hashEnd.Length - 5; i++) { - if (hashEnd[i] == hashEnd[i + 1] && - hashEnd[i + 1] == hashEnd[i + 2] && - hashEnd[i + 2] == hashEnd[i + 3] && + for (int i = 0; i < hashEnd.Length - 5; i++) { + if (hashEnd[i] == hashEnd[i + 1] && + hashEnd[i + 1] == hashEnd[i + 2] && + hashEnd[i + 2] == hashEnd[i + 3] && hashEnd[i + 3] == hashEnd[i + 4] ) { - var c = hashEnd[i] <= '9' ? hashEnd[i] - '0' : hashEnd[i] - 'a' + 10; + var c = hashEnd[i] <= '9' ? hashEnd[i] - '0' : hashEnd[i] - 'a' + 10; nextIdx[c].Enqueue(idxEnd); } } @@ -320,14 +320,14 @@

One-Time Pad

if (hashQueue.Count() == 1001) { var hash = hashQueue.Dequeue(); - for (int i = 0; i < hash.Length - 2; i++) { - if (hash[i] == hash[i + 1] && hash[i + 2] == hash[i + 1]) { - var iq = hash[i] <= '9' ? hash[i] - '0' : hash[i] - 'a' + 10; + for (int i = 0; i < hash.Length - 2; i++) { + if (hash[i] == hash[i + 1] && hash[i + 2] == hash[i + 1]) { + var iq = hash[i] <= '9' ? hash[i] - '0' : hash[i] - 'a' + 10; var q = nextIdx[iq]; - while (q.Any() && q.First() <= idx) { + while (q.Any() && q.First() <= idx) { q.Dequeue(); } - if (q.Any() && q.First() - idx <= 1000) { + if (q.Any() && q.First() - idx <= 1000) { found++; res = idx; if (found == 64) { @@ -344,34 +344,34 @@

One-Time Pad

throw new Exception(); } - public IEnumerable Hashes(string input, int rehash) { + public IEnumerable<string> Hashes(string input, int rehash) { - for (var i = 0; i < int.MaxValue; i++) { - var q = new ConcurrentQueue<(int i, string hash)>(); + for (var i = 0; i < int.MaxValue; i++) { + var q = new ConcurrentQueue<(int i, string hash)>(); Parallel.ForEach( Enumerable.Range(i, 1000), - () => MD5.Create(), - (i, state, md5) => { + () => MD5.Create(), + (i, state, md5) => { var newInput = new byte[32]; - var btoh = new[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + var btoh = new[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; var hash = md5.ComputeHash(Encoding.ASCII.GetBytes(input + i)); - for (var r = 0; r < rehash; r++) { - for (int ib = 0; ib < 16; ib++) { - newInput[2 * ib] = (byte)btoh[(hash[ib] >> 4) & 15]; - newInput[2 * ib + 1] = (byte)btoh[hash[ib] & 15]; + for (var r = 0; r < rehash; r++) { + for (int ib = 0; ib < 16; ib++) { + newInput[2 * ib] = (byte)btoh[(hash[ib] >> 4) & 15]; + newInput[2 * ib + 1] = (byte)btoh[hash[ib] & 15]; } hash = md5.ComputeHash(newInput); } - q.Enqueue((i, string.Join("", hash.Select(b => b.ToString("x2"))))); + q.Enqueue((i, string.Join("", hash.Select(b => b.ToString("x2"))))); return md5; }, - (_) => { } + (_) => { } ); - foreach (var item in q.OrderBy(x => x.i)) { + foreach (var item in q.OrderBy(x => x.i)) { i = item.i; yield return item.hash; } diff --git a/2016/15/index.html b/2016/15/index.html index 51b29bed..baffea80 100644 --- a/2016/15/index.html +++ b/2016/15/index.html @@ -285,23 +285,23 @@

Timing is Everything

namespace AdventOfCode.Y2016.Day15; -[ProblemName("Timing is Everything")] +[ProblemName("Timing is Everything")] class Solution : Solver { - public object PartOne(string input) => Iterate(Parse(input)).First(v => v.ok).t; + public object PartOne(string input) => Iterate(Parse(input)).First(v => v.ok).t; - public object PartTwo(string input) => Iterate(Parse(input).Concat(new []{(pos: 0, mod: 11)}).ToArray()).First(v => v.ok).t; + public object PartTwo(string input) => Iterate(Parse(input).Concat(new []{(pos: 0, mod: 11)}).ToArray()).First(v => v.ok).t; - (int pos, int mod)[] Parse(string input) => ( - from line in input.Split('\n') - let m = Regex.Match(line, @"Disc #\d has (\d+) positions; at time=0, it is at position (\d+).") + (int pos, int mod)[] Parse(string input) => ( + from line in input.Split('\n') + let m = Regex.Match(line, @"Disc #\d has (\d+) positions; at time=0, it is at position (\d+).") select (pos: int.Parse(m.Groups[2].Value), mod: int.Parse(m.Groups[1].Value)) ).ToArray(); - IEnumerable<(int t, bool ok)> Iterate((int pos, int mod)[] discs) { + IEnumerable<(int t, bool ok)> Iterate((int pos, int mod)[] discs) { for (int t = 0; ; t++) { var ok = Enumerable.Range(0, discs.Length) - .All(i => (discs[i].pos + t + i + 1) % discs[i].mod == 0); + .All(i => (discs[i].pos + t + i + 1) % discs[i].mod == 0); yield return (t, ok); } } diff --git a/2016/16/index.html b/2016/16/index.html index de82cbb9..d4d5b377 100644 --- a/2016/16/index.html +++ b/2016/16/index.html @@ -284,27 +284,27 @@

Dragon Checksum

namespace AdventOfCode.Y2016.Day16; -[ProblemName("Dragon Checksum")] +[ProblemName("Dragon Checksum")] class Solution : Solver { - public object PartOne(string input) => Checksum(input, 272); + public object PartOne(string input) => Checksum(input, 272); - public object PartTwo(string input) => Checksum(input, 35651584); + public object PartTwo(string input) => Checksum(input, 35651584); string Checksum(string st, int length) { - while (st.Length < length) { + while (st.Length < length) { var a = st; - var b = string.Join("", from ch in a.Reverse() select ch == '0' ? '1' : '0'); - st = a + "0" + b; + var b = string.Join("", from ch in a.Reverse() select ch == '0' ? '1' : '0'); + st = a + "0" + b; } st = st.Substring(0, length); var sb = new StringBuilder(); while (sb.Length % 2 == 0) { sb.Clear(); - for (int i = 0; i < st.Length; i += 2) { - sb.Append(st[i] == st[i + 1] ? "1" : "0"); + for (int i = 0; i < st.Length; i += 2) { + sb.Append(st[i] == st[i + 1] ? "1" : "0"); } st = sb.ToString(); } diff --git a/2016/17/index.html b/2016/17/index.html index 110e6b8e..189dfc78 100644 --- a/2016/17/index.html +++ b/2016/17/index.html @@ -295,37 +295,37 @@

Two Steps Forward

namespace AdventOfCode.Y2016.Day17; -[ProblemName("Two Steps Forward")] +[ProblemName("Two Steps Forward")] class Solution : Solver { - public object PartOne(string input) => Routes(input).First(); + public object PartOne(string input) => Routes(input).First(); - public object PartTwo(string input) => Routes(input).Last().Length; + public object PartTwo(string input) => Routes(input).Last().Length; - IEnumerable Routes(string input) { + IEnumerable<string> Routes(string input) { - var q = new Queue<(string path, int irow, int icol)>(); - q.Enqueue(("", 0, 0)); + var q = new Queue<(string path, int irow, int icol)>(); + q.Enqueue(("", 0, 0)); while (q.Any()) { var s = q.Dequeue(); - if (s.icol == 3 && s.irow == 3) { + if (s.icol == 3 && s.irow == 3) { yield return s.path; } else { var doors = DoorState(input + s.path); - if (doors.down && s.irow < 3) { - q.Enqueue((s.path + "D", s.irow + 1, s.icol)); + if (doors.down && s.irow < 3) { + q.Enqueue((s.path + "D", s.irow + 1, s.icol)); } - if (doors.up && s.irow > 0) { - q.Enqueue((s.path + "U", s.irow - 1, s.icol)); + if (doors.up && s.irow > 0) { + q.Enqueue((s.path + "U", s.irow - 1, s.icol)); } - if (doors.left && s.icol > 0) { - q.Enqueue((s.path + "L", s.irow, s.icol - 1)); + if (doors.left && s.icol > 0) { + q.Enqueue((s.path + "L", s.irow, s.icol - 1)); } - if (doors.right && s.icol < 3) { - q.Enqueue((s.path + "R", s.irow, s.icol + 1)); + if (doors.right && s.icol < 3) { + q.Enqueue((s.path + "R", s.irow, s.icol + 1)); } } } @@ -334,8 +334,8 @@

Two Steps Forward

(bool up, bool down, bool left, bool right) DoorState(string st) { var md5 = MD5.Create(); var hash = md5.ComputeHash(Encoding.ASCII.GetBytes(st)); - var stHash = string.Join("", hash.Select(b => b.ToString("x2"))); - return (stHash[0] > 'a', stHash[1] > 'a', stHash[2] > 'a', stHash[3] > 'a'); + var stHash = string.Join("", hash.Select(b => b.ToString("x2"))); + return (stHash[0] > 'a', stHash[1] > 'a', stHash[2] > 'a', stHash[3] > 'a'); } } diff --git a/2016/18/index.html b/2016/18/index.html index 88b835c6..3a9a2537 100644 --- a/2016/18/index.html +++ b/2016/18/index.html @@ -284,33 +284,33 @@

Like a Rogue

namespace AdventOfCode.Y2016.Day18; -[ProblemName("Like a Rogue")] +[ProblemName("Like a Rogue")] class Solution : Solver { - public object PartOne(string input) => SafeCount(input, 40); + public object PartOne(string input) => SafeCount(input, 40); - public object PartTwo(string input) => SafeCount(input, 400000); + public object PartTwo(string input) => SafeCount(input, 400000); int SafeCount(string input, int lines) { var rowPrev = input; - var safeCount = rowPrev.Count(ch => ch == '.'); - for (int i = 0; i < lines - 1; i++) { + var safeCount = rowPrev.Count(ch => ch == '.'); + for (int i = 0; i < lines - 1; i++) { StringBuilder sb = new StringBuilder(); - for (int j = 0; j < rowPrev.Length; j++) { - var leftTrap = j != 0 && rowPrev[j - 1] == '^'; - var centerTrap = rowPrev[j] == '^'; - var rightTrap = j != rowPrev.Length - 1 && rowPrev[j + 1] == '^'; + for (int j = 0; j < rowPrev.Length; j++) { + var leftTrap = j != 0 && rowPrev[j - 1] == '^'; + var centerTrap = rowPrev[j] == '^'; + var rightTrap = j != rowPrev.Length - 1 && rowPrev[j + 1] == '^'; var trap = - (leftTrap && centerTrap && !rightTrap) || - (!leftTrap && centerTrap && rightTrap) || - (leftTrap && !centerTrap && !rightTrap) || - (!leftTrap && !centerTrap && rightTrap) + (leftTrap && centerTrap && !rightTrap) || + (!leftTrap && centerTrap && rightTrap) || + (leftTrap && !centerTrap && !rightTrap) || + (!leftTrap && !centerTrap && rightTrap) ; - sb.Append(trap ? '^' : '.'); + sb.Append(trap ? '^' : '.'); } rowPrev = sb.ToString(); - safeCount += rowPrev.Count(ch => ch == '.'); + safeCount += rowPrev.Count(ch => ch == '.'); } return safeCount; diff --git a/2016/19/index.html b/2016/19/index.html index 4b92e218..46f0400c 100644 --- a/2016/19/index.html +++ b/2016/19/index.html @@ -284,23 +284,23 @@

An Elephant Named Joseph

namespace AdventOfCode.Y2016.Day19; -[ProblemName("An Elephant Named Joseph")] +[ProblemName("An Elephant Named Joseph")] class Solution : Solver { public object PartOne(string input) { var elves = Elves(int.Parse(input)); return Solve(elves[0], elves[1], elves.Length, - (elfVictim, count) => elfVictim.next.next); + (elfVictim, count) => elfVictim.next.next); } public object PartTwo(string input) { var elves = Elves(int.Parse(input)); return Solve(elves[0], elves[elves.Length / 2], elves.Length, - (elfVictim, count) => count % 2 == 1 ? elfVictim.next : elfVictim.next.next); + (elfVictim, count) => count % 2 == 1 ? elfVictim.next : elfVictim.next.next); } - int Solve(Elf elf, Elf elfVictim, int elfCount, Func nextVictim) { - while (elfCount > 1) { + int Solve(Elf elf, Elf elfVictim, int elfCount, Func<Elf, int, Elf> nextVictim) { + while (elfCount > 1) { elfVictim.prev.next = elfVictim.next; elfVictim.next.prev = elfVictim.prev; elf = elf.next; @@ -311,8 +311,8 @@

An Elephant Named Joseph

} Elf[] Elves(int count) { - var elves = Enumerable.Range(0, count).Select(x => new Elf { id = x + 1 }).ToArray(); - for (var i = 0; i < count; i++) { + var elves = Enumerable.Range(0, count).Select(x => new Elf { id = x + 1 }).ToArray(); + for (var i = 0; i < count; i++) { elves[i].prev = elves[(i - 1 + count) % count]; elves[i].next = elves[(i + 1) % count]; } diff --git a/2016/2/index.html b/2016/2/index.html index 6bd0e71a..7383933f 100644 --- a/2016/2/index.html +++ b/2016/2/index.html @@ -283,29 +283,29 @@

Bathroom Security

namespace AdventOfCode.Y2016.Day02; -[ProblemName("Bathroom Security")] +[ProblemName("Bathroom Security")] class Solution : Solver { - public object PartOne(string input) => Solve(input, "123\n456\n789"); - public object PartTwo(string input) => Solve(input, " 1 \n 234 \n56789\n ABC \n D "); + public object PartOne(string input) => Solve(input, "123\n456\n789"); + public object PartTwo(string input) => Solve(input, " 1 \n 234 \n56789\n ABC \n D "); string Solve(string input, string keypad) { - var res = ""; - var lines = keypad.Split('\n'); + var res = ""; + var lines = keypad.Split('\n'); var (crow, ccol) = (lines.Length, lines[0].Length); var (irow, icol) = (crow / 2, ccol / 2); - foreach (var line in input.Split('\n')) { + foreach (var line in input.Split('\n')) { foreach (var ch in line) { var (drow, dcol) = ch switch { - 'U' => (-1, 0), - 'D' => (1, 0), - 'L' => (0, -1), - 'R' => (0, 1), - _ => throw new ArgumentException() + 'U' => (-1, 0), + 'D' => (1, 0), + 'L' => (0, -1), + 'R' => (0, 1), + _ => throw new ArgumentException() }; var (irowT, icolT) = (irow + drow, icol + dcol); - if (irowT >= 0 && irowT < crow && icolT >= 0 && icolT < ccol && lines[irowT][icolT] != ' ') { + if (irowT >= 0 && irowT < crow && icolT >= 0 && icolT < ccol && lines[irowT][icolT] != ' ') { (irow, icol) = (irowT, icolT); } } diff --git a/2016/20/index.html b/2016/20/index.html index 56321052..19d2c691 100644 --- a/2016/20/index.html +++ b/2016/20/index.html @@ -284,15 +284,15 @@

Firewall Rules

namespace AdventOfCode.Y2016.Day20; -[ProblemName("Firewall Rules")] +[ProblemName("Firewall Rules")] class Solution : Solver { public object PartOne(string input) { var k = 0L; foreach (var range in Parse(input)) { - if (k < range.min) { + if (k < range.min) { break; - } else if (range.min <= k && k <= range.max) { + } else if (range.min <= k && k <= range.max) { k = range.max + 1; } } @@ -303,24 +303,24 @@

Firewall Rules

var k = 0L; var sum = 0L; foreach (var range in Parse(input)) { - if (k < range.min) { + if (k < range.min) { sum += range.min - k; k = range.max + 1; - } else if (range.min <= k && k <= range.max) { + } else if (range.min <= k && k <= range.max) { k = range.max + 1; } } var lim = 4294967296L; - if (lim > k) { + if (lim > k) { sum += lim - k; } return sum; } - IEnumerable<(long min, long max)> Parse(string input) => ( - from line in input.Split('\n') - let parts = line.Split('-') + IEnumerable<(long min, long max)> Parse(string input) => ( + from line in input.Split('\n') + let parts = line.Split('-') let min = long.Parse(parts[0]) let max = long.Parse(parts[1]) orderby min diff --git a/2016/21/index.html b/2016/21/index.html index f4d86de7..d583a68b 100644 --- a/2016/21/index.html +++ b/2016/21/index.html @@ -286,24 +286,24 @@

Scrambled Letters and Hash

namespace AdventOfCode.Y2016.Day21; -[ProblemName("Scrambled Letters and Hash")] +[ProblemName("Scrambled Letters and Hash")] class Solution : Solver { - public object PartOne(string input) => string.Join("", Parse(input)("abcdefgh")); + public object PartOne(string input) => string.Join("", Parse(input)("abcdefgh")); public object PartTwo(string input) { var scramble = Parse(input); - return string.Join("", Permutations("abcdefgh".ToArray()).First(p => scramble(p).SequenceEqual("fbgdceah"))); + return string.Join("", Permutations("abcdefgh".ToArray()).First(p => scramble(p).SequenceEqual("fbgdceah"))); } - IEnumerable Permutations(T[] rgt) { + IEnumerable<T[]> Permutations<T>(T[] rgt) { - IEnumerable PermutationsRec(int i) { + IEnumerable<T[]> PermutationsRec(int i) { if (i == rgt.Length) { yield return rgt.ToArray(); } - for (var j = i; j < rgt.Length; j++) { + for (var j = i; j < rgt.Length; j++) { (rgt[i], rgt[j]) = (rgt[j], rgt[i]); foreach (var perm in PermutationsRec(i + 1)) { yield return perm; @@ -315,46 +315,46 @@

Scrambled Letters and Hash

return PermutationsRec(0); } - Func, IEnumerable> Parse(string input) { + Func<IEnumerable<char>, IEnumerable<char>> Parse(string input) { var steps = ( - from line in input.Split('\n') + from line in input.Split('\n') select - Match(line, @"swap position (\d+) with position (\d+)", m => { + Match(line, @"swap position (\d+) with position (\d+)", m => { var x = int.Parse(m[0]); var y = int.Parse(m[1]); - return chars => SwapPosition(chars, x, y); + return chars => SwapPosition(chars, x, y); }) ?? - Match(line, @"swap letter (\w) with letter (\w)", m => { + Match(line, @"swap letter (\w) with letter (\w)", m => { var chX = m[0][0]; var chY = m[1][0]; - return (chars) => SwapLetter(chars, chX, chY); + return (chars) => SwapLetter(chars, chX, chY); }) ?? - Match(line, @"rotate left (\d+) step", m => { + Match(line, @"rotate left (\d+) step", m => { var x = int.Parse(m[0]); - return chars => RotateLeft(chars, x); + return chars => RotateLeft(chars, x); }) ?? - Match(line, @"rotate right (\d+) step", m => { + Match(line, @"rotate right (\d+) step", m => { var x = int.Parse(m[0]); - return chars => RotateRight(chars, x); + return chars => RotateRight(chars, x); }) ?? - Match(line, @"rotate based on position of letter (\w)", m => { + Match(line, @"rotate based on position of letter (\w)", m => { var chX = m[0][0]; - return chars => RotateBasedOnPosition(chars, chX); + return chars => RotateBasedOnPosition(chars, chX); }) ?? - Match(line, @"reverse positions (\d+) through (\d+)", m => { + Match(line, @"reverse positions (\d+) through (\d+)", m => { var x = int.Parse(m[0]); var y = int.Parse(m[1]); - return chars => Reverse(chars, x, y); + return chars => Reverse(chars, x, y); }) ?? - Match(line, @"move position (\d+) to position (\d+)", m => { + Match(line, @"move position (\d+) to position (\d+)", m => { var x = int.Parse(m[0]); var y = int.Parse(m[1]); - return chars => MovePosition(chars, x, y); + return chars => MovePosition(chars, x, y); }) ?? - throw new Exception("Cannot parse " + line) + throw new Exception("Cannot parse " + line) ).ToArray(); - return chars => { + return chars => { var charsArray = chars.ToArray(); foreach (var step in steps) { step(charsArray); @@ -363,10 +363,10 @@

Scrambled Letters and Hash

}; } - Action Match(string stm, string pattern, Func> a) { + Action<char[]> Match(string stm, string pattern, Func<string[], Action<char[]>> a) { var match = Regex.Match(stm, pattern); if (match.Success) { - return a(match.Groups.Cast().Skip(1).Select(g => g.Value).ToArray()); + return a(match.Groups.Cast<Group>().Skip(1).Select(g => g.Value).ToArray()); } else { return null; } @@ -377,14 +377,14 @@

Scrambled Letters and Hash

} void SwapLetter(char[] chars, char chX, char chY) { - for (var i = 0; i < chars.Length; i++) { + for (var i = 0; i < chars.Length; i++) { chars[i] = chars[i] == chX ? chY : chars[i] == chY ? chX : chars[i]; } } void RotateBasedOnPosition(char[] chars, char chX) { var i = Array.IndexOf(chars, chX); - RotateRight(chars, i >= 4 ? i + 2 : i + 1); + RotateRight(chars, i >= 4 ? i + 2 : i + 1); } void RotateLeft(char[] chars, int t) { @@ -402,7 +402,7 @@

Scrambled Letters and Hash

} void Reverse(char[] chars, int x, int y) { - while (x < y) { + while (x < y) { (chars[x], chars[y]) = (chars[y], chars[x]); x++; y--; @@ -410,7 +410,7 @@

Scrambled Letters and Hash

} void MovePosition(char[] chars, int x, int y) { - var d = x < y ? 1 : -1; + var d = x < y ? 1 : -1; var ch = chars[x]; for (int i = x + d; i != y + d; i += d) { diff --git a/2016/22/index.html b/2016/22/index.html index 4126fbd2..a59243af 100644 --- a/2016/22/index.html +++ b/2016/22/index.html @@ -286,16 +286,16 @@

Grid Computing

namespace AdventOfCode.Y2016.Day22; -[ProblemName("Grid Computing")] +[ProblemName("Grid Computing")] class Solution : Solver { public object PartOne(string input) { var nodes = Parse(input); var r = 0; foreach (var nodeA in nodes) { - if (nodeA.used > 0) { + if (nodeA.used > 0) { foreach (var nodeB in nodes) { - if ((nodeA.irow != nodeB.irow || nodeA.icol != nodeB.icol) && nodeB.avail > nodeA.used) { + if ((nodeA.irow != nodeB.irow || nodeA.icol != nodeB.icol) && nodeB.avail > nodeA.used) { r++; } } @@ -330,12 +330,12 @@

Grid Computing

Node[,] Parse(string input) { var nodes = ( - from line in input.Split('\n').Skip(2) - let parts = Regex.Matches(line, @"(\d+)").Select(m => int.Parse(m.Groups[1].Value)).ToArray() + from line in input.Split('\n').Skip(2) + let parts = Regex.Matches(line, @"(\d+)").Select(m => int.Parse(m.Groups[1].Value)).ToArray() select new Node { irow = parts[1], icol = parts[0], size = parts[2], used = parts[3] } ).ToArray(); - var (crow, ccol) = (nodes.Select(x => x.irow).Max() + 1, nodes.Select(x => x.icol).Max() + 1); + var (crow, ccol) = (nodes.Select(x => x.irow).Max() + 1, nodes.Select(x => x.icol).Max() + 1); var res = new Node[crow, ccol]; foreach (var file in nodes) { res[file.irow, file.icol] = file; @@ -367,18 +367,18 @@

Grid Computing

public void Tsto() { var sb = new StringBuilder(); sb.AppendLine(); - for (var irowT = 0; irowT < crow; irowT++) { - for (var icolT = 0; icolT < ccol; icolT++) { + for (var irowT = 0; irowT < crow; irowT++) { + for (var icolT = 0; icolT < ccol; icolT++) { if (nodes[irowT, icolT].goal) { - sb.Append("G"); - } else if (irowT == 0 && icolT == 0) { - sb.Append("x"); + sb.Append("G"); + } else if (irowT == 0 && icolT == 0) { + sb.Append("x"); } else if (nodes[irowT, icolT].used == 0) { - sb.Append("E"); + sb.Append("E"); } else if (Wall(irowT, icolT)) { - sb.Append("#"); + sb.Append("#"); } else { - sb.Append("."); + sb.Append("."); } } sb.AppendLine(); @@ -386,8 +386,8 @@

Grid Computing

Console.WriteLine(sb.ToString()); } - public bool Wall(int irow, int icol) => - nodes[irow, icol].used > nodes[irowEmpty, icolEmpty].size; + public bool Wall(int irow, int icol) => + nodes[irow, icol].used > nodes[irowEmpty, icolEmpty].size; public void Move(int drow, int dcol) { if (Math.Abs(drow) + Math.Abs(dcol) != 1) throw new Exception(); @@ -395,9 +395,9 @@

Grid Computing

var irowT = irowEmpty + drow; var icolT = icolEmpty + dcol; - if (irowT < 0 || irowT >= crow) throw new Exception(); - if (icolT < 0 || icolT >= ccol) throw new Exception(); - if (nodes[irowT, icolT].used > nodes[irowEmpty, icolEmpty].avail) throw new Exception(); + if (irowT < 0 || irowT >= crow) throw new Exception(); + if (icolT < 0 || icolT >= ccol) throw new Exception(); + if (nodes[irowT, icolT].used > nodes[irowEmpty, icolEmpty].avail) throw new Exception(); nodes[irowEmpty, icolEmpty].used = nodes[irowT, icolT].used; nodes[irowEmpty, icolEmpty].goal = nodes[irowT, icolT].goal; diff --git a/2016/23/index.html b/2016/23/index.html index 11140972..fb1b8d47 100644 --- a/2016/23/index.html +++ b/2016/23/index.html @@ -285,15 +285,15 @@

Safe Cracking

namespace AdventOfCode.Y2016.Day23; -[ProblemName("Safe Cracking")] +[ProblemName("Safe Cracking")] class Solution : Solver { - public object PartOne(string input) => Solve(input, 7); - public object PartTwo(string input) => Solve(input, 12); + public object PartOne(string input) => Solve(input, 7); + public object PartTwo(string input) => Solve(input, 12); int Solve(string input, int a) { var prg = Parse(Patch(input)); - var regs = new Dictionary(); + var regs = new Dictionary<string, int>(); var ip = 0; int getReg(string reg) { return int.TryParse(reg, out var n) ? n @@ -306,63 +306,63 @@

Safe Cracking

} } - setReg("a", a); + setReg("a", a); - while(ip < prg.Length){ + while(ip < prg.Length){ var stm = prg[ip]; switch (stm[0]) { - case "cpy": + case "cpy": setReg(stm[2], getReg(stm[1])); ip++; break; - case "inc": + case "inc": setReg(stm[1], getReg(stm[1]) + 1); ip++; break; - case "mul": + case "mul": setReg(stm[2], getReg(stm[1]) * getReg(stm[2])); ip++; break; - case "dec": + case "dec": setReg(stm[1], getReg(stm[1]) - 1); ip++; break; - case "jnz": + case "jnz": ip += getReg(stm[1]) != 0 ? getReg(stm[2]) : 1; break; - case "tgl": + case "tgl": var ipDst = ip + getReg(stm[1]); - if (ipDst >= 0 && ipDst < prg.Length) { + if (ipDst >= 0 && ipDst < prg.Length) { var stmDst = prg[ipDst]; stmDst[0] = stmDst[0] switch { - "cpy" => "jnz", - "inc" => "dec", - "dec" => "inc", - "jnz" => "cpy", - "tgl" => "inc", - _ => stmDst[0] + "cpy" => "jnz", + "inc" => "dec", + "dec" => "inc", + "jnz" => "cpy", + "tgl" => "inc", + _ => stmDst[0] }; } ip++; break; default: - throw new Exception("Cannot parse " + string.Join(" ", stm)); + throw new Exception("Cannot parse " + string.Join(" ", stm)); } } - return getReg("a"); + return getReg("a"); } string Patch(string input) { - var lines = input.Split('\n'); - lines[5] = "cpy c a"; - lines[6] = "mul d a"; - lines[7] = "cpy 0 d"; - lines[8] = "cpy 0 c"; - return string.Join("\n", lines); + var lines = input.Split('\n'); + lines[5] = "cpy c a"; + lines[6] = "mul d a"; + lines[7] = "cpy 0 d"; + lines[8] = "cpy 0 c"; + return string.Join("\n", lines); } - string[][] Parse(string input) => - input.Split('\n').Select(line => line.Split(' ')).ToArray(); + string[][] Parse(string input) => + input.Split('\n').Select(line => line.Split(' ')).ToArray(); }

Please ☆ my repo if you like it!

diff --git a/2016/24/index.html b/2016/24/index.html index 3163dffe..6be7d248 100644 --- a/2016/24/index.html +++ b/2016/24/index.html @@ -284,14 +284,14 @@

Air Duct Spelunking

namespace AdventOfCode.Y2016.Day24; -[ProblemName("Air Duct Spelunking")] +[ProblemName("Air Duct Spelunking")] class Solution : Solver { - public object PartOne(string input) => Routes(input, false).Min(); + public object PartOne(string input) => Routes(input, false).Min(); - public object PartTwo(string input) => Routes(input, true).Min(); + public object PartTwo(string input) => Routes(input, true).Min(); - IEnumerable Routes(string input, bool loop) { + IEnumerable<int> Routes(string input, bool loop) { var map = new Map(input); foreach (var perm in Permutations(Enumerable.Range(1, map.poi.Length - 1).ToArray())) { @@ -301,21 +301,21 @@

Air Duct Spelunking

perm.Add(0); } var l = 0; - for (int i = 0; i < perm.Count - 1; i++) { + for (int i = 0; i < perm.Count - 1; i++) { l += map.ShortestPathLength(map.poi[perm[i]], map.poi[perm[i + 1]]); } yield return l; } } - IEnumerable> Permutations(T[] rgt) { + IEnumerable<List<T>> Permutations<T>(T[] rgt) { - IEnumerable> PermutationsRec(int i) { + IEnumerable<List<T>> PermutationsRec(int i) { if (i == rgt.Length) { yield return rgt.ToList(); } - for (var j = i; j < rgt.Length; j++) { + for (var j = i; j < rgt.Length; j++) { (rgt[i], rgt[j]) = (rgt[j], rgt[i]); foreach (var perm in PermutationsRec(i + 1)) { yield return perm; @@ -333,18 +333,18 @@

Air Duct Spelunking

public int crow; public int ccol; public (int irow, int icol)[] poi; - private Dictionary<(int, int, int, int), int> cache = new Dictionary<(int, int, int, int), int>(); + private Dictionary<(int, int, int, int), int> cache = new Dictionary<(int, int, int, int), int>(); public Map(string input) { - this.map = input.Split('\n'); + this.map = input.Split('\n'); this.crow = map.Length; this.ccol = map[0].Length; poi = new(int irow, int icol)[10]; var poiCount = 0; - for (var irow = 0; irow < crow; irow++) { - for (var icol = 0; icol < ccol; icol++) { - if (int.TryParse($"{map[irow][icol]}", out var i)) { + for (var irow = 0; irow < crow; irow++) { + for (var icol = 0; icol < ccol; icol++) { + if (int.TryParse($"{map[irow][icol]}", out var i)) { poi[i] = (irow, icol); poiCount++; } @@ -356,21 +356,21 @@

Air Duct Spelunking

public int ShortestPathLength((int irow, int icol) from, (int irow, int icol) to) { var key = (from.irow, from.icol, to.irow, to.icol); if (!cache.ContainsKey(key)) { - var q = new Queue<(int steps, int irow, int icol)>(); + var q = new Queue<(int steps, int irow, int icol)>(); q.Enqueue((0, from.irow, from.icol)); - var seen = new HashSet<(int, int)>(); + var seen = new HashSet<(int, int)>(); seen.Add(from); while (q.Any()) { var p = q.Dequeue(); - if (p.irow == to.irow && p.icol == to.icol) { + if (p.irow == to.irow && p.icol == to.icol) { cache[key] = p.steps; break; } foreach (var (drow, dcol) in new[] { (-1, 0), (1, 0), (0, 1), (0, -1) }) { var (irowT, icolT) = (p.irow + drow, p.icol + dcol); - if (irowT >= 0 && irowT < crow && - icolT >= 0 && icolT < ccol && - map[irowT][icolT] != '#' && + if (irowT >= 0 && irowT < crow && + icolT >= 0 && icolT < ccol && + map[irowT][icolT] != '#' && !seen.Contains((irowT, icolT)) ) { q.Enqueue((p.steps + 1, irowT, icolT)); diff --git a/2016/25/index.html b/2016/25/index.html index 081a56d3..bcb8617d 100644 --- a/2016/25/index.html +++ b/2016/25/index.html @@ -285,7 +285,7 @@

Clock Signal

namespace AdventOfCode.Y2016.Day25; -[ProblemName("Clock Signal")] +[ProblemName("Clock Signal")] class Solution : Solver { public object PartOne(string input) { @@ -306,9 +306,9 @@

Clock Signal

} } - IEnumerable Run(string input, int a) { + IEnumerable<int> Run(string input, int a) { var prg = Parse(input); - var regs = new Dictionary(); + var regs = new Dictionary<string, int>(); var ip = 0; int getReg(string reg) { return int.TryParse(reg, out var n) ? n @@ -321,38 +321,38 @@

Clock Signal

} } - setReg("a", a); + setReg("a", a); - while (ip < prg.Length) { + while (ip < prg.Length) { var stm = prg[ip]; switch (stm[0]) { - case "cpy": + case "cpy": setReg(stm[2], getReg(stm[1])); ip++; break; - case "inc": + case "inc": setReg(stm[1], getReg(stm[1]) + 1); ip++; break; - case "out": + case "out": yield return getReg(stm[1]); ip++; break; - case "dec": + case "dec": setReg(stm[1], getReg(stm[1]) - 1); ip++; break; - case "jnz": + case "jnz": ip += getReg(stm[1]) != 0 ? getReg(stm[2]) : 1; break; default: - throw new Exception("Cannot parse " + string.Join(" ", stm)); + throw new Exception("Cannot parse " + string.Join(" ", stm)); } } } - string[][] Parse(string input) => - input.Split('\n').Select(line => line.Split(' ')).ToArray(); + string[][] Parse(string input) => + input.Split('\n').Select(line => line.Split(' ')).ToArray(); }

Please ☆ my repo if you like it!

diff --git a/2016/3/index.html b/2016/3/index.html index baceab1b..7d2567d0 100644 --- a/2016/3/index.html +++ b/2016/3/index.html @@ -285,16 +285,16 @@

Squares With Three Sides

namespace AdventOfCode.Y2016.Day03; -[ProblemName("Squares With Three Sides")] +[ProblemName("Squares With Three Sides")] class Solution : Solver { - public object PartOne(string input) => ValidTriangles(Parse(input)); + public object PartOne(string input) => ValidTriangles(Parse(input)); public object PartTwo(string input) { - var tripplets = new List>(); + var tripplets = new List<IEnumerable<int>>(); foreach (var lineT in Transpose(Parse(input))) { - IEnumerable line = lineT; + IEnumerable<int> line = lineT; while (line.Any()) { tripplets.Add(line.Take(3)); line = line.Skip(3); @@ -304,24 +304,24 @@

Squares With Three Sides

return ValidTriangles(tripplets); } - int[][] Parse(string input) => ( - from line in input.Split('\n') - select Regex.Matches(line, @"\d+").Select(m => int.Parse(m.Value)).ToArray() + int[][] Parse(string input) => ( + from line in input.Split('\n') + select Regex.Matches(line, @"\d+").Select(m => int.Parse(m.Value)).ToArray() ).ToArray(); - int ValidTriangles(IEnumerable> tripplets) => - tripplets.Count(tripplet => { - var nums = tripplet.OrderBy(x => x).ToArray(); - return nums[0] + nums[1] > nums[2]; + int ValidTriangles(IEnumerable<IEnumerable<int>> tripplets) => + tripplets.Count(tripplet => { + var nums = tripplet.OrderBy(x => x).ToArray(); + return nums[0] + nums[1] > nums[2]; }); int[][] Transpose(int[][] src) { var crowDst = src[0].Length; var ccolDst = src.Length; int[][] dst = new int[crowDst][]; - for (int irowDst = 0; irowDst < crowDst; irowDst++) { + for (int irowDst = 0; irowDst < crowDst; irowDst++) { dst[irowDst] = new int[ccolDst]; - for (int icolDst = 0; icolDst < ccolDst; icolDst++) { + for (int icolDst = 0; icolDst < ccolDst; icolDst++) { dst[irowDst][icolDst] = src[icolDst][irowDst]; } } diff --git a/2016/4/index.html b/2016/4/index.html index 35a19d05..24c5835b 100644 --- a/2016/4/index.html +++ b/2016/4/index.html @@ -285,28 +285,28 @@

Security Through Obscurity

namespace AdventOfCode.Y2016.Day04; -[ProblemName("Security Through Obscurity")] +[ProblemName("Security Through Obscurity")] class Solution : Solver { - public object PartOne(string input) => ( + public object PartOne(string input) => ( from i in Parse(input) - let name = i.name.Replace("-", "") - let computedChecksum = string.Join("", (from ch in name group ch by ch into g orderby -g.Count(), g.Key select g.Key).Take(5)) + let name = i.name.Replace("-", "") + let computedChecksum = string.Join("", (from ch in name group ch by ch into g orderby -g.Count(), g.Key select g.Key).Take(5)) where computedChecksum == i.checksum select i.sectorid ).Sum(); - public object PartTwo(string input) => ( + public object PartTwo(string input) => ( from i in Parse(input) - let name = string.Join("", from ch in i.name select ch == '-' ? ' ' : (char)('a' + (ch - 'a' + i.sectorid) % 26)) - where name.Contains("northpole") + let name = string.Join("", from ch in i.name select ch == '-' ? ' ' : (char)('a' + (ch - 'a' + i.sectorid) % 26)) + where name.Contains("northpole") select i.sectorid ).Single(); - IEnumerable<(string name, int sectorid, string checksum)> Parse(string input){ - var rx = new Regex(@"([^\d]+)\-(\d+)\[(.*)\]"); + IEnumerable<(string name, int sectorid, string checksum)> Parse(string input){ + var rx = new Regex(@"([^\d]+)\-(\d+)\[(.*)\]"); - return from line in input.Split('\n') + return from line in input.Split('\n') let m = rx.Match(line) select (m.Groups[1].Value, int.Parse(m.Groups[2].Value), m.Groups[3].Value); diff --git a/2016/5/index.html b/2016/5/index.html index e258e7e8..74a5ec6c 100644 --- a/2016/5/index.html +++ b/2016/5/index.html @@ -290,13 +290,13 @@

How About a Nice Game of Chess?

namespace AdventOfCode.Y2016.Day05; -[ProblemName("How About a Nice Game of Chess?")] +[ProblemName("How About a Nice Game of Chess?")] class Solution : Solver { public object PartOne(string input) { - return string.Join("", Hashes(input).Select(hash => hash[5]).Take(8)); + return string.Join("", Hashes(input).Select(hash => hash[5]).Take(8)); } public object PartTwo(string input) @@ -305,8 +305,8 @@

How About a Nice Game of Chess?

var found = 0; foreach (var hash in Hashes(input)) { - var idx = hash[5] - '0'; - if (0 <= idx && idx < 8 && res[idx] == 0) + var idx = hash[5] - '0'; + if (0 <= idx && idx < 8 && res[idx] == 0) { res[idx] = hash[6]; found++; @@ -316,40 +316,40 @@

How About a Nice Game of Chess?

} } - return string.Join("", res); + return string.Join("", res); } - public IEnumerable Hashes(string input) + public IEnumerable<string> Hashes(string input) { - for (var i = 0; i < int.MaxValue; i++) + for (var i = 0; i < int.MaxValue; i++) { - var q = new ConcurrentQueue<(int i, string hash)>(); + var q = new ConcurrentQueue<(int i, string hash)>(); Parallel.ForEach( NumbersFrom(i), - () => MD5.Create(), - (i, state, md5) => + () => MD5.Create(), + (i, state, md5) => { var hash = md5.ComputeHash(Encoding.ASCII.GetBytes(input + i)); - var hashString = string.Join("", hash.Select(x => x.ToString("x2"))); + var hashString = string.Join("", hash.Select(x => x.ToString("x2"))); - if (hashString.StartsWith("00000")) + if (hashString.StartsWith("00000")) { q.Enqueue((i, hashString)); state.Stop(); } return md5; }, - (_) => { } + (_) => { } ); - var item = q.OrderBy(x => x.i).First(); + var item = q.OrderBy(x => x.i).First(); i = item.i; yield return item.hash; } } - IEnumerable NumbersFrom(int i) + IEnumerable<int> NumbersFrom(int i) { for (;;) yield return i++; } diff --git a/2016/6/index.html b/2016/6/index.html index e7f79c4d..ea57feb2 100644 --- a/2016/6/index.html +++ b/2016/6/index.html @@ -283,17 +283,17 @@

Signals and Noise

namespace AdventOfCode.Y2016.Day06; -[ProblemName("Signals and Noise")] +[ProblemName("Signals and Noise")] class Solution : Solver { - public object PartOne(string input) => Decode(input).mostFrequent; - public object PartTwo(string input) => Decode(input).leastFrequent; + public object PartOne(string input) => Decode(input).mostFrequent; + public object PartTwo(string input) => Decode(input).leastFrequent; (string mostFrequent, string leastFrequent) Decode(string input) { - var lines = input.Split('\n'); - string mostFrequent = ""; - string leastFrequent = ""; - for (int i = 0; i < lines[0].Length; i++) { + var lines = input.Split('\n'); + string mostFrequent = ""; + string leastFrequent = ""; + for (int i = 0; i < lines[0].Length; i++) { var items = (from line in lines group line by line[i] into g orderby g.Count() select g.Key); mostFrequent += items.Last(); leastFrequent += items.First(); diff --git a/2016/7/index.html b/2016/7/index.html index a95d2bc8..95d56b40 100644 --- a/2016/7/index.html +++ b/2016/7/index.html @@ -284,58 +284,58 @@

Internet Protocol Version 7

namespace AdventOfCode.Y2016.Day07; -[ProblemName("Internet Protocol Version 7")] +[ProblemName("Internet Protocol Version 7")] class Solution : Solver { - public object PartOne(string input) => - input.Split('\n').Count(TLS); + public object PartOne(string input) => + input.Split('\n').Count(TLS); - public object PartTwo(string input) => - input.Split('\n').Count(SSL); + public object PartTwo(string input) => + input.Split('\n').Count(SSL); - bool TLS(string st) => - Classify(st).Any(c => !c.f && Abba(c.st).Any()) && - Classify(st).All(c => !c.f || !Abba(c.st).Any()); + bool TLS(string st) => + Classify(st).Any(c => !c.f && Abba(c.st).Any()) && + Classify(st).All(c => !c.f || !Abba(c.st).Any()); - bool SSL(string st) => ( + bool SSL(string st) => ( from c1 in Classify(st) from c2 in Classify(st) - where !c1.f && c2.f + where !c1.f && c2.f from aba in Aba(c1.st) - let bab = $"{aba[1]}{aba[0]}{aba[1]}" + let bab = $"{aba[1]}{aba[0]}{aba[1]}" where c2.st.Contains(bab) select true ).Any(); - IEnumerable<(string st, bool f)> Classify(string st) { - var part = ""; - for (var i = 0; i < st.Length; i++) { + IEnumerable<(string st, bool f)> Classify(string st) { + var part = ""; + for (var i = 0; i < st.Length; i++) { var ch = st[i]; - if (ch == '[') { + if (ch == '[') { yield return (part, false); - part = ""; - } else if (ch == ']') { + part = ""; + } else if (ch == ']') { yield return (part, true); - part = ""; + part = ""; } else { part += ch; } } - if (part != "") + if (part != "") yield return (part, false); } - IEnumerable Abba(string st) { - for (var i = 0; i < st.Length - 3; i++) { - if(st[i + 2] == st[i + 1] && st[i] == st[i + 3] && st[i] != st[i + 2]) + IEnumerable<string> Abba(string st) { + for (var i = 0; i < st.Length - 3; i++) { + if(st[i + 2] == st[i + 1] && st[i] == st[i + 3] && st[i] != st[i + 2]) yield return st.Substring(i, 4); } } - IEnumerable Aba(string st) { - for (var i = 0; i < st.Length -2; i++) { - if(st[i] == st[i + 2] && st[i] != st[i + 1]) + IEnumerable<string> Aba(string st) { + for (var i = 0; i < st.Length -2; i++) { + if(st[i] == st[i + 2] && st[i] != st[i + 1]) yield return st.Substring(i, 3); } } diff --git a/2016/8/index.html b/2016/8/index.html index 59157d97..acac0631 100644 --- a/2016/8/index.html +++ b/2016/8/index.html @@ -285,7 +285,7 @@

Two-Factor Authentication

namespace AdventOfCode.Y2016.Day08; -[ProblemName("Two-Factor Authentication")] +[ProblemName("Two-Factor Authentication")] class Solution : Solver { public object PartOne(string input) { @@ -300,12 +300,12 @@

Two-Factor Authentication

public object PartTwo(string input) { var mtx = Execute(input); - var res = ""; + var res = ""; foreach (var irow in Enumerable.Range(0, mtx.GetLength(0))) { foreach (var icol in Enumerable.Range(0, mtx.GetLength(1))) { - res += mtx[irow, icol] ? "#" : " "; + res += mtx[irow, icol] ? "#" : " "; } - res += "\n"; + res += "\n"; } return res.Ocr(); } @@ -313,28 +313,28 @@

Two-Factor Authentication

bool[,] Execute(string input) { var (crow, ccol) = (6, 50); var mtx = new bool[crow, ccol]; - foreach (var line in input.Split('\n')) { - if (Match(line, @"rect (\d+)x(\d+)", out var m)) { + foreach (var line in input.Split('\n')) { + if (Match(line, @"rect (\d+)x(\d+)", out var m)) { var (ccolT, crowT) = (int.Parse(m[0]), int.Parse(m[1])); - for (var irow = 0; irow < crowT; irow++) { - for (var icol = 0; icol < ccolT; icol++) { + for (var irow = 0; irow < crowT; irow++) { + for (var icol = 0; icol < ccolT; icol++) { mtx[irow, icol] = true; } } - } else if (Match(line, @"rotate row y=(\d+) by (\d+)", out m)) { + } else if (Match(line, @"rotate row y=(\d+) by (\d+)", out m)) { var (irow, d) = (int.Parse(m[0]), int.Parse(m[1])); - for (int i = 0; i < d; i++) { + for (int i = 0; i < d; i++) { var t = mtx[irow, ccol - 1]; - for (var icol = ccol - 1; icol >= 1; icol--) { + for (var icol = ccol - 1; icol >= 1; icol--) { mtx[irow, icol] = mtx[irow, icol - 1]; } mtx[irow, 0] = t; } - } else if (Match(line, @"rotate column x=(\d+) by (\d+)", out m)) { + } else if (Match(line, @"rotate column x=(\d+) by (\d+)", out m)) { var (icol, d) = (int.Parse(m[0]), int.Parse(m[1])); - for (int i = 0; i < d; i++) { + for (int i = 0; i < d; i++) { var t = mtx[crow - 1, icol]; - for (var irow = crow - 1; irow >= 1; irow--) { + for (var irow = crow - 1; irow >= 1; irow--) { mtx[irow, icol] = mtx[irow - 1, icol]; } mtx[0, icol] = t; @@ -348,7 +348,7 @@

Two-Factor Authentication

var match = Regex.Match(stm, pattern); m = null; if (match.Success) { - m = match.Groups.Cast().Skip(1).Select(g => g.Value).ToArray(); + m = match.Groups.Cast<Group>().Skip(1).Select(g => g.Value).ToArray(); return true; } else { return false; diff --git a/2016/9/index.html b/2016/9/index.html index fb5bd6c1..9e9eb9ed 100644 --- a/2016/9/index.html +++ b/2016/9/index.html @@ -283,7 +283,7 @@

Explosives in Cyberspace

namespace AdventOfCode.Y2016.Day09; -[ProblemName("Explosives in Cyberspace")] +[ProblemName("Explosives in Cyberspace")] class Solution : Solver { public object PartOne(string input) { @@ -296,10 +296,10 @@

Explosives in Cyberspace

long Expand(string input, int i, int lim, bool recursive) { var res = 0L; - while (i < lim) { - if (input[i] == '(') { - var j = input.IndexOf(')', i + 1); - var m = Regex.Match(input.Substring(i + 1, j - i - 1), @"(\d+)x(\d+)"); + while (i < lim) { + if (input[i] == '(') { + var j = input.IndexOf(')', i + 1); + var m = Regex.Match(input.Substring(i + 1, j - i - 1), @"(\d+)x(\d+)"); var length = int.Parse(m.Groups[1].Value); var mul = int.Parse(m.Groups[2].Value); res += recursive ? Expand(input, j + 1, j + length + 1, recursive) * mul : length * mul; diff --git a/2017/1/index.html b/2017/1/index.html index 9cd85e81..44529efd 100644 --- a/2017/1/index.html +++ b/2017/1/index.html @@ -283,12 +283,12 @@

Inverse Captcha

namespace AdventOfCode.Y2017.Day01; -[ProblemName("Inverse Captcha")] +[ProblemName("Inverse Captcha")] class Solution : Solver { - public object PartOne(string input) => InverseCaptcha(input, 1); + public object PartOne(string input) => InverseCaptcha(input, 1); - public object PartTwo(string input) => InverseCaptcha(input, input.Length / 2); + public object PartTwo(string input) => InverseCaptcha(input, input.Length / 2); int InverseCaptcha(string input, int skip) { return ( diff --git a/2017/10/index.html b/2017/10/index.html index c6c19c22..624e14ec 100644 --- a/2017/10/index.html +++ b/2017/10/index.html @@ -284,35 +284,35 @@

Knot Hash

namespace AdventOfCode.Y2017.Day10; -[ProblemName("Knot Hash")] +[ProblemName("Knot Hash")] class Solution : Solver { public object PartOne(string input) { - var chars = input.Split(',').Select(int.Parse); + var chars = input.Split(',').Select(int.Parse); var hash = KnotHash(chars, 1); return hash[0] * hash[1]; } public object PartTwo(string input) { var suffix = new [] { 17, 31, 73, 47, 23 }; - var chars = input.ToCharArray().Select(b => (int)b).Concat(suffix); + var chars = input.ToCharArray().Select(b => (int)b).Concat(suffix); var hash = KnotHash(chars, 64); - return string.Join("", + return string.Join("", from blockIdx in Enumerable.Range(0, 16) let block = hash.Skip(16 * blockIdx).Take(16) - select block.Aggregate(0, (acc, ch) => acc ^ ch).ToString("x2")); + select block.Aggregate(0, (acc, ch) => acc ^ ch).ToString("x2")); } - int[] KnotHash(IEnumerable input, int rounds) { + int[] KnotHash(IEnumerable<int> input, int rounds) { var output = Enumerable.Range(0, 256).ToArray(); var current = 0; var skip = 0; - for (var round = 0; round < rounds; round++) { + for (var round = 0; round < rounds; round++) { foreach (var len in input) { - for (int i = 0; i < len / 2; i++) { + for (int i = 0; i < len / 2; i++) { var from = (current + i) % output.Length; var to = (current + len - 1 - i) % output.Length; (output[from], output[to]) = (output[to], output[from]); diff --git a/2017/11/index.html b/2017/11/index.html index 8a22275e..0eaca413 100644 --- a/2017/11/index.html +++ b/2017/11/index.html @@ -285,26 +285,26 @@

Hex Ed

namespace AdventOfCode.Y2017.Day11; -[ProblemName("Hex Ed")] +[ProblemName("Hex Ed")] class Solution : Solver { - public object PartOne(string input) => Distances(input).Last(); + public object PartOne(string input) => Distances(input).Last(); - public object PartTwo(string input) => Distances(input).Max(); + public object PartTwo(string input) => Distances(input).Max(); - IEnumerable Distances(string input) => + IEnumerable<int> Distances(string input) => from w in Wander(input) select (Math.Abs(w.x) + Math.Abs(w.y) + Math.Abs(w.z))/2; - IEnumerable<(int x, int y, int z)> Wander(string input) { + IEnumerable<(int x, int y, int z)> Wander(string input) { var (x, y, z) = (0, 0, 0); - foreach (var dir in input.Split(',')) { + foreach (var dir in input.Split(',')) { switch (dir) { - case "n": (x, y, z) = (x + 0, y + 1, z - 1); break; - case "ne": (x, y, z) = (x + 1, y + 0, z - 1); break; - case "se": (x, y, z) = (x + 1, y - 1, z + 0); break; - case "s": (x, y, z) = (x + 0, y - 1, z + 1); break; - case "sw": (x, y, z) = (x - 1, y + 0, z + 1); break; - case "nw": (x, y, z) = (x - 1, y + 1, z + 0); break; + case "n": (x, y, z) = (x + 0, y + 1, z - 1); break; + case "ne": (x, y, z) = (x + 1, y + 0, z - 1); break; + case "se": (x, y, z) = (x + 1, y - 1, z + 0); break; + case "s": (x, y, z) = (x + 0, y - 1, z + 1); break; + case "sw": (x, y, z) = (x - 1, y + 0, z + 1); break; + case "nw": (x, y, z) = (x - 1, y + 1, z + 0); break; default: throw new ArgumentException(dir); } yield return (x, y, z); diff --git a/2017/12/index.html b/2017/12/index.html index 4de99df5..0d2515f1 100644 --- a/2017/12/index.html +++ b/2017/12/index.html @@ -287,18 +287,18 @@

Digital Plumber

class Node { public string Id; - public List Neighbours; + public List<string> Neighbours; } -[ProblemName("Digital Plumber")] +[ProblemName("Digital Plumber")] class Solution : Solver { - public object PartOne(string input) => GetPartitions(input).Single(x => x.Contains("0")).Count(); - public object PartTwo(string input) => GetPartitions(input).Count(); + public object PartOne(string input) => GetPartitions(input).Single(x => x.Contains("0")).Count(); + public object PartTwo(string input) => GetPartitions(input).Count(); - IEnumerable> GetPartitions(string input) { + IEnumerable<HashSet<string>> GetPartitions(string input) { var nodes = Parse(input); - var parent = new Dictionary(); + var parent = new Dictionary<string, string>(); string getRoot(string id) { var root = id; @@ -322,17 +322,17 @@

Digital Plumber

from node in nodes let root = getRoot(node.Id) group node.Id by root into partitions - select new HashSet(partitions.ToArray()); + select new HashSet<string>(partitions.ToArray()); } - List Parse(string input) { + List<Node> Parse(string input) { return ( - from line in input.Split('\n') - let parts = Regex.Split(line, " <-> ") + from line in input.Split('\n') + let parts = Regex.Split(line, " <-> ") select new Node() { Id = parts[0], - Neighbours = new List(Regex.Split(parts[1], ", ")) + Neighbours = new List<string>(Regex.Split(parts[1], ", ")) } ).ToList(); } diff --git a/2017/13/index.html b/2017/13/index.html index c985cdce..68dc9cfd 100644 --- a/2017/13/index.html +++ b/2017/13/index.html @@ -285,31 +285,31 @@

Packet Scanners

namespace AdventOfCode.Y2017.Day13; -class Layers : List<(int depth, int range)> { - public Layers(IEnumerable<(int depth, int range)> layers) : base(layers) { +class Layers : List<(int depth, int range)> { + public Layers(IEnumerable<(int depth, int range)> layers) : base(layers) { } } -[ProblemName("Packet Scanners")] +[ProblemName("Packet Scanners")] class Solution : Solver { - public object PartOne(string input) => Severities(Parse(input), 0).Sum(); + public object PartOne(string input) => Severities(Parse(input), 0).Sum(); public object PartTwo(string input) { var layers = Parse(input); return Enumerable .Range(0, int.MaxValue) - .First(n => !Severities(layers, n).Any()); + .First(n => !Severities(layers, n).Any()); } - Layers Parse(string input) => + Layers Parse(string input) => new Layers( - from line in input.Split('\n') - let parts = Regex.Split(line, ": ").Select(int.Parse).ToArray() + from line in input.Split('\n') + let parts = Regex.Split(line, ": ").Select(int.Parse).ToArray() select (parts[0], parts[1]) ); - IEnumerable Severities(Layers layers, int t) { + IEnumerable<int> Severities(Layers layers, int t) { var packetPos = 0; foreach (var layer in layers) { t += layer.depth - packetPos; diff --git a/2017/14/index.html b/2017/14/index.html index 5dcdc02a..01205e9e 100644 --- a/2017/14/index.html +++ b/2017/14/index.html @@ -285,17 +285,17 @@

Disk Defragmentation

namespace AdventOfCode.Y2017.Day14; -[ProblemName("Disk Defragmentation")] +[ProblemName("Disk Defragmentation")] class Solution : Solver { - public object PartOne(string input) => Extract(input).Select(row => row.Count(ch => ch == '#')).Sum(); + public object PartOne(string input) => Extract(input).Select(row => row.Count(ch => ch == '#')).Sum(); public object PartTwo(string input) { - var mtx = Extract(input).Select(row => row.ToCharArray()).ToArray(); + var mtx = Extract(input).Select(row => row.ToCharArray()).ToArray(); var regions = 0; - for (int irow = 0; irow < mtx.Count(); irow++) { - for (int icol = 0; icol < mtx[0].Count(); icol++) { - if (mtx[irow][icol] == '#') { + for (int irow = 0; irow < mtx.Count(); irow++) { + for (int icol = 0; icol < mtx[0].Count(); icol++) { + if (mtx[irow][icol] == '#') { regions++; Fill(mtx, (irow, icol)); } @@ -305,14 +305,14 @@

Disk Defragmentation

} void Fill(char[][] mtx, (int, int) startCell) { - var q = new Queue<(int irow, int icol)>(); + var q = new Queue<(int irow, int icol)>(); var ccol = mtx[0].Count(); var crow = mtx.Count(); q.Enqueue(startCell); while (q.Any()) { var (irowCurrent, icolCurrent) = q.Dequeue(); - mtx[irowCurrent][icolCurrent] = ' '; + mtx[irowCurrent][icolCurrent] = ' '; var neighbourCells = from drow in new[] { -1, 0, 1 } @@ -322,11 +322,11 @@

Disk Defragmentation

let icolNeighbour = icolCurrent + dcol let irowNeighbour = irowCurrent + drow - where icolNeighbour >= 0 && - icolNeighbour < ccol && - irowNeighbour >= 0 && - irowNeighbour < crow && - mtx[irowNeighbour][icolNeighbour] == '#' + where icolNeighbour >= 0 && + icolNeighbour < ccol && + irowNeighbour >= 0 && + irowNeighbour < crow && + mtx[irowNeighbour][icolNeighbour] == '#' select (irowNeighbour, icolNeighbour); @@ -336,16 +336,16 @@

Disk Defragmentation

} } - IEnumerable Extract(string input) { - for (var irow = 0; irow < 128; irow++) { - var row = ""; - foreach (var n in KnotHash(input + "-" + irow)) { + IEnumerable<string> Extract(string input) { + for (var irow = 0; irow < 128; irow++) { + var row = ""; + foreach (var n in KnotHash(input + "-" + irow)) { var m = n; - for (var bit = 0; bit < 8; bit++) { - if ((m & (1 << (7 - bit))) != 0) { - row += "#"; + for (var bit = 0; bit < 8; bit++) { + if ((m & (1 << (7 - bit))) != 0) { + row += "#"; } else { - row += "."; + row += "."; } } } @@ -355,14 +355,14 @@

Disk Defragmentation

int[] KnotHash(string input) { var suffix = new[] { 17, 31, 73, 47, 23 }; - var chars = input.ToCharArray().Select(b => (int)b).Concat(suffix); + var chars = input.ToCharArray().Select(b => (int)b).Concat(suffix); var output = Enumerable.Range(0, 256).ToArray(); var current = 0; var skip = 0; - for (var round = 0; round < 64; round++) { + for (var round = 0; round < 64; round++) { foreach (var len in chars) { - for (int i = 0; i < len / 2; i++) { + for (int i = 0; i < len / 2; i++) { var from = (current + i) % output.Length; var to = (current + len - 1 - i) % output.Length; (output[from], output[to]) = (output[to], output[from]); @@ -375,7 +375,7 @@

Disk Defragmentation

return ( from blockIdx in Enumerable.Range(0, 16) let block = hash.Skip(16 * blockIdx).Take(16) - select block.Aggregate(0, (acc, ch) => acc ^ ch) + select block.Aggregate(0, (acc, ch) => acc ^ ch) ).ToArray(); } } diff --git a/2017/15/index.html b/2017/15/index.html index d86347e7..58edbda1 100644 --- a/2017/15/index.html +++ b/2017/15/index.html @@ -284,32 +284,32 @@

Dueling Generators

namespace AdventOfCode.Y2017.Day15; -[ProblemName("Dueling Generators")] +[ProblemName("Dueling Generators")] class Solution : Solver { - public object PartOne(string input) => + public object PartOne(string input) => MatchCount(Combine(ParseGenerators(input)).Take(40000000)); public object PartTwo(string input) { var generators = ParseGenerators(input); - return MatchCount(Combine((generators.a.Where(a => (a & 3) == 0), generators.b.Where(a => (a & 7) == 0))).Take(5000000)); + return MatchCount(Combine((generators.a.Where(a => (a & 3) == 0), generators.b.Where(a => (a & 7) == 0))).Take(5000000)); } - IEnumerable<(long, long)> Combine((IEnumerable a, IEnumerable b) items) => - Enumerable.Zip(items.a, items.b, (a, b) => (a, b)); + IEnumerable<(long, long)> Combine((IEnumerable<long> a, IEnumerable<long> b) items) => + Enumerable.Zip(items.a, items.b, (a, b) => (a, b)); - int MatchCount(IEnumerable<(long a, long b)> items) => - items.Count(item => (item.a & 0xffff) == (item.b & 0xffff)); + int MatchCount(IEnumerable<(long a, long b)> items) => + items.Count(item => (item.a & 0xffff) == (item.b & 0xffff)); - (IEnumerable a, IEnumerable b) ParseGenerators(string input) { - var lines = input.Split('\n'); - var startA = int.Parse(lines[0].Substring("Generator A starts with ".Length)); - var startB = int.Parse(lines[1].Substring("Generator B starts with ".Length)); + (IEnumerable<long> a, IEnumerable<long> b) ParseGenerators(string input) { + var lines = input.Split('\n'); + var startA = int.Parse(lines[0].Substring("Generator A starts with ".Length)); + var startB = int.Parse(lines[1].Substring("Generator B starts with ".Length)); return (Generator(startA, 16807), Generator(startB, 48271)); } - IEnumerable Generator(int start, int mul) { + IEnumerable<long> Generator(int start, int mul) { var mod = 2147483647; long state = start; diff --git a/2017/16/index.html b/2017/16/index.html index 3ccf4e4d..0d9e41cb 100644 --- a/2017/16/index.html +++ b/2017/16/index.html @@ -286,27 +286,27 @@

Permutation Promenade

namespace AdventOfCode.Y2017.Day16; -[ProblemName("Permutation Promenade")] +[ProblemName("Permutation Promenade")] class Solution : Solver { public object PartOne(string input) { - return ParseStep(input)("abcdefghijklmnop"); + return ParseStep(input)("abcdefghijklmnop"); } public object PartTwo(string input) { var step = ParseStep(input); - var startState = "abcdefghijklmnop"; + var startState = "abcdefghijklmnop"; var mod = Mod(step, startState); var state = startState; - for (int i = 0; i < 1000000000 % mod; i++) { + for (int i = 0; i < 1000000000 % mod; i++) { state = step(state); } return state; } - int Mod(Func step, string startState) { + int Mod(Func<string, string> step, string startState) { var state = startState; for (int i = 0; ; i++) { state = step(state); @@ -316,49 +316,49 @@

Permutation Promenade

} } - Func ParseStep(string input) { + Func<string, string> ParseStep(string input) { var moves = ( - from stm in input.Split(',') + from stm in input.Split(',') select - ParseMove(stm, "s([0-9]+)", m => { + ParseMove(stm, "s([0-9]+)", m => { int n = int.Parse(m[0]); - return (order) => { + return (order) => { return order.Skip(order.Count - n).Concat(order.Take(order.Count - n)).ToList(); }; }) ?? - ParseMove(stm, "x([0-9]+)/([0-9]+)", m => { + ParseMove(stm, "x([0-9]+)/([0-9]+)", m => { int idx1 = int.Parse(m[0]); int idx2 = int.Parse(m[1]); - return (order) => { + return (order) => { (order[idx1], order[idx2]) = (order[idx2], order[idx1]); return order; }; }) ?? - ParseMove(stm, "p([a-z])/([a-z])", m => { + ParseMove(stm, "p([a-z])/([a-z])", m => { var (c1, c2) = (m[0].Single(), m[1].Single()); - return order => { + return order => { var (idx1, idx2) = (order.IndexOf(c1), order.IndexOf(c2)); order[idx1] = c2; order[idx2] = c1; return order; }; }) ?? - throw new Exception("Cannot parse " + stm) + throw new Exception("Cannot parse " + stm) ).ToArray(); - return startOrder => { + return startOrder => { var order = startOrder.ToList(); foreach (var move in moves) { order = move(order); } - return string.Join("", order); + return string.Join("", order); }; } - Func, List> ParseMove(string stm, string pattern, Func, List>> a) { + Func<List<char>, List<char>> ParseMove(string stm, string pattern, Func<string[], Func<List<char>, List<char>>> a) { var match = Regex.Match(stm , pattern); if (match.Success) { - return a(match.Groups.Cast().Skip(1).Select(g => g.Value).ToArray()); + return a(match.Groups.Cast<Group>().Skip(1).Select(g => g.Value).ToArray()); } else { return null; } diff --git a/2017/17/index.html b/2017/17/index.html index 7914875c..daa858eb 100644 --- a/2017/17/index.html +++ b/2017/17/index.html @@ -283,14 +283,14 @@

Spinlock

namespace AdventOfCode.Y2017.Day17; -[ProblemName("Spinlock")] +[ProblemName("Spinlock")] class Solution : Solver { public object PartOne(string input) { var step = int.Parse(input); - var nums = new List() { 0 }; + var nums = new List<int>() { 0 }; var pos = 0; - for (int i = 1; i < 2018; i++) { + for (int i = 1; i < 2018; i++) { pos = (pos + step) % nums.Count + 1; nums.Insert(pos, i); } @@ -302,7 +302,7 @@

Spinlock

var pos = 0; var numsCount = 1; var res = 0; - for (int i = 1; i < 50000001; i++) { + for (int i = 1; i < 50000001; i++) { pos = (pos + step) % numsCount + 1; if (pos == 1) { res = i; diff --git a/2017/18/index.html b/2017/18/index.html index 6326b98a..9a8230bd 100644 --- a/2017/18/index.html +++ b/2017/18/index.html @@ -285,30 +285,30 @@

Duet

namespace AdventOfCode.Y2017.Day18; -[ProblemName("Duet")] +[ProblemName("Duet")] class Solution : Solver { - public object PartOne(string input) => + public object PartOne(string input) => new Machine1() .Execute(input) - .First(received => received != null).Value; + .First(received => received != null).Value; public object PartTwo(string input) { - var p0Input = new Queue(); - var p1Input = new Queue(); + var p0Input = new Queue<long>(); + var p1Input = new Queue<long>(); return Enumerable .Zip( new Machine2(0, p0Input, p1Input).Execute(input), new Machine2(1, p1Input, p0Input).Execute(input), - (state0, state1) => (state0: state0, state1: state1)) - .First(x => !x.state0.running && !x.state1.running) + (state0, state1) => (state0: state0, state1: state1)) + .First(x => !x.state0.running && !x.state1.running) .state1.valueSent; } } -abstract class Machine { - private Dictionary regs = new Dictionary(); +abstract class Machine<TState> { + private Dictionary<string, long> regs = new Dictionary<string, long>(); protected bool running; protected int ip = 0; @@ -323,22 +323,22 @@

Duet

} } - public IEnumerable Execute(string input) { - var prog = input.Split('\n').ToArray(); + public IEnumerable<TState> Execute(string input) { + var prog = input.Split('\n').ToArray(); - while (ip >= 0 && ip < prog.Length) { + while (ip >= 0 && ip < prog.Length) { running = true; var line = prog[ip]; - var parts = line.Split(' '); + var parts = line.Split(' '); switch (parts[0]) { - case "snd": snd(parts[1]); break; - case "rcv": rcv(parts[1]); break; - case "set": set(parts[1], parts[2]); break; - case "add": add(parts[1], parts[2]); break; - case "mul": mul(parts[1], parts[2]); break; - case "mod": mod(parts[1], parts[2]); break; - case "jgz": jgz(parts[1], parts[2]); break; - default: throw new Exception("Cannot parse " + line); + case "snd": snd(parts[1]); break; + case "rcv": rcv(parts[1]); break; + case "set": set(parts[1], parts[2]); break; + case "add": add(parts[1], parts[2]); break; + case "mul": mul(parts[1], parts[2]); break; + case "mod": mod(parts[1], parts[2]); break; + case "jgz": jgz(parts[1], parts[2]); break; + default: throw new Exception("Cannot parse " + line); } yield return State(); } @@ -374,11 +374,11 @@

Duet

} protected void jgz(string reg0, string reg1) { - ip += this[reg0] > 0 ? (int)this[reg1] : 1; + ip += this[reg0] > 0 ? (int)this[reg1] : 1; } } -class Machine1 : Machine { +class Machine1 : Machine<long?> { private long? sent = null; private long? received = null; @@ -400,13 +400,13 @@

Duet

} -class Machine2 : Machine<(bool running, int valueSent)> { +class Machine2 : Machine<(bool running, int valueSent)> { private int valueSent = 0; - private Queue qIn; - private Queue qOut; + private Queue<long> qIn; + private Queue<long> qOut; - public Machine2(long p, Queue qIn, Queue qOut) { - this["p"] = p; + public Machine2(long p, Queue<long> qIn, Queue<long> qOut) { + this["p"] = p; this.qIn = qIn; this.qOut = qOut; } diff --git a/2017/19/index.html b/2017/19/index.html index ac9e9ded..0ad31c66 100644 --- a/2017/19/index.html +++ b/2017/19/index.html @@ -283,20 +283,20 @@

A Series of Tubes

namespace AdventOfCode.Y2017.Day19; -[ProblemName("A Series of Tubes")] +[ProblemName("A Series of Tubes")] class Solution : Solver { - public object PartOne(string input) => FollowPath(input).msg; + public object PartOne(string input) => FollowPath(input).msg; - public object PartTwo(string input) => FollowPath(input).steps; + public object PartTwo(string input) => FollowPath(input).steps; (string msg, int steps) FollowPath(string input){ - var map = input.Split('\n'); + var map = input.Split('\n'); var (ccol, crow) = (map[0].Length, map.Length); - var (icol, irow) = (map[0].IndexOf('|'), 0); + var (icol, irow) = (map[0].IndexOf('|'), 0); var (dcol, drow) = (0, 1); - var msg = ""; + var msg = ""; var steps = 0; while (true) { @@ -304,21 +304,21 @@

A Series of Tubes

icol += dcol; steps++; - if (icol < 0 || icol >= ccol || irow < 0 || irow >= crow || map[irow][icol] == ' ') { + if (icol < 0 || icol >= ccol || irow < 0 || irow >= crow || map[irow][icol] == ' ') { break; } switch (map[irow][icol]) { - case '+': + case '+': (dcol, drow) = ( from q in new[] { (drow: dcol, dcol: -drow), (drow: -dcol, dcol: drow)} let icolT = icol + q.dcol let irowT = irow + q.drow - where icolT >= 0 && icolT < ccol && irowT >= 0 && irowT < crow && map[irowT][icolT] != ' ' + where icolT >= 0 && icolT < ccol && irowT >= 0 && irowT < crow && map[irowT][icolT] != ' ' select (q.dcol, q.drow) ).Single(); break; - case char ch when (ch >= 'A' && ch <= 'Z'): + case char ch when (ch >= 'A' && ch <= 'Z'): msg += ch; break; } diff --git a/2017/2/index.html b/2017/2/index.html index 5f2c4677..107da96a 100644 --- a/2017/2/index.html +++ b/2017/2/index.html @@ -283,24 +283,24 @@

Corruption Checksum

namespace AdventOfCode.Y2017.Day02; -[ProblemName("Corruption Checksum")] +[ProblemName("Corruption Checksum")] class Solution : Solver { public object PartOne(string input) { return ( - from line in input.Split('\n') - let numbers = line.Split('\t').Select(int.Parse) + from line in input.Split('\n') + let numbers = line.Split('\t').Select(int.Parse) select numbers.Max() - numbers.Min() ).Sum(); } public object PartTwo(string input) { return ( - from line in input.Split('\n') - let numbers = line.Split('\t').Select(int.Parse) + from line in input.Split('\n') + let numbers = line.Split('\t').Select(int.Parse) from a in numbers from b in numbers - where a > b && a % b == 0 + where a > b && a % b == 0 select a / b ).Sum(); } diff --git a/2017/20/index.html b/2017/20/index.html index c58f917f..a6916fd6 100644 --- a/2017/20/index.html +++ b/2017/20/index.html @@ -286,7 +286,7 @@

Particle Swarm

namespace AdventOfCode.Y2017.Day20; -[ProblemName("Particle Swarm")] +[ProblemName("Particle Swarm")] class Solution : Solver { public object PartOne(string input) { @@ -310,22 +310,22 @@

Particle Swarm

var T = collisionTimes.Max(); var t = 0; - while (t <= T) { + while (t <= T) { var particlesByPos = (from particle in particles orderby particle.pos.x, particle.pos.y, particle.pos.z select particle).ToArray(); var particlePrev = particlesByPos[0]; - for (int i = 1; i < particlesByPos.Length; i++) { + for (int i = 1; i < particlesByPos.Length; i++) { var particle = particlesByPos[i]; - if (particlePrev.pos.x == particle.pos.x && particlePrev.pos.y == particle.pos.y && particlePrev.pos.z == particle.pos.z) { + if (particlePrev.pos.x == particle.pos.x && particlePrev.pos.y == particle.pos.y && particlePrev.pos.z == particle.pos.z) { particlePrev.destroyed = true; particle.destroyed = true; } particlePrev = particle; } - if (particles.Any(p => p.destroyed)) { - particles = particles.Where(particle => !particle.destroyed).ToList(); + if (particles.Any(p => p.destroyed)) { + particles = particles.Where(particle => !particle.destroyed).ToList(); } foreach (var particle in particles) { @@ -338,11 +338,11 @@

Particle Swarm

} - List Parse(string input) { - var lines = input.Split('\n'); + List<Particle> Parse(string input) { + var lines = input.Split('\n'); return ( - from q in Enumerable.Zip(lines, Enumerable.Range(0, int.MaxValue), (line, i) => (i: i, line: line)) - let nums = Regex.Matches(q.line, "-?[0-9]+").Select(m => int.Parse(m.Value)).ToArray() + from q in Enumerable.Zip(lines, Enumerable.Range(0, int.MaxValue), (line, i) => (i: i, line: line)) + let nums = Regex.Matches(q.line, "-?[0-9]+").Select(m => int.Parse(m.Value)).ToArray() let p = new Point(nums[0], nums[1], nums[2]) let v = new Point(nums[3], nums[4], nums[5]) let a = new Point(nums[6], nums[7], nums[8]) @@ -356,7 +356,7 @@

Particle Swarm

public int y; public int z; - public int Len() => Math.Abs(x) + Math.Abs(y) + Math.Abs(z); + public int Len() => Math.Abs(x) + Math.Abs(y) + Math.Abs(z); public Point(int x, int y, int z) { this.x = x; @@ -385,19 +385,19 @@

Particle Swarm

(pos.x, pos.y, pos.z) = (pos.x + vel.x, pos.y + vel.y, pos.z + vel.z); } - public IEnumerable CollisionTime(Particle particle) { + public IEnumerable<int> CollisionTime(Particle particle) { return from tx in CollisionTimeOnAxis(particle.acc.x - acc.x, particle.vel.x - vel.x, particle.pos.x - pos.x) from ty in CollisionTimeOnAxis(particle.acc.y - acc.y, particle.vel.y - vel.y, particle.pos.y - pos.y) from tz in CollisionTimeOnAxis(particle.acc.z - acc.x, particle.vel.z - vel.z, particle.pos.z - pos.z) - where tx == ty && ty == tz + where tx == ty && ty == tz select (tx); } - private IEnumerable CollisionTimeOnAxis(int da, int dv, int dp) => + private IEnumerable<int> CollisionTimeOnAxis(int da, int dv, int dp) => SolveIntEq(da / 2, dv, dp); - private IEnumerable SolveIntEq(int a, int b, int c) { + private IEnumerable<int> SolveIntEq(int a, int b, int c) { if (a == 0) { if (b == 0) { if (c == 0) { @@ -410,7 +410,7 @@

Particle Swarm

var d = b * b - 4 * a * c; if (d == 0) { yield return -b / (2 * a); - } else if (d > 0) { + } else if (d > 0) { var ds = Math.Sqrt(d); if (ds * ds == d) { yield return (int)((-b + ds) / (2 * a)); diff --git a/2017/21/index.html b/2017/21/index.html index 4150ecfe..e6cdfe8d 100644 --- a/2017/21/index.html +++ b/2017/21/index.html @@ -287,17 +287,17 @@

Fractal Art

namespace AdventOfCode.Y2017.Day21; -[ProblemName("Fractal Art")] +[ProblemName("Fractal Art")] class Solution : Solver { - public object PartOne(string input) => Iterate(input, 5); + public object PartOne(string input) => Iterate(input, 5); - public object PartTwo(string input) => Iterate(input, 18); + public object PartTwo(string input) => Iterate(input, 18); int Iterate(string input, int iterations) { - var mtx = Mtx.FromString(".#./..#/###"); + var mtx = Mtx.FromString(".#./..#/###"); var ruleset = new RuleSet(input); - for (var i = 0; i < iterations; i++) { + for (var i = 0; i < iterations; i++) { mtx = ruleset.Apply(mtx); } return mtx.Count(); @@ -305,15 +305,15 @@

Fractal Art

} class RuleSet { - private Dictionary rules2; - private Dictionary rules3; + private Dictionary<int, Mtx> rules2; + private Dictionary<int, Mtx> rules3; public RuleSet(string input) { - rules2 = new Dictionary(); - rules3 = new Dictionary(); + rules2 = new Dictionary<int, Mtx>(); + rules3 = new Dictionary<int, Mtx>(); - foreach (var line in input.Split('\n')) { - var parts = Regex.Split(line, " => "); + foreach (var line in input.Split('\n')) { + var parts = Regex.Split(line, " => "); var left = parts[0]; var right = parts[1]; var rules = @@ -336,9 +336,9 @@

Fractal Art

).ToArray()); } - IEnumerable Variations(Mtx mtx) { - for (int j = 0; j < 2; j++) { - for (int i = 0; i < 4; i++) { + IEnumerable<Mtx> Variations(Mtx mtx) { + for (int j = 0; j < 2; j++) { + for (int i = 0; i < 4; i++) { yield return mtx; mtx = mtx.Rotate(); } @@ -357,14 +357,14 @@

Fractal Art

public int CodeNumber { get { - if (Size != 2 && Size != 3) { + if (Size != 2 && Size != 3) { throw new ArgumentException(); } var i = 0; - for (int irow = 0; irow < Size; irow++) { - for (int icol = 0; icol < Size; icol++) { + for (int irow = 0; irow < Size; irow++) { + for (int icol = 0; icol < Size; icol++) { if (this[irow, icol]) { - i |= (1 << (irow * Size + icol)); + i |= (1 << (irow * Size + icol)); } } } @@ -378,11 +378,11 @@

Fractal Art

} public static Mtx FromString(string st) { - st = st.Replace("/", ""); + st = st.Replace("/", ""); var size = (int)Math.Sqrt(st.Length); var res = new Mtx(size); - for (int i = 0; i < st.Length; i++) { - res[i / size, i % size] = st[i] == '#'; + for (int i = 0; i < st.Length; i++) { + res[i / size, i % size] = st[i] == '#'; } return res; } @@ -390,10 +390,10 @@

Fractal Art

public static Mtx Join(Mtx[] rgmtx) { var mtxPerRow = (int)Math.Sqrt(rgmtx.Length); var res = new Mtx(mtxPerRow * rgmtx[0].Size); - for (int imtx = 0; imtx < rgmtx.Length; imtx++) { + for (int imtx = 0; imtx < rgmtx.Length; imtx++) { var mtx = rgmtx[imtx]; - for (int irow = 0; irow < mtx.Size; irow++) { - for (int icol = 0; icol < mtx.Size; icol++) { + for (int irow = 0; irow < mtx.Size; irow++) { + for (int icol = 0; icol < mtx.Size; icol++) { var irowRes = (imtx / mtxPerRow) * mtx.Size + irow; var icolRes = (imtx % mtxPerRow) * mtx.Size + icol; res[irowRes, icolRes] = mtx[irow, icol]; @@ -404,18 +404,18 @@

Fractal Art

return res; } - public IEnumerable Split() { + public IEnumerable<Mtx> Split() { var blockSize = Size % 2 == 0 ? 2 : Size % 3 == 0 ? 3 : throw new Exception(); - for (int irow = 0; irow < Size; irow += blockSize) { - for (int icol = 0; icol < Size; icol += blockSize) { + for (int irow = 0; irow < Size; irow += blockSize) { + for (int icol = 0; icol < Size; icol += blockSize) { var mtx = new Mtx(blockSize); - for (int drow = 0; drow < blockSize; drow++) { - for (int dcol = 0; dcol < blockSize; dcol++) { + for (int drow = 0; drow < blockSize; drow++) { + for (int dcol = 0; dcol < blockSize; dcol++) { mtx[drow, dcol] = this[irow + drow, icol + dcol]; } } @@ -426,8 +426,8 @@

Fractal Art

public Mtx Flip() { var res = new Mtx(this.Size); - for (int irow = 0; irow < Size; irow++) { - for (int icol = 0; icol < Size; icol++) { + for (int irow = 0; irow < Size; irow++) { + for (int icol = 0; icol < Size; icol++) { res[irow, Size - icol - 1] = this[irow, icol]; } } @@ -436,8 +436,8 @@

Fractal Art

public Mtx Rotate() { var res = new Mtx(this.Size); - for (int i = 0; i < Size; i++) { - for (int j = 0; j < Size; j++) { + for (int i = 0; i < Size; i++) { + for (int j = 0; j < Size; j++) { res[i, j] = this[j, Size - i - 1]; } } @@ -446,8 +446,8 @@

Fractal Art

public int Count() { var count = 0; - for (int irow = 0; irow < Size; irow++) { - for (int icol = 0; icol < Size; icol++) { + for (int irow = 0; irow < Size; irow++) { + for (int icol = 0; icol < Size; icol++) { if (this[irow, icol]) { count++; } @@ -458,9 +458,9 @@

Fractal Art

public override string ToString() { var sb = new StringBuilder(); - for (int irow = 0; irow < Size; irow++) { - for (int icol = 0; icol < Size; icol++) { - sb.Append(this[irow, icol] ? "#" : "."); + for (int irow = 0; irow < Size; irow++) { + for (int icol = 0; icol < Size; icol++) { + sb.Append(this[irow, icol] ? "#" : "."); } sb.AppendLine(); } diff --git a/2017/22/index.html b/2017/22/index.html index 71eb8b6f..cc321e69 100644 --- a/2017/22/index.html +++ b/2017/22/index.html @@ -290,40 +290,40 @@

Sporifica Virus

Flagged } -[ProblemName("Sporifica Virus")] +[ProblemName("Sporifica Virus")] class Solution : Solver { - public object PartOne(string input) => + public object PartOne(string input) => Iterate(input, 10000, - (state, drow, dcol) => + (state, drow, dcol) => state switch { - State.Clean => (State.Infected, -dcol, drow), - State.Infected => (State.Clean, dcol, -drow), - _ => throw new ArgumentException() + State.Clean => (State.Infected, -dcol, drow), + State.Infected => (State.Clean, dcol, -drow), + _ => throw new ArgumentException() } ); - public object PartTwo(string input) => + public object PartTwo(string input) => Iterate(input, 10000000, - (state, drow, dcol) => + (state, drow, dcol) => state switch { - State.Clean => (State.Weakened, -dcol, drow), - State.Weakened => (State.Infected, drow, dcol), - State.Infected => (State.Flagged, dcol, -drow), - State.Flagged => (State.Clean, -drow, -dcol), - _ => throw new ArgumentException() + State.Clean => (State.Weakened, -dcol, drow), + State.Weakened => (State.Infected, drow, dcol), + State.Infected => (State.Flagged, dcol, -drow), + State.Flagged => (State.Clean, -drow, -dcol), + _ => throw new ArgumentException() } ); - int Iterate(string input, int iterations, Func update) { - var lines = input.Split('\n'); + int Iterate(string input, int iterations, Func<State, int, int, (State State, int irow, int icol)> update) { + var lines = input.Split('\n'); var crow = lines.Length; var ccol = lines[0].Length; - var cells = new Dictionary<(int irow, int icol), State>(); - for (int irowT = 0; irowT < crow; irowT++) { - for (int icolT = 0; icolT < ccol; icolT++) { - if (lines[irowT][icolT] == '#') { + var cells = new Dictionary<(int irow, int icol), State>(); + for (int irowT = 0; irowT < crow; irowT++) { + for (int icolT = 0; icolT < ccol; icolT++) { + if (lines[irowT][icolT] == '#') { cells.Add((irowT, icolT), State.Infected); } } @@ -331,7 +331,7 @@

Sporifica Virus

var (irow, icol) = (crow / 2, ccol / 2); var (drow, dcol) = (-1, 0); var infections = 0; - for (int i = 0; i < iterations; i++) { + for (int i = 0; i < iterations; i++) { var state = cells.TryGetValue((irow, icol), out var s) ? s : State.Clean; (state, drow, dcol) = update(state, drow, dcol); diff --git a/2017/23/index.html b/2017/23/index.html index cd185888..ade36c7e 100644 --- a/2017/23/index.html +++ b/2017/23/index.html @@ -284,11 +284,11 @@

Coprocessor Conflagration

namespace AdventOfCode.Y2017.Day23; -[ProblemName("Coprocessor Conflagration")] +[ProblemName("Coprocessor Conflagration")] class Solution : Solver { public object PartOne(string input) { - var regs = new Dictionary(); + var regs = new Dictionary<string, int>(); int ip = 0; int getReg(string reg) { return int.TryParse(reg, out var n) ? n @@ -299,29 +299,29 @@

Coprocessor Conflagration

regs[reg] = value; } - var prog = input.Split('\n'); + var prog = input.Split('\n'); var mulCount = 0; - while (ip >= 0 && ip < prog.Length) { + while (ip >= 0 && ip < prog.Length) { var line = prog[ip]; - var parts = line.Split(' '); + var parts = line.Split(' '); switch (parts[0]) { - case "set": + case "set": setReg(parts[1], getReg(parts[2])); ip++; break; - case "sub": + case "sub": setReg(parts[1], getReg(parts[1]) - getReg(parts[2])); ip++; break; - case "mul": + case "mul": mulCount++; setReg(parts[1], getReg(parts[1]) * getReg(parts[2])); ip++; break; - case "jnz": + case "jnz": ip += getReg(parts[1]) != 0 ? getReg(parts[2]) : 1; break; - default: throw new Exception("Cannot parse " + line); + default: throw new Exception("Cannot parse " + line); } } return mulCount; @@ -329,7 +329,7 @@

Coprocessor Conflagration

public object PartTwo(string input) { var c = 0; - for (int b = 107900; b <= 124900; b += 17) { + for (int b = 107900; b <= 124900; b += 17) { if (!IsPrime(b)) { c++; } @@ -338,7 +338,7 @@

Coprocessor Conflagration

} bool IsPrime(int n) { - for (int j = 2; j * j <= n; j++) { + for (int j = 2; j * j <= n; j++) { if (n % j == 0) return false; } return true; diff --git a/2017/24/index.html b/2017/24/index.html index f7c84c95..4735042f 100644 --- a/2017/24/index.html +++ b/2017/24/index.html @@ -285,15 +285,15 @@

Electromagnetic Moat

namespace AdventOfCode.Y2017.Day24; -[ProblemName("Electromagnetic Moat")] +[ProblemName("Electromagnetic Moat")] class Solution : Solver { - public object PartOne(string input) => StrongestBridge(input, (a, b) => a.strength - b.strength); - public object PartTwo(string input) => StrongestBridge(input, (a, b) => a.CompareTo(b)); + public object PartOne(string input) => StrongestBridge(input, (a, b) => a.strength - b.strength); + public object PartTwo(string input) => StrongestBridge(input, (a, b) => a.CompareTo(b)); - int StrongestBridge(string input, Func<(int length, int strength), (int length, int strength), int> compare) { + int StrongestBridge(string input, Func<(int length, int strength), (int length, int strength), int> compare) { - (int length, int strength) fold(int pinIn, HashSet components) { + (int length, int strength) fold(int pinIn, HashSet<Component> components) { var strongest = (0, 0); foreach (var component in components.ToList()) { var pinOut = @@ -305,7 +305,7 @@

Electromagnetic Moat

components.Remove(component); var curr = fold(pinOut, components); (curr.length, curr.strength) = (curr.length + 1, curr.strength + component.pinA + component.pinB); - strongest = compare(curr, strongest) > 0 ? curr : strongest; + strongest = compare(curr, strongest) > 0 ? curr : strongest; components.Add(component); } } @@ -314,10 +314,10 @@

Electromagnetic Moat

return fold(0, Parse(input)).strength; } - HashSet Parse(string input) { - var components = new HashSet(); - foreach (var line in input.Split('\n')) { - var parts = line.Split('/'); + HashSet<Component> Parse(string input) { + var components = new HashSet<Component>(); + foreach (var line in input.Split('\n')) { + var parts = line.Split('/'); components.Add(new Component { pinA = int.Parse(parts[0]), pinB = int.Parse(parts[1]) }); } return components; diff --git a/2017/25/index.html b/2017/25/index.html index a225918a..f38c05be 100644 --- a/2017/25/index.html +++ b/2017/25/index.html @@ -285,14 +285,14 @@

The Halting Problem

namespace AdventOfCode.Y2017.Day25; -[ProblemName("The Halting Problem")] +[ProblemName("The Halting Problem")] class Solution : Solver { public object PartOne(string input) { var machine = Parse(input); - var tape = new Dictionary(); + var tape = new Dictionary<int, int>(); var pos = 0; - while (machine.iterations > 0) { + while (machine.iterations > 0) { var read = tape.TryGetValue(pos, out var t) ? t : 0; var (write, dir, newState) = machine.prg[(machine.state, read)]; machine.state = newState; @@ -300,35 +300,35 @@

The Halting Problem

pos += dir; machine.iterations--; } - return tape.Select(kvp => kvp.Value).Sum(); + return tape.Select(kvp => kvp.Value).Sum(); } Machine Parse(string input) { - var lines = input.Split('\n').Where(line => !string.IsNullOrEmpty(line)).ToArray(); + var lines = input.Split('\n').Where(line => !string.IsNullOrEmpty(line)).ToArray(); int iline = 0; Machine machine = new Machine(); - String(@"Begin in state (\w).", out machine.state); - Int(@"Perform a diagnostic checksum after (\d+) steps.", out machine.iterations); + String(@"Begin in state (\w).", out machine.state); + Int(@"Perform a diagnostic checksum after (\d+) steps.", out machine.iterations); - while (String(@"In state (\w):", out var state)) { - while (Int(@"If the current value is (\d):", out var read)) { - Int(@"- Write the value (\d).", out var write); - String(@"- Move one slot to the (left|right).", out var dir); - String(@" - Continue with state (\w).", out string newState); - machine.prg[(state, read)] = (write, dir == "left" ? -1 : 1, newState); + while (String(@"In state (\w):", out var state)) { + while (Int(@"If the current value is (\d):", out var read)) { + Int(@"- Write the value (\d).", out var write); + String(@"- Move one slot to the (left|right).", out var dir); + String(@" - Continue with state (\w).", out string newState); + machine.prg[(state, read)] = (write, dir == "left" ? -1 : 1, newState); } } bool Int(string pattern, out int r) { r = 0; - return String(pattern, out string st) && int.TryParse(st, out r); + return String(pattern, out string st) && int.TryParse(st, out r); } bool String(string pattern, out string st) { st = null; - if (iline >= lines.Length) { + if (iline >= lines.Length) { return false; } var m = Regex.Match(lines[iline], pattern); @@ -346,8 +346,8 @@

The Halting Problem

class Machine { public string state; public int iterations; - public Dictionary<(string state, int read), (int write, int dir, string state)> prg = - new Dictionary<(string, int), (int, int, string)>(); + public Dictionary<(string state, int read), (int write, int dir, string state)> prg = + new Dictionary<(string, int), (int, int, string)>(); }

Please ☆ my repo if you like it!

diff --git a/2017/3/index.html b/2017/3/index.html index c08bd799..5d2399a8 100644 --- a/2017/3/index.html +++ b/2017/3/index.html @@ -285,7 +285,7 @@

Spiral Memory

namespace AdventOfCode.Y2017.Day03; -[ProblemName("Spiral Memory")] +[ProblemName("Spiral Memory")] class Solution : Solver { public object PartOne(string input) { @@ -295,16 +295,16 @@

Spiral Memory

public object PartTwo(string input) { var num = int.Parse(input); - return SpiralSums().First(v => v > num); + return SpiralSums().First(v => v > num); } - IEnumerable<(int, int)> SpiralCoordinates() { + IEnumerable<(int, int)> SpiralCoordinates() { var (x, y) = (0, 0); var (dx, dy) = (1, 0); for (var edgeLength = 1; ; edgeLength++) { - for (var run = 0; run < 2; run++) { - for (var step = 0; step < edgeLength; step++) { + for (var run = 0; run < 2; run++) { + for (var step = 0; step < edgeLength; step++) { yield return (x, y); (x, y) = (x + dx, y - dy); } @@ -313,8 +313,8 @@

Spiral Memory

} } - IEnumerable SpiralSums() { - var mem = new Dictionary<(int, int), int>(); + IEnumerable<int> SpiralSums() { + var mem = new Dictionary<(int, int), int>(); mem[(0, 0)] = 1; foreach (var coord in SpiralCoordinates()) { @@ -324,7 +324,7 @@

Spiral Memory

} } - IEnumerable<(int, int)> Window((int x, int y) coord) => + IEnumerable<(int, int)> Window((int x, int y) coord) => from dx in new[] { -1, 0, 1 } from dy in new[] { -1, 0, 1 } select (coord.x + dx, coord.y + dy); diff --git a/2017/4/index.html b/2017/4/index.html index 9bc46475..5649d704 100644 --- a/2017/4/index.html +++ b/2017/4/index.html @@ -284,19 +284,19 @@

High-Entropy Passphrases

namespace AdventOfCode.Y2017.Day04; -[ProblemName("High-Entropy Passphrases")] +[ProblemName("High-Entropy Passphrases")] class Solution : Solver { - public object PartOne(string lines) => - ValidLineCount(lines, word => word); + public object PartOne(string lines) => + ValidLineCount(lines, word => word); - public object PartTwo(string lines) => - ValidLineCount(lines, word => string.Concat(word.OrderBy(ch => ch))); + public object PartTwo(string lines) => + ValidLineCount(lines, word => string.Concat(word.OrderBy(ch => ch))); - int ValidLineCount(string lines, Func normalizer) => - lines.Split('\n').Where(line => IsValidLine(line.Split(' '), normalizer)).Count(); + int ValidLineCount(string lines, Func<string, string> normalizer) => + lines.Split('\n').Where(line => IsValidLine(line.Split(' '), normalizer)).Count(); - bool IsValidLine(string[] words, Func normalizer) => + bool IsValidLine(string[] words, Func<string, string> normalizer) => words.Select(normalizer).Distinct().Count() == words.Count(); } diff --git a/2017/5/index.html b/2017/5/index.html index 02352b09..524906a2 100644 --- a/2017/5/index.html +++ b/2017/5/index.html @@ -284,18 +284,18 @@

A Maze of Twisty Trampolines, All Alike

namespace AdventOfCode.Y2017.Day05; -[ProblemName("A Maze of Twisty Trampolines, All Alike")] +[ProblemName("A Maze of Twisty Trampolines, All Alike")] class Solution : Solver { - public object PartOne(string input) => GetStepCount(input, x => x + 1); + public object PartOne(string input) => GetStepCount(input, x => x + 1); - public object PartTwo(string input) => GetStepCount(input, x => x < 3 ? x + 1 : x - 1); + public object PartTwo(string input) => GetStepCount(input, x => x < 3 ? x + 1 : x - 1); - int GetStepCount(string input, Func update) { - var numbers = input.Split('\n').Select(int.Parse).ToArray(); + int GetStepCount(string input, Func<int, int> update) { + var numbers = input.Split('\n').Select(int.Parse).ToArray(); var i = 0; var stepCount = 0; - while (i < numbers.Length && i >= 0) { + while (i < numbers.Length && i >= 0) { var jmp = numbers[i]; numbers[i] = update(numbers[i]); i += jmp; diff --git a/2017/6/index.html b/2017/6/index.html index b2c684de..393b06e6 100644 --- a/2017/6/index.html +++ b/2017/6/index.html @@ -284,10 +284,10 @@

Memory Reallocation

namespace AdventOfCode.Y2017.Day06; -[ProblemName("Memory Reallocation")] +[ProblemName("Memory Reallocation")] class Solution : Solver { - public object PartOne(string input) => GetStepCount(Parse(input)); + public object PartOne(string input) => GetStepCount(Parse(input)); public object PartTwo(string input) { var numbers = Parse(input); @@ -295,13 +295,13 @@

Memory Reallocation

return GetStepCount(numbers); } - List Parse(string input) => input.Split('\t').Select(int.Parse).ToList(); + List<int> Parse(string input) => input.Split('\t').Select(int.Parse).ToList(); - int GetStepCount(List numbers) { + int GetStepCount(List<int> numbers) { var stepCount = 0; - var seen = new HashSet(); + var seen = new HashSet<string>(); while (true) { - var key = string.Join(";", numbers.Select(x => x.ToString())); + var key = string.Join(";", numbers.Select(x => x.ToString())); if (seen.Contains(key)) { return stepCount; } @@ -311,11 +311,11 @@

Memory Reallocation

} } - void Redistribute(List numbers) { + void Redistribute(List<int> numbers) { var max = numbers.Max(); var i = numbers.IndexOf(max); numbers[i] = 0; - while (max > 0) { + while (max > 0) { i++; numbers[i % numbers.Count]++; max--; diff --git a/2017/7/index.html b/2017/7/index.html index 7ff1849f..e7f22e97 100644 --- a/2017/7/index.html +++ b/2017/7/index.html @@ -293,45 +293,45 @@

Recursive Circus

public int TreeWeight = -1; } -class Tree : Dictionary { } +class Tree : Dictionary<string, Node> { } -[ProblemName("Recursive Circus")] +[ProblemName("Recursive Circus")] class Solution : Solver { - public object PartOne(string input) => Root(Parse(input)).Id; + public object PartOne(string input) => Root(Parse(input)).Id; public object PartTwo(string input) { var tree = Parse(input); var root = Root(tree); ComputeTreeWeights(root, tree); var bogusChild = BogusChild(root, tree); - var desiredWeight = tree[root.Children.First(childId => childId != bogusChild.Id)].TreeWeight; + var desiredWeight = tree[root.Children.First(childId => childId != bogusChild.Id)].TreeWeight; return Fix(bogusChild, desiredWeight, tree); } Tree Parse(string input) { var tree = new Tree(); - foreach (var line in input.Split('\n')) { - var parts = Regex.Match(line, @"(?[a-z]+) \((?[0-9]+)\)( -> (?.*))?"); + foreach (var line in input.Split('\n')) { + var parts = Regex.Match(line, @"(?<id>[a-z]+) \((?<weight>[0-9]+)\)( -> (?<children>.*))?"); tree.Add( - parts.Groups["id"].Value, + parts.Groups["id"].Value, new Node { - Id = parts.Groups["id"].Value, - Weight = int.Parse(parts.Groups["weight"].Value), - Children = string.IsNullOrEmpty(parts.Groups["children"].Value) + Id = parts.Groups["id"].Value, + Weight = int.Parse(parts.Groups["weight"].Value), + Children = string.IsNullOrEmpty(parts.Groups["children"].Value) ? new string[0] - : Regex.Split(parts.Groups["children"].Value, ", "), + : Regex.Split(parts.Groups["children"].Value, ", "), }); } return tree; } - Node Root(Tree tree) => - tree.Values.First(node => !tree.Values.Any(nodeParent => nodeParent.Children.Contains(node.Id))); + Node Root(Tree tree) => + tree.Values.First(node => !tree.Values.Any(nodeParent => nodeParent.Children.Contains(node.Id))); int ComputeTreeWeights(Node node, Tree tree) { - node.TreeWeight = node.Weight + node.Children.Select(childId => ComputeTreeWeights(tree[childId], tree)).Sum(); + node.TreeWeight = node.Weight + node.Children.Select(childId => ComputeTreeWeights(tree[childId], tree)).Sum(); return node.TreeWeight; } @@ -347,7 +347,7 @@

Recursive Circus

} int Fix(Node node, int desiredWeight, Tree tree) { - if (node.Children.Length < 2) { + if (node.Children.Length < 2) { throw new NotImplementedException(); } diff --git a/2017/8/index.html b/2017/8/index.html index 689d83d1..07944f1a 100644 --- a/2017/8/index.html +++ b/2017/8/index.html @@ -285,18 +285,18 @@

I Heard You Like Registers

namespace AdventOfCode.Y2017.Day08; -[ProblemName("I Heard You Like Registers")] +[ProblemName("I Heard You Like Registers")] class Solution : Solver { - public object PartOne(string input) => Run(input).lastMax; - public object PartTwo(string input) => Run(input).runningMax; + public object PartOne(string input) => Run(input).lastMax; + public object PartTwo(string input) => Run(input).runningMax; (int runningMax, int lastMax) Run(string input) { - var regs = new Dictionary(); + var regs = new Dictionary<string, int>(); var runningMax = 0; - foreach (var line in input.Split('\n')) { - //hsv inc 472 if hsv >= 4637 - var words = line.Split(' '); + foreach (var line in input.Split('\n')) { + //hsv inc 472 if hsv >= 4637 + var words = line.Split(' '); var (regDst, op, num, regCond, cond, condNum) = (words[0], words[1], int.Parse(words[2]), words[4], words[5], int.Parse(words[6])); if (!regs.ContainsKey(regDst)) { regs[regDst] = 0; @@ -306,18 +306,18 @@

I Heard You Like Registers

} var conditionHolds = cond switch { - ">=" => regs[regCond] >= condNum, - "<=" => regs[regCond] <= condNum, - "==" => regs[regCond] == condNum, - "!=" => regs[regCond] != condNum, - ">" => regs[regCond] > condNum, - "<" => regs[regCond] < condNum, - _ => throw new NotImplementedException(cond) + ">=" => regs[regCond] >= condNum, + "<=" => regs[regCond] <= condNum, + "==" => regs[regCond] == condNum, + "!=" => regs[regCond] != condNum, + ">" => regs[regCond] > condNum, + "<" => regs[regCond] < condNum, + _ => throw new NotImplementedException(cond) }; if (conditionHolds) { regs[regDst] += - op == "inc" ? num : - op == "dec" ? -num : + op == "inc" ? num : + op == "dec" ? -num : throw new NotImplementedException(op); } runningMax = Math.Max(runningMax, regs[regDst]); diff --git a/2017/9/index.html b/2017/9/index.html index 9758cd06..5cc7a4b6 100644 --- a/2017/9/index.html +++ b/2017/9/index.html @@ -284,25 +284,25 @@

Stream Processing

namespace AdventOfCode.Y2017.Day09; -[ProblemName("Stream Processing")] +[ProblemName("Stream Processing")] class Solution : Solver { - public object PartOne(string input) => BlockScores(input).Sum(); - public object PartTwo(string input) => Classify(input).Where((x) => x.garbage).Count(); + public object PartOne(string input) => BlockScores(input).Sum(); + public object PartTwo(string input) => Classify(input).Where((x) => x.garbage).Count(); - IEnumerable BlockScores(string input) { + IEnumerable<int> BlockScores(string input) { var score = 0; - foreach (var ch in Classify(input).Where((x) => !x.garbage).Select(x => x.ch)) { - if (ch == '}') { + foreach (var ch in Classify(input).Where((x) => !x.garbage).Select(x => x.ch)) { + if (ch == '}') { score--; - } else if (ch == '{') { + } else if (ch == '{') { score++; yield return score; } } } - IEnumerable<(char ch, bool garbage)> Classify(string input) { + IEnumerable<(char ch, bool garbage)> Classify(string input) { var skip = false; var garbage = false; foreach (var ch in input) { @@ -310,16 +310,16 @@

Stream Processing

if (skip) { skip = false; } else { - if (ch == '>') { + if (ch == '>') { garbage = false; - } else if (ch == '!') { + } else if (ch == '!') { skip = true; } else { yield return (ch, garbage); } } } else { - if (ch == '<') { + if (ch == '<') { garbage = true; } else { yield return (ch, garbage); diff --git a/2018/1/index.html b/2018/1/index.html index f05e98d2..3791fd4a 100644 --- a/2018/1/index.html +++ b/2018/1/index.html @@ -285,15 +285,15 @@

Chronal Calibration

namespace AdventOfCode.Y2018.Day01; -[ProblemName("Chronal Calibration")] +[ProblemName("Chronal Calibration")] class Solution : Solver { public object PartOne(string input) { - return Frequencies(input).ElementAt(input.Split("\n").Count() - 1); + return Frequencies(input).ElementAt(input.Split("\n").Count() - 1); } public object PartTwo(string input) { - var seen = new HashSet(); + var seen = new HashSet<int>(); foreach (var f in Frequencies(input)) { if (seen.Contains(f)) { return f; @@ -303,10 +303,10 @@

Chronal Calibration

throw new Exception(); } - IEnumerable Frequencies(string input) { + IEnumerable<int> Frequencies(string input) { var f = 0; while (true) { - foreach (var d in input.Split("\n").Select(int.Parse)) { + foreach (var d in input.Split("\n").Select(int.Parse)) { f += d; yield return f; } diff --git a/2018/10/index.html b/2018/10/index.html index 2919d414..73c1deda 100644 --- a/2018/10/index.html +++ b/2018/10/index.html @@ -285,29 +285,29 @@

The Stars Align

namespace AdventOfCode.Y2018.Day10; -[ProblemName("The Stars Align")] +[ProblemName("The Stars Align")] class Solution : Solver { - public object PartOne(string input) => Solver(input).st.Ocr(); + public object PartOne(string input) => Solver(input).st.Ocr(); - public object PartTwo(string input) => Solver(input).seconds; + public object PartTwo(string input) => Solver(input).seconds; (string st, int seconds) Solver(string input) { - // position=< 21992, -10766> velocity=<-2, 1> - var rx = new Regex(@"position=\<\s*(?-?\d+),\s*(?-?\d+)\> velocity=\<\s*(?-?\d+),\s*(?-?\d+)\>"); + // position=< 21992, -10766> velocity=<-2, 1> + var rx = new Regex(@"position=\<\s*(?<x>-?\d+),\s*(?<y>-?\d+)\> velocity=\<\s*(?<vx>-?\d+),\s*(?<vy>-?\d+)\>"); var points = ( - from line in input.Split("\n") + from line in input.Split("\n") let m = rx.Match(line) select new Point { - x = int.Parse(m.Groups["x"].Value), - y = int.Parse(m.Groups["y"].Value), - vx = int.Parse(m.Groups["vx"].Value), - vy = int.Parse(m.Groups["vy"].Value) + x = int.Parse(m.Groups["x"].Value), + y = int.Parse(m.Groups["y"].Value), + vx = int.Parse(m.Groups["vx"].Value), + vy = int.Parse(m.Groups["vy"].Value) } ).ToArray(); var seconds = 0; - Func step = (bool forward) => { + Func<bool, (int left, int top, long width, long height)> step = (bool forward) => { foreach (var point in points) { if (forward) { point.x += point.vx; @@ -319,10 +319,10 @@

The Stars Align

} seconds += forward ? 1 : -1; - var minX = points.Min(pt => pt.x); - var maxX = points.Max(pt => pt.x); - var minY = points.Min(pt => pt.y); - var maxY = points.Max(pt => pt.y); + var minX = points.Min(pt => pt.x); + var maxX = points.Max(pt => pt.x); + var minY = points.Min(pt => pt.y); + var maxY = points.Max(pt => pt.y); return (minX, minY, maxX - minX + 1, maxY - minY + 1); }; @@ -332,15 +332,15 @@

The Stars Align

var rect = step(true); var areaNew = (rect.width) * (rect.height); - if (areaNew > area) { + if (areaNew > area) { rect = step(false); - var st = ""; - for(var irow=0;irow p.x - rect.left == icol && p.y-rect.top == irow) ? '#': ' '; + for(var icol=0;icol<rect.width;icol++){ + st += points.Any(p => p.x - rect.left == icol && p.y-rect.top == irow) ? '#': ' '; } - st+= "\n"; + st+= "\n"; } return (st, seconds); } diff --git a/2018/11/index.html b/2018/11/index.html index 133662f8..e18d9fc4 100644 --- a/2018/11/index.html +++ b/2018/11/index.html @@ -281,26 +281,26 @@

Chronal Charge

namespace AdventOfCode.Y2018.Day11;
 
-[ProblemName("Chronal Charge")]
+[ProblemName("Chronal Charge")]
 class Solution : Solver {
 
     public object PartOne(string input) {
         var res = Solver(int.Parse(input), 3);
-        return $"{res.xMax},{res.yMax}";
+        return $"{res.xMax},{res.yMax}";
     }
 
     public object PartTwo(string input) {
         var res = Solver(int.Parse(input), 300);
-        return $"{res.xMax},{res.yMax},{res.dMax}";
+        return $"{res.xMax},{res.yMax},{res.dMax}";
     }
 
     (int xMax, int yMax, int dMax) Solver(int gridSerialNumber, int D) {
         var gridOriginal = new int[300, 300];
-        for (var irow = 0; irow < 300; irow++) {
-            for (var icol = 0; icol < 300; icol++) {
+        for (var irow = 0; irow < 300; irow++) {
+            for (var icol = 0; icol < 300; icol++) {
                 var x = icol + 1;
                 var y = irow + 1;
-                //  Find the fuel cell's *rack ID*, which is its *X coordinate plus 10*.
+                //  Find the fuel cell's *rack ID*, which is its *X coordinate plus 10*.
                 var rackId = x + 10;
                 // - Begin with a power level of the *rack ID* times the *Y coordinate*.
                 var powerLevel = rackId * y;
@@ -323,22 +323,22 @@ 

Chronal Charge

var dMax = int.MinValue; var grid = new int[300, 300]; - for (var d = 1; d <= D; d++) { - for (var irow = 0; irow < 300 - d; irow++) { - for (var icol = 0; icol < 300; icol++) { + for (var d = 1; d <= D; d++) { + for (var irow = 0; irow < 300 - d; irow++) { + for (var icol = 0; icol < 300; icol++) { grid[irow, icol] += gridOriginal[irow + d - 1, icol]; } } - for (var irow = 0; irow < 300 - d; irow++) { - for (var icol = 0; icol < 300 - d; icol++) { + for (var irow = 0; irow < 300 - d; irow++) { + for (var icol = 0; icol < 300 - d; icol++) { var totalPower = 0; - for (var i = 0; i < d; i++) { + for (var i = 0; i < d; i++) { totalPower += grid[irow, icol + i]; } - if (totalPower > maxTotalPower) { + if (totalPower > maxTotalPower) { maxTotalPower = totalPower; yMax = irow + 1; xMax = icol + 1; diff --git a/2018/12/index.html b/2018/12/index.html index 97ffcbbc..2ebb723a 100644 --- a/2018/12/index.html +++ b/2018/12/index.html @@ -284,19 +284,19 @@

Subterranean Sustainability

namespace AdventOfCode.Y2018.Day12; -[ProblemName("Subterranean Sustainability")] +[ProblemName("Subterranean Sustainability")] class Solution : Solver { - public object PartOne(string input) => Iterate(input, 20); + public object PartOne(string input) => Iterate(input, 20); - public object PartTwo(string input) => Iterate(input, 50000000000); + public object PartTwo(string input) => Iterate(input, 50000000000); long Iterate(string input, long iterations) { var (state, rules) = Parse(input); var dLeftPos = 0L; - while (iterations > 0) { + while (iterations > 0) { var prevState = state; state = Step(state, rules); iterations--; @@ -307,31 +307,31 @@

Subterranean Sustainability

} } - return Enumerable.Range(0, state.pots.Length).Select(i => state.pots[i] == '#' ? i + state.left : 0).Sum(); + return Enumerable.Range(0, state.pots.Length).Select(i => state.pots[i] == '#' ? i + state.left : 0).Sum(); } - State Step(State state, Dictionary rules) { - var pots = "....." + state.pots + "....."; - var newPots = ""; - for (var i = 2; i < pots.Length - 2; i++) { + State Step(State state, Dictionary<string, string> rules) { + var pots = "....." + state.pots + "....."; + var newPots = ""; + for (var i = 2; i < pots.Length - 2; i++) { var x = pots.Substring(i - 2, 5); - newPots += rules.TryGetValue(x, out var ch) ? ch : "."; + newPots += rules.TryGetValue(x, out var ch) ? ch : "."; } - var firstFlower = newPots.IndexOf("#"); + var firstFlower = newPots.IndexOf("#"); var newLeft = firstFlower + state.left - 3; newPots = newPots.Substring(firstFlower); - newPots = newPots.Substring(0, newPots.LastIndexOf("#") + 1); + newPots = newPots.Substring(0, newPots.LastIndexOf("#") + 1); var res = new State { left = newLeft, pots = newPots }; return res; } - (State state, Dictionary rules) Parse(string input) { - var lines = input.Split("\n"); - var state = new State { left = 0, pots = lines[0].Substring("initial state: ".Length) }; - var rules = (from line in lines.Skip(2) let parts = line.Split(" => ") select new { key = parts[0], value = parts[1] }).ToDictionary(x => x.key, x => x.value); + (State state, Dictionary<string, string> rules) Parse(string input) { + var lines = input.Split("\n"); + var state = new State { left = 0, pots = lines[0].Substring("initial state: ".Length) }; + var rules = (from line in lines.Skip(2) let parts = line.Split(" => ") select new { key = parts[0], value = parts[1] }).ToDictionary(x => x.key, x => x.value); return (state, rules); } } diff --git a/2018/13/index.html b/2018/13/index.html index 2143a3bc..ecdade13 100644 --- a/2018/13/index.html +++ b/2018/13/index.html @@ -285,7 +285,7 @@

Mine Cart Madness

namespace AdventOfCode.Y2018.Day13; -[ProblemName("Mine Cart Madness")] +[ProblemName("Mine Cart Madness")] class Solution : Solver { @@ -301,30 +301,30 @@

Mine Cart Madness

public object PartTwo(string input) { var (mat, carts) = Parse(input); - while (carts.Count > 1) { + while (carts.Count > 1) { var newState = Step(mat, carts); carts = newState.carts; } return Tsto(carts[0]); } - string Tsto(Cart cart) => $"{cart.pos.icol},{cart.pos.irow}"; + string Tsto(Cart cart) => $"{cart.pos.icol},{cart.pos.irow}"; - (List crashed, List carts) Step(string[] mat, List carts) { - var crashed = new List(); + (List<Cart> crashed, List<Cart> carts) Step(string[] mat, List<Cart> carts) { + var crashed = new List<Cart>(); - foreach (var cart in carts.OrderBy((cartT) => cartT.pos)) { + foreach (var cart in carts.OrderBy((cartT) => cartT.pos)) { cart.pos = (irow: cart.pos.irow + cart.drow, icol: cart.pos.icol + cart.dcol); foreach (var cart2 in carts.ToArray()) { - if (cart != cart2 && cart.pos.irow == cart2.pos.irow && cart.pos.icol == cart2.pos.icol) { + if (cart != cart2 && cart.pos.irow == cart2.pos.irow && cart.pos.icol == cart2.pos.icol) { crashed.Add(cart); crashed.Add(cart2); } } switch (mat[cart.pos.irow][cart.pos.icol]) { - case '\\': + case '\\': if (cart.dcol == 1 || cart.dcol == -1) { cart.Rotate(Dir.Right); } else if (cart.drow == -1 || cart.drow == 1) { @@ -333,41 +333,41 @@

Mine Cart Madness

throw new Exception(); } break; - case '/': + case '/': if (cart.dcol == 1 || cart.dcol == -1) { cart.Rotate(Dir.Left); } else if (cart.drow == 1 || cart.drow == -1) { cart.Rotate(Dir.Right); } break; - case '+': + case '+': cart.Turn(); break; } } - return (crashed, carts.Where(cart => !crashed.Contains(cart)).ToList()); + return (crashed, carts.Where(cart => !crashed.Contains(cart)).ToList()); } - (string[] mat, List carts) Parse(string input){ - var mat = input.Split("\n"); + (string[] mat, List<Cart> carts) Parse(string input){ + var mat = input.Split("\n"); var crow = mat.Length; var ccol = mat[0].Length; - var carts = new List(); - for (var irow = 0; irow < crow; irow++) { - for (var icol = 0; icol < ccol; icol++) { + var carts = new List<Cart>(); + for (var irow = 0; irow < crow; irow++) { + for (var icol = 0; icol < ccol; icol++) { var ch = mat[irow][icol]; switch (ch) { - case '^': + case '^': carts.Add(new Cart { pos = (irow: irow, icol: icol), dcol = 0, drow = -1 }); break; - case 'v': + case 'v': carts.Add(new Cart { pos = (irow: irow, icol: icol), dcol = 0, drow = 1 }); break; - case '<': + case '<': carts.Add(new Cart { pos = (irow: irow, icol: icol), dcol = -1, drow = 0 }); break; - case '>': + case '>': carts.Add(new Cart { pos = (irow: irow, icol: icol), dcol = 1, drow = 0 }); break; } @@ -386,10 +386,10 @@

Mine Cart Madness

public void Rotate(Dir dir) { (drow, dcol) = dir switch { - Dir.Left => (-dcol, drow), - Dir.Right => (dcol, -drow), - Dir.Forward => (drow, dcol), - _ => throw new ArgumentException() + Dir.Left => (-dcol, drow), + Dir.Right => (dcol, -drow), + Dir.Forward => (drow, dcol), + _ => throw new ArgumentException() }; } diff --git a/2018/14/index.html b/2018/14/index.html index 894d4bb0..4c3297ff 100644 --- a/2018/14/index.html +++ b/2018/14/index.html @@ -285,20 +285,20 @@

Chocolate Charts

namespace AdventOfCode.Y2018.Day14; -[ProblemName("Chocolate Charts")] +[ProblemName("Chocolate Charts")] class Solution : Solver { - public object PartOne(string input) => Window(10).ElementAt(int.Parse(input)).st; + public object PartOne(string input) => Window(10).ElementAt(int.Parse(input)).st; - public object PartTwo(string input) => Window(input.Length).First(item => item.st == input).i; + public object PartTwo(string input) => Window(input.Length).First(item => item.st == input).i; - IEnumerable<(int i, string st)> Window(int w) { - var st = ""; + IEnumerable<(int i, string st)> Window(int w) { + var st = ""; var i = 0; foreach (var score in Scores()) { i++; st += score; - if (st.Length > w) { + if (st.Length > w) { st = st.Substring(st.Length - w); } if (st.Length == w) { @@ -307,9 +307,9 @@

Chocolate Charts

} } - IEnumerable Scores() { - var scores = new List(); - Func add = (i) => { scores.Add(i); return i; }; + IEnumerable<int> Scores() { + var scores = new List<int>(); + Func<int, int> add = (i) => { scores.Add(i); return i; }; var elf1 = 0; var elf2 = 1; @@ -319,7 +319,7 @@

Chocolate Charts

while (true) { var sum = scores[elf1] + scores[elf2]; - if (sum >= 10) { + if (sum >= 10) { yield return add(sum / 10); } yield return add(sum % 10); diff --git a/2018/15/index.html b/2018/15/index.html index 89c58e12..cce875b3 100644 --- a/2018/15/index.html +++ b/2018/15/index.html @@ -285,7 +285,7 @@

Beverage Bandits

namespace AdventOfCode.Y2018.Day15; -[ProblemName("Beverage Bandits")] +[ProblemName("Beverage Bandits")] class Solution : Solver { public object PartOne(string input) { @@ -305,7 +305,7 @@

Beverage Bandits

(bool noElfDied, int score) Outcome(string input, int goblinAp, int elfAp, bool tsto) { var game = Parse(input, goblinAp, elfAp); - var elfCount = game.players.Count(player => player.elf); + var elfCount = game.players.Count(player => player.elf); if (tsto) { Console.WriteLine(game.Tsto()); @@ -318,30 +318,30 @@

Beverage Bandits

} } - return (game.players.Count(p => p.elf) == elfCount, game.rounds * game.players.Select(player => player.hp).Sum()); + return (game.players.Count(p => p.elf) == elfCount, game.rounds * game.players.Select(player => player.hp).Sum()); } Game Parse(string input, int goblinAp, int elfAp) { - var players = new List(); - var lines = input.Split("\n"); + var players = new List<Player>(); + var lines = input.Split("\n"); var mtx = new Block[lines.Length, lines[0].Length]; var game = new Game { mtx = mtx, players = players }; - for (var irow = 0; irow < lines.Length; irow++) { - for (var icol = 0; icol < lines[0].Length; icol++) { + for (var irow = 0; irow < lines.Length; irow++) { + for (var icol = 0; icol < lines[0].Length; icol++) { switch (lines[irow][icol]) { - case '#': + case '#': mtx[irow, icol] = Wall.Block; break; - case '.': + case '.': mtx[irow, icol] = Empty.Block; break; - case var ch when ch == 'G' || ch == 'E': + case var ch when ch == 'G' || ch == 'E': var player = new Player { - elf = ch == 'E', - ap = ch == 'E' ? elfAp : goblinAp, + elf = ch == 'E', + ap = ch == 'E' ? elfAp : goblinAp, pos = (irow, icol), game = game }; @@ -359,19 +359,19 @@

Beverage Bandits

class Game { public Block[,] mtx; - public List players; + public List<Player> players; public int rounds; - private bool ValidPos((int irow, int icol) pos) => - pos.irow >= 0 && pos.irow < this.mtx.GetLength(0) && pos.icol >= 0 && pos.icol < this.mtx.GetLength(1); + private bool ValidPos((int irow, int icol) pos) => + pos.irow >= 0 && pos.irow < this.mtx.GetLength(0) && pos.icol >= 0 && pos.icol < this.mtx.GetLength(1); - public Block GetBlock((int irow, int icol) pos) => + public Block GetBlock((int irow, int icol) pos) => ValidPos(pos) ? mtx[pos.irow, pos.icol] : Wall.Block; public void Step() { var finishedBeforeEndOfRound = false; - foreach (var player in players.OrderBy(player => player.pos).ToArray()) { - if (player.hp > 0) { + foreach (var player in players.OrderBy(player => player.pos).ToArray()) { + if (player.hp > 0) { finishedBeforeEndOfRound |= Finished(); player.Step(); } @@ -382,32 +382,32 @@

Beverage Bandits

} } - public bool Finished() => - players.Where(p => p.elf).All(p => p.hp == 0) || - players.Where(p => !p.elf).All(p => p.hp == 0); + public bool Finished() => + players.Where(p => p.elf).All(p => p.hp == 0) || + players.Where(p => !p.elf).All(p => p.hp == 0); public string Tsto() { - var res = ""; - res += rounds == 0 ? "Initial:\n" : $"After round {rounds}:\n"; - for (var irow = 0; irow < mtx.GetLength(0); irow++) { - for (var icol = 0; icol < mtx.GetLength(1); icol++) { + var res = ""; + res += rounds == 0 ? "Initial:\n" : $"After round {rounds}:\n"; + for (var irow = 0; irow < mtx.GetLength(0); irow++) { + for (var icol = 0; icol < mtx.GetLength(1); icol++) { res += GetBlock((irow, icol)) switch { - Player p when p.elf => "E", - Player p when !p.elf => "G", - Empty _ => ".", - Wall _ => "#", - _ => throw new ArgumentException() + Player p when p.elf => "E", + Player p when !p.elf => "G", + Empty _ => ".", + Wall _ => "#", + _ => throw new ArgumentException() }; } - foreach (var player in players.Where(player => player.pos.irow == irow).OrderBy(player => player.pos)) { - var ch = player.elf ? 'E' : 'G'; - res += $" {ch}{{{player.pos.irow}, {player.pos.icol}}}({player.hp})"; + foreach (var player in players.Where(player => player.pos.irow == irow).OrderBy(player => player.pos)) { + var ch = player.elf ? 'E' : 'G'; + res += $" {ch}{{{player.pos.irow}, {player.pos.icol}}}({player.hp})"; } - res += "\n"; + res += "\n"; } - res += "\n"; + res += "\n"; return res; } } @@ -432,7 +432,7 @@

Beverage Bandits

public Game game; public bool Step() { - if (hp <= 0) { + if (hp <= 0) { return false; } else if (Attack()) { return true; @@ -449,19 +449,19 @@

Beverage Bandits

if (!targets.Any()) { return false; } - var opponent = targets.OrderBy(a => a.target).First(); - var nextPos = targets.Where(a => a.player == opponent.player).Select(a => a.firstStep).OrderBy(_ => _).First(); + var opponent = targets.OrderBy(a => a.target).First(); + var nextPos = targets.Where(a => a.player == opponent.player).Select(a => a.firstStep).OrderBy(_ => _).First(); (game.mtx[nextPos.irow, nextPos.icol], game.mtx[pos.irow, pos.icol]) = (game.mtx[pos.irow, pos.icol], game.mtx[nextPos.irow, nextPos.icol]); pos = nextPos; return true; } - private IEnumerable<(Player player, (int irow, int icol) firstStep, (int irow, int icol) target)> FindTargets() { + private IEnumerable<(Player player, (int irow, int icol) firstStep, (int irow, int icol) target)> FindTargets() { var minDist = int.MaxValue; foreach (var (otherPlayer, firstStep, target, dist) in BlocksNextToOpponentsByDistance()) { - if (dist > minDist) { + if (dist > minDist) { break; } else { minDist = dist; @@ -470,10 +470,10 @@

Beverage Bandits

} } - private IEnumerable<(Player player, (int irow, int icol) firstStep, (int irow, int icol) target, int dist)> BlocksNextToOpponentsByDistance() { - var seen = new HashSet<(int irow, int icol)>(); + private IEnumerable<(Player player, (int irow, int icol) firstStep, (int irow, int icol) target, int dist)> BlocksNextToOpponentsByDistance() { + var seen = new HashSet<(int irow, int icol)>(); seen.Add(pos); - var q = new Queue<((int irow, int icol) pos, (int drow, int dcol) origDir, int dist)>(); + var q = new Queue<((int irow, int icol) pos, (int drow, int dcol) origDir, int dist)>(); foreach (var (drow, dcol) in new[] { (-1, 0), (0, -1), (0, 1), (1, 0) }) { var posT = (pos.irow + drow, pos.icol + dcol); @@ -504,7 +504,7 @@

Beverage Bandits

} private bool Attack() { - var opponents = new List(); + var opponents = new List<Player>(); foreach (var (drow, dcol) in new[] { (-1, 0), (0, -1), (0, 1), (1, 0) }) { var posT = (this.pos.irow + drow, this.pos.icol + dcol); @@ -519,10 +519,10 @@

Beverage Bandits

if (!opponents.Any()) { return false; } - var minHp = opponents.Select(a => a.hp).Min(); - var opponent = opponents.First(a => a.hp == minHp); + var minHp = opponents.Select(a => a.hp).Min(); + var opponent = opponents.First(a => a.hp == minHp); opponent.hp -= this.ap; - if (opponent.hp <= 0) { + if (opponent.hp <= 0) { game.players.Remove(opponent); game.mtx[opponent.pos.irow, opponent.pos.icol] = Empty.Block; } diff --git a/2018/16/index.html b/2018/16/index.html index 36c82f20..38242252 100644 --- a/2018/16/index.html +++ b/2018/16/index.html @@ -286,7 +286,7 @@

Chronal Classification

namespace AdventOfCode.Y2018.Day16; -[ProblemName("Chronal Classification")] +[ProblemName("Chronal Classification")] class Solution : Solver { public object PartOne(string input) { @@ -294,14 +294,14 @@

Chronal Classification

var (testCases, prg) = Parse(input); foreach (var testCase in testCases) { var match = 0; - for (var i = 0; i < 16; i++) { + for (var i = 0; i < 16; i++) { testCase.stm[0] = i; var regsActual = Step(testCase.regsBefore, testCase.stm); - if (Enumerable.Range(0, 4).All(ireg => regsActual[ireg] == testCase.regsAfter[ireg])) { + if (Enumerable.Range(0, 4).All(ireg => regsActual[ireg] == testCase.regsAfter[ireg])) { match++; } } - if (match >= 3) { + if (match >= 3) { res++; } } @@ -310,23 +310,23 @@

Chronal Classification

public object PartTwo(string input) { - var constraints = Enumerable.Range(0, 16).ToDictionary(i => i, i => Enumerable.Range(0, 16).ToList()); + var constraints = Enumerable.Range(0, 16).ToDictionary(i => i, i => Enumerable.Range(0, 16).ToList()); var (testCases, prg) = Parse(input); foreach (var testCase in testCases) { var op = testCase.stm[0]; var oldMapping = constraints[op]; - var newMapping = new List(); + var newMapping = new List<int>(); foreach (var i in oldMapping) { testCase.stm[0] = i; var regsActual = Step(testCase.regsBefore, testCase.stm); - if (Enumerable.Range(0, 4).All(ireg => regsActual[ireg] == testCase.regsAfter[ireg])) { + if (Enumerable.Range(0, 4).All(ireg => regsActual[ireg] == testCase.regsAfter[ireg])) { newMapping.Add(i); } } constraints[op] = newMapping; } - var mapping = WorkOutMapping(constraints, new bool[16], new Dictionary()); + var mapping = WorkOutMapping(constraints, new bool[16], new Dictionary<int, int>()); var regs = new int[4]; foreach (var stm in prg) { stm[0] = mapping[stm[0]]; @@ -335,7 +335,7 @@

Chronal Classification

return regs[0]; } - Dictionary WorkOutMapping(Dictionary> constaints, bool[] used, Dictionary res) { + Dictionary<int, int> WorkOutMapping(Dictionary<int, List<int>> constaints, bool[] used, Dictionary<int, int> res) { var op = res.Count; if (op == 16) { return res; @@ -355,33 +355,33 @@

Chronal Classification

return null; } - (List testCases, List prg) Parse(string input) { - var lines = input.Split("\n").ToList(); + (List<TestCase> testCases, List<int[]> prg) Parse(string input) { + var lines = input.Split("\n").ToList(); var iline = 0; - var testCases = new List(); - while (Ints(@"Before: \[(\d+), (\d+), (\d+), (\d+)\]", out var regsBefore)) { - Ints(@"(\d+) (\d+) (\d+) (\d+)", out var stm); - Ints(@"After: \[(\d+), (\d+), (\d+), (\d+)\]", out var regsAfter); + var testCases = new List<TestCase>(); + while (Ints(@"Before: \[(\d+), (\d+), (\d+), (\d+)\]", out var regsBefore)) { + Ints(@"(\d+) (\d+) (\d+) (\d+)", out var stm); + Ints(@"After: \[(\d+), (\d+), (\d+), (\d+)\]", out var regsAfter); iline++; testCases.Add(new TestCase() { regsBefore = regsBefore, regsAfter = regsAfter, stm = stm }); } iline++; iline++; - var prg = new List(); - while (Ints(@"(\d+) (\d+) (\d+) (\d+)", out var stm)) { + var prg = new List<int[]>(); + while (Ints(@"(\d+) (\d+) (\d+) (\d+)", out var stm)) { prg.Add(stm); } bool Ints(string pattern, out int[] r) { r = null; - if (iline >= lines.Count) { + if (iline >= lines.Count) { return false; } var m = Regex.Match(lines[iline], pattern); if (m.Success) { iline++; - r = m.Groups.Values.Skip(1).Select(x => int.Parse(x.Value)).ToArray(); + r = m.Groups.Values.Skip(1).Select(x => int.Parse(x.Value)).ToArray(); } return m.Success; } @@ -391,23 +391,23 @@

Chronal Classification

int[] Step(int[] regs, int[] stm) { regs = regs.ToArray(); regs[stm[3]] = stm[0] switch { - 0 => regs[stm[1]] + regs[stm[2]], - 1 => regs[stm[1]] + stm[2], - 2 => regs[stm[1]] * regs[stm[2]], - 3 => regs[stm[1]] * stm[2], - 4 => regs[stm[1]] & regs[stm[2]], - 5 => regs[stm[1]] & stm[2], - 6 => regs[stm[1]] | regs[stm[2]], - 7 => regs[stm[1]] | stm[2], - 8 => regs[stm[1]], - 9 => stm[1], - 10 => stm[1] > regs[stm[2]] ? 1 : 0, - 11 => regs[stm[1]] > stm[2] ? 1 : 0, - 12 => regs[stm[1]] > regs[stm[2]] ? 1 : 0, - 13 => stm[1] == regs[stm[2]] ? 1 : 0, - 14 => regs[stm[1]] == stm[2] ? 1 : 0, - 15 => regs[stm[1]] == regs[stm[2]] ? 1 : 0, - _ => throw new ArgumentException() + 0 => regs[stm[1]] + regs[stm[2]], + 1 => regs[stm[1]] + stm[2], + 2 => regs[stm[1]] * regs[stm[2]], + 3 => regs[stm[1]] * stm[2], + 4 => regs[stm[1]] & regs[stm[2]], + 5 => regs[stm[1]] & stm[2], + 6 => regs[stm[1]] | regs[stm[2]], + 7 => regs[stm[1]] | stm[2], + 8 => regs[stm[1]], + 9 => stm[1], + 10 => stm[1] > regs[stm[2]] ? 1 : 0, + 11 => regs[stm[1]] > stm[2] ? 1 : 0, + 12 => regs[stm[1]] > regs[stm[2]] ? 1 : 0, + 13 => stm[1] == regs[stm[2]] ? 1 : 0, + 14 => regs[stm[1]] == stm[2] ? 1 : 0, + 15 => regs[stm[1]] == regs[stm[2]] ? 1 : 0, + _ => throw new ArgumentException() }; return regs; } diff --git a/2018/17/index.html b/2018/17/index.html index 9c9ce3ab..b418ef85 100644 --- a/2018/17/index.html +++ b/2018/17/index.html @@ -286,46 +286,46 @@

Reservoir Research

namespace AdventOfCode.Y2018.Day17; -[ProblemName("Reservoir Research")] +[ProblemName("Reservoir Research")] class Solution : Solver { - public object PartOne(string input) => Regex.Matches(Fill(input), "[~|]").Count; - public object PartTwo(string input) => Regex.Matches(Fill(input), "[~]").Count; + public object PartOne(string input) => Regex.Matches(Fill(input), "[~|]").Count; + public object PartTwo(string input) => Regex.Matches(Fill(input), "[~]").Count; string Fill(string input) { var (width, height) = (2000, 2000); var mtx = new char[width, height]; - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - mtx[x, y] = '.'; + for (var y = 0; y < height; y++) { + for (var x = 0; x < width; x++) { + mtx[x, y] = '.'; } } - foreach (var line in input.Split("\n")) { - var nums = Regex.Matches(line, @"\d+").Select(g => int.Parse(g.Value)).ToArray(); - for (var i = nums[1]; i <= nums[2]; i++) { - if (line.StartsWith("x")) { - mtx[nums[0], i] = '#'; + foreach (var line in input.Split("\n")) { + var nums = Regex.Matches(line, @"\d+").Select(g => int.Parse(g.Value)).ToArray(); + for (var i = nums[1]; i <= nums[2]; i++) { + if (line.StartsWith("x")) { + mtx[nums[0], i] = '#'; } else { - mtx[i, nums[0]] = '#'; + mtx[i, nums[0]] = '#'; } } } FillRecursive(mtx, 500, 0); var (minY, maxY) = (int.MaxValue, int.MinValue); - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - if (mtx[x, y] == '#') { + for (var y = 0; y < height; y++) { + for (var x = 0; x < width; x++) { + if (mtx[x, y] == '#') { minY = Math.Min(minY, y); maxY = Math.Max(maxY, y); } } } var sb = new StringBuilder(); - for (var y = minY; y <= maxY; y++) { - for (var x = 0; x < width; x++) { + for (var y = minY; y <= maxY; y++) { + for (var x = 0; x < width; x++) { sb.Append(mtx[x, y]); } sb.AppendLine(); @@ -336,28 +336,28 @@

Reservoir Research

void FillRecursive(char[,] mtx, int x, int y) { var width = mtx.GetLength(0); var height = mtx.GetLength(1); - if (mtx[x, y] != '.') { + if (mtx[x, y] != '.') { return; } - mtx[x, y] = '|'; + mtx[x, y] = '|'; if (y == height - 1) { return ; } FillRecursive(mtx, x, y + 1); - if (mtx[x, y + 1] == '#' || mtx[x, y + 1] == '~') { - if (x > 0) { + if (mtx[x, y + 1] == '#' || mtx[x, y + 1] == '~') { + if (x > 0) { FillRecursive(mtx, x - 1, y); } - if (x < width - 1) { + if (x < width - 1) { FillRecursive(mtx, x + 1, y); } } if (IsStill(mtx, x, y)) { foreach (var dx in new[] { -1, 1 }) { - for (var xT = x; xT >= 0 && xT < width && mtx[xT, y] == '|'; xT += dx) { - mtx[xT, y] = '~'; + for (var xT = x; xT >= 0 && xT < width && mtx[xT, y] == '|'; xT += dx) { + mtx[xT, y] = '~'; } } } @@ -366,8 +366,8 @@

Reservoir Research

bool IsStill(char[,] mtx, int x, int y) { var width = mtx.GetLength(0); foreach (var dx in new[] { -1, 1 }) { - for (var xT = x; xT >= 0 && xT < width && mtx[xT, y] != '#'; xT += dx) { - if (mtx[xT, y] == '.' || mtx[xT, y + 1] == '|') { + for (var xT = x; xT >= 0 && xT < width && mtx[xT, y] != '#'; xT += dx) { + if (mtx[xT, y] == '.' || mtx[xT, y + 1] == '|') { return false; } } diff --git a/2018/18/index.html b/2018/18/index.html index a9c8836c..dddbe62a 100644 --- a/2018/18/index.html +++ b/2018/18/index.html @@ -284,18 +284,18 @@

Settlers of The North Pole

namespace AdventOfCode.Y2018.Day18; -[ProblemName("Settlers of The North Pole")] +[ProblemName("Settlers of The North Pole")] class Solution : Solver { - public object PartOne(string input) => Iterate(input, 10); - public object PartTwo(string input) => Iterate(input, 1000000000); + public object PartOne(string input) => Iterate(input, 10); + public object PartTwo(string input) => Iterate(input, 1000000000); int Iterate(string input, int lim) { - var seen = new Dictionary(); - var mtx = input.Split("\n"); + var seen = new Dictionary<string, int>(); + var mtx = input.Split("\n"); - for (var t = 0; t < lim; t++) { - var hash = string.Join("", mtx); + for (var t = 0; t < lim; t++) { + var hash = string.Join("", mtx); if (seen.ContainsKey(hash)) { var loopLength = t - seen[hash]; var remainingSteps = lim - t - 1; @@ -306,28 +306,28 @@

Settlers of The North Pole

} mtx = Step(mtx); } - var res = string.Join("", mtx); - return Regex.Matches(res, @"\#").Count * Regex.Matches(res, @"\|").Count; + var res = string.Join("", mtx); + return Regex.Matches(res, @"\#").Count * Regex.Matches(res, @"\|").Count; } string[] Step(string[] mtx) { - var res = new List(); + var res = new List<string>(); var crow = mtx.Length; var ccol = mtx[0].Length; - for (var irow = 0; irow < crow; irow++) { - var line = ""; - for (var icol = 0; icol < ccol; icol++) { + for (var irow = 0; irow < crow; irow++) { + var line = ""; + for (var icol = 0; icol < ccol; icol++) { var (tree, lumberyard, empty) = (0, 0, 0); foreach (var drow in new[] { -1, 0, 1 }) { foreach (var dcol in new[] { -1, 0, 1 }) { if (drow != 0 || dcol != 0) { var (icolT, irowT) = (icol + dcol, irow + drow); - if (icolT >= 0 && icolT < ccol && irowT >= 0 && irowT < crow) { + if (icolT >= 0 && icolT < ccol && irowT >= 0 && irowT < crow) { switch (mtx[irowT][icolT]) { - case '#': lumberyard++; break; - case '|': tree++; break; - case '.': empty++; break; + case '#': lumberyard++; break; + case '|': tree++; break; + case '.': empty++; break; } } } @@ -335,11 +335,11 @@

Settlers of The North Pole

} line += mtx[irow][icol] switch { - '#' when lumberyard >= 1 && tree >= 1 => '#', - '|' when lumberyard >= 3 => '#', - '.' when tree >= 3 => '|', - '#' => '.', - var c => c + '#' when lumberyard >= 1 && tree >= 1 => '#', + '|' when lumberyard >= 3 => '#', + '.' when tree >= 3 => '|', + '#' => '.', + var c => c }; } res.Add(line); diff --git a/2018/19/index.html b/2018/19/index.html index 9614801b..ed0d9a53 100644 --- a/2018/19/index.html +++ b/2018/19/index.html @@ -284,16 +284,16 @@

Go With The Flow

namespace AdventOfCode.Y2018.Day19; -[ProblemName("Go With The Flow")] +[ProblemName("Go With The Flow")] class Solution : Solver { public object PartOne(string input) { var ip = 0; - var ipReg = int.Parse(input.Split("\n").First().Substring("#ip ".Length)); - var prg = input.Split("\n").Skip(1).ToArray(); + var ipReg = int.Parse(input.Split("\n").First().Substring("#ip ".Length)); + var prg = input.Split("\n").Skip(1).ToArray(); var regs = new int[6]; - while (ip >= 0 && ip < prg.Length) { - var args = prg[ip].Split(" "); + while (ip >= 0 && ip < prg.Length) { + var args = prg[ip].Split(" "); regs[ipReg] = ip; regs = Step(regs, args[0], args.Skip(1).Select(int.Parse).ToArray()); ip = regs[ipReg]; @@ -305,7 +305,7 @@

Go With The Flow

public object PartTwo(string input) { var t = 10551292; var r0 = 0; - for (var x = 1; x <= t; x++) { + for (var x = 1; x <= t; x++) { if (t % x == 0) r0 += x; } @@ -315,23 +315,23 @@

Go With The Flow

int[] Step(int[] regs, string op, int[] stm) { regs = regs.ToArray(); regs[stm[2]] = op switch { - "addr" => regs[stm[0]] + regs[stm[1]], - "addi" => regs[stm[0]] + stm[1], - "mulr" => regs[stm[0]] * regs[stm[1]], - "muli" => regs[stm[0]] * stm[1], - "banr" => regs[stm[0]] & regs[stm[1]], - "bani" => regs[stm[0]] & stm[1], - "borr" => regs[stm[0]] | regs[stm[1]], - "bori" => regs[stm[0]] | stm[1], - "setr" => regs[stm[0]], - "seti" => stm[0], - "gtir" => stm[0] > regs[stm[1]] ? 1 : 0, - "gtri" => regs[stm[0]] > stm[1] ? 1 : 0, - "gtrr" => regs[stm[0]] > regs[stm[1]] ? 1 : 0, - "eqir" => stm[0] == regs[stm[1]] ? 1 : 0, - "eqri" => regs[stm[0]] == stm[1] ? 1 : 0, - "eqrr" => regs[stm[0]] == regs[stm[1]] ? 1 : 0, - _ => throw new ArgumentException() + "addr" => regs[stm[0]] + regs[stm[1]], + "addi" => regs[stm[0]] + stm[1], + "mulr" => regs[stm[0]] * regs[stm[1]], + "muli" => regs[stm[0]] * stm[1], + "banr" => regs[stm[0]] & regs[stm[1]], + "bani" => regs[stm[0]] & stm[1], + "borr" => regs[stm[0]] | regs[stm[1]], + "bori" => regs[stm[0]] | stm[1], + "setr" => regs[stm[0]], + "seti" => stm[0], + "gtir" => stm[0] > regs[stm[1]] ? 1 : 0, + "gtri" => regs[stm[0]] > stm[1] ? 1 : 0, + "gtrr" => regs[stm[0]] > regs[stm[1]] ? 1 : 0, + "eqir" => stm[0] == regs[stm[1]] ? 1 : 0, + "eqri" => regs[stm[0]] == stm[1] ? 1 : 0, + "eqrr" => regs[stm[0]] == regs[stm[1]] ? 1 : 0, + _ => throw new ArgumentException() }; return regs; } diff --git a/2018/2/index.html b/2018/2/index.html index f61c48be..1affeacc 100644 --- a/2018/2/index.html +++ b/2018/2/index.html @@ -283,17 +283,17 @@

Inventory Management System

namespace AdventOfCode.Y2018.Day02; -[ProblemName("Inventory Management System")] +[ProblemName("Inventory Management System")] class Solution : Solver { public object PartOne(string input) { var doubles = ( - from line in input.Split("\n") + from line in input.Split("\n") where CheckLine(line, 2) select line ).Count(); var tripples = ( - from line in input.Split("\n") + from line in input.Split("\n") where CheckLine(line, 3) select line ).Count(); @@ -303,11 +303,11 @@

Inventory Management System

bool CheckLine(string line, int n) { return (from ch in line group ch by ch into g - select g.Count()).Any(cch => cch == n); + select g.Count()).Any(cch => cch == n); } public object PartTwo(string input) { - var lines = input.Split("\n"); + var lines = input.Split("\n"); return (from i in Enumerable.Range(0, lines.Length) from j in Enumerable.Range(i + 1, lines.Length - i - 1) let line1 = lines[i] @@ -319,12 +319,12 @@

Inventory Management System

int Diff(string line1, string line2) { return line1.Zip(line2, - (chA, chB) => chA == chB - ).Count(x => x == false); + (chA, chB) => chA == chB + ).Count(x => x == false); } string Common(string line1, string line2) { - return string.Join("", line1.Zip(line2, (chA, chB) => chA == chB ? chA.ToString() : "")); + return string.Join("", line1.Zip(line2, (chA, chB) => chA == chB ? chA.ToString() : "")); } }
diff --git a/2018/20/index.html b/2018/20/index.html index 835da9ae..c984eea1 100644 --- a/2018/20/index.html +++ b/2018/20/index.html @@ -284,22 +284,22 @@

A Regular Map

using System.Linq; namespace AdventOfCode.Y2018.Day20; -[ProblemName("A Regular Map")] +[ProblemName("A Regular Map")] class Solution : Solver { - public object PartOne(string input) => Solver(input).dMax; - public object PartTwo(string input) => Solver(input).distantRooms; + public object PartOne(string input) => Solver(input).dMax; + public object PartTwo(string input) => Solver(input).distantRooms; (int dMax, int distantRooms) Solver(string input) { var grid = Doors(input) .ToList() - .GroupBy(x => x.posFrom) - .ToDictionary(x=>x.Key, x=> x.Select(y => y.posTo).ToList()); + .GroupBy(x => x.posFrom) + .ToDictionary(x=>x.Key, x=> x.Select(y => y.posTo).ToList()); - var queue = new Queue<((int x, int y) pos, int d)>(); + var queue = new Queue<((int x, int y) pos, int d)>(); queue.Enqueue(((0, 0), 0)); - var seen = new HashSet<(int x, int y)>(); + var seen = new HashSet<(int x, int y)>(); var (dMax, distantRooms) = (int.MinValue, 0); while (queue.Any()) { @@ -309,7 +309,7 @@

A Regular Map

} dMax = Math.Max(dMax, d); - if (d >= 1000) { + if (d >= 1000) { distantRooms++; } @@ -322,22 +322,22 @@

A Regular Map

return (dMax, distantRooms); } - IEnumerable<((int x, int y) posFrom, (int x, int y) posTo)> Doors(string input) { - var s = new Stack<(int x, int y)>(); + IEnumerable<((int x, int y) posFrom, (int x, int y) posTo)> Doors(string input) { + var s = new Stack<(int x, int y)>(); (int x, int y) pos = (0, 0); foreach (var ch in input) { var prev = pos; switch (ch) { - case 'N': pos = (pos.x, pos.y - 1); break; - case 'S': pos = (pos.x, pos.y + 1); break; - case 'E': pos = (pos.x + 1, pos.y); break; - case 'W': pos = (pos.x - 1, pos.y); break; - case '(': s.Push(pos); break; - case '|': pos = s.Peek(); break; - case ')': pos = s.Pop(); break; + case 'N': pos = (pos.x, pos.y - 1); break; + case 'S': pos = (pos.x, pos.y + 1); break; + case 'E': pos = (pos.x + 1, pos.y); break; + case 'W': pos = (pos.x - 1, pos.y); break; + case '(': s.Push(pos); break; + case '|': pos = s.Peek(); break; + case ')': pos = s.Pop(); break; } - if ("NSEW".IndexOf(ch) >= 0) { + if ("NSEW".IndexOf(ch) >= 0) { yield return (prev, pos); yield return (pos, prev); } diff --git a/2018/21/index.html b/2018/21/index.html index a5652198..389f62c9 100644 --- a/2018/21/index.html +++ b/2018/21/index.html @@ -285,15 +285,15 @@

Chronal Conversion

namespace AdventOfCode.Y2018.Day21; -[ProblemName("Chronal Conversion")] +[ProblemName("Chronal Conversion")] class Solution : Solver { - public object PartOne(string input) => Run(input).First(); - public object PartTwo(string input) => Run(input).Last(); + public object PartOne(string input) => Run(input).First(); + public object PartTwo(string input) => Run(input).Last(); - public IEnumerable Run(string input) { + public IEnumerable<long> Run(string input) { var breakpoint = 28; - var seen = new List(); + var seen = new List<long>(); foreach (var regs in Trace(input, breakpoint)) { if (seen.Contains(regs[3])) { @@ -304,9 +304,9 @@

Chronal Conversion

} } - public IEnumerable Trace(string input, int breakpoint) { - var lines = input.Split("\n"); - var ipReg = int.Parse(lines.First().Split(" ")[1]); + public IEnumerable<long[]> Trace(string input, int breakpoint) { + var lines = input.Split("\n"); + var ipReg = int.Parse(lines.First().Split(" ")[1]); var program = lines.Skip(1).Select(Compile).ToArray(); var regs = new long[] { 0, 0, 0, 0, 0, 0 }; @@ -319,28 +319,28 @@

Chronal Conversion

} } - Action Compile(string line) { - var parts = line.Split(" "); + Action<long[]> Compile(string line) { + var parts = line.Split(" "); var op = parts[0]; var args = parts.Skip(1).Select(long.Parse).ToArray(); return op switch { - "addr" => regs => regs[args[2]] = regs[args[0]] + regs[args[1]], - "addi" => regs => regs[args[2]] = regs[args[0]] + args[1], - "mulr" => regs => regs[args[2]] = regs[args[0]] * regs[args[1]], - "muli" => regs => regs[args[2]] = regs[args[0]] * args[1], - "banr" => regs => regs[args[2]] = regs[args[0]] & regs[args[1]], - "bani" => regs => regs[args[2]] = regs[args[0]] & args[1], - "borr" => regs => regs[args[2]] = regs[args[0]] | regs[args[1]], - "bori" => regs => regs[args[2]] = regs[args[0]] | args[1], - "setr" => regs => regs[args[2]] = regs[args[0]], - "seti" => regs => regs[args[2]] = args[0], - "gtir" => regs => regs[args[2]] = args[0] > regs[args[1]] ? 1 : 0, - "gtri" => regs => regs[args[2]] = regs[args[0]] > args[1] ? 1 : 0, - "gtrr" => regs => regs[args[2]] = regs[args[0]] > regs[args[1]] ? 1 : 0, - "eqir" => regs => regs[args[2]] = args[0] == regs[args[1]] ? 1 : 0, - "eqri" => regs => regs[args[2]] = regs[args[0]] == args[1] ? 1 : 0, - "eqrr" => regs => regs[args[2]] = regs[args[0]] == regs[args[1]] ? 1 : 0, - _ => throw new ArgumentException() + "addr" => regs => regs[args[2]] = regs[args[0]] + regs[args[1]], + "addi" => regs => regs[args[2]] = regs[args[0]] + args[1], + "mulr" => regs => regs[args[2]] = regs[args[0]] * regs[args[1]], + "muli" => regs => regs[args[2]] = regs[args[0]] * args[1], + "banr" => regs => regs[args[2]] = regs[args[0]] & regs[args[1]], + "bani" => regs => regs[args[2]] = regs[args[0]] & args[1], + "borr" => regs => regs[args[2]] = regs[args[0]] | regs[args[1]], + "bori" => regs => regs[args[2]] = regs[args[0]] | args[1], + "setr" => regs => regs[args[2]] = regs[args[0]], + "seti" => regs => regs[args[2]] = args[0], + "gtir" => regs => regs[args[2]] = args[0] > regs[args[1]] ? 1 : 0, + "gtri" => regs => regs[args[2]] = regs[args[0]] > args[1] ? 1 : 0, + "gtrr" => regs => regs[args[2]] = regs[args[0]] > regs[args[1]] ? 1 : 0, + "eqir" => regs => regs[args[2]] = args[0] == regs[args[1]] ? 1 : 0, + "eqri" => regs => regs[args[2]] = regs[args[0]] == args[1] ? 1 : 0, + "eqrr" => regs => regs[args[2]] = regs[args[0]] == regs[args[1]] ? 1 : 0, + _ => throw new ArgumentException() }; } } diff --git a/2018/22/index.html b/2018/22/index.html index 2a00c87f..32e902ce 100644 --- a/2018/22/index.html +++ b/2018/22/index.html @@ -286,14 +286,14 @@

Mode Maze

namespace AdventOfCode.Y2018.Day22; -[ProblemName("Mode Maze")] +[ProblemName("Mode Maze")] class Solution : Solver { public object PartOne(string input) { var (targetX, targetY, regionType) = Parse(input); var riskLevel = 0; - for (var y = 0; y <= targetY; y++) { - for (var x = 0; x <= targetX; x++) { + for (var y = 0; y <= targetY; y++) { + for (var x = 0; x <= targetX; x++) { riskLevel += (int)regionType(x, y); } } @@ -303,15 +303,15 @@

Mode Maze

public object PartTwo(string input) { var (targetX, targetY, regionType) = Parse(input); - var q = new PQueue<((int x, int y) pos, Tool tool, int t)>(); - var seen = new HashSet<((int x, int y), Tool tool)>(); + var q = new PQueue<((int x, int y) pos, Tool tool, int t)>(); + var seen = new HashSet<((int x, int y), Tool tool)>(); - IEnumerable<((int x, int y) pos, Tool tool, int dt)> Neighbours((int x, int y) pos, Tool tool) { + IEnumerable<((int x, int y) pos, Tool tool, int dt)> Neighbours((int x, int y) pos, Tool tool) { yield return regionType(pos.x, pos.y) switch { - RegionType.Rocky => (pos, tool == Tool.ClimbingGear ? Tool.Torch : Tool.ClimbingGear, 7), - RegionType.Narrow => (pos, tool == Tool.Torch ? Tool.Nothing : Tool.Torch, 7), - RegionType.Wet => (pos, tool == Tool.ClimbingGear ? Tool.Nothing : Tool.ClimbingGear, 7), - _ => throw new ArgumentException() + RegionType.Rocky => (pos, tool == Tool.ClimbingGear ? Tool.Torch : Tool.ClimbingGear, 7), + RegionType.Narrow => (pos, tool == Tool.Torch ? Tool.Nothing : Tool.Torch, 7), + RegionType.Wet => (pos, tool == Tool.ClimbingGear ? Tool.Nothing : Tool.ClimbingGear, 7), + _ => throw new ArgumentException() }; foreach (var dx in new[] { -1, 0, 1 }) { @@ -321,7 +321,7 @@

Mode Maze

} var posNew = (x: pos.x + dx, y: pos.y + dy); - if (posNew.x < 0 || posNew.y < 0) { + if (posNew.x < 0 || posNew.y < 0) { continue; } @@ -342,7 +342,7 @@

Mode Maze

var state = q.Dequeue(); var (pos, tool, t) = state; - if (pos.x == targetX && pos.y == targetY && tool == Tool.Torch) { + if (pos.x == targetX && pos.y == targetY && tool == Tool.Torch) { return t; } @@ -365,21 +365,21 @@

Mode Maze

throw new Exception(); } - (int targetX, int targetY, Func regionType) Parse(string input) { - var lines = input.Split("\n"); - var depth = Regex.Matches(lines[0], @"\d+").Select(x => int.Parse(x.Value)).Single(); - var target = Regex.Matches(lines[1], @"\d+").Select(x => int.Parse(x.Value)).ToArray(); + (int targetX, int targetY, Func<int, int, RegionType> regionType) Parse(string input) { + var lines = input.Split("\n"); + var depth = Regex.Matches(lines[0], @"\d+").Select(x => int.Parse(x.Value)).Single(); + var target = Regex.Matches(lines[1], @"\d+").Select(x => int.Parse(x.Value)).ToArray(); var (targetX, targetY) = (target[0], target[1]); var m = 20183; - var erosionLevelCache = new Dictionary<(int, int), int>(); + var erosionLevelCache = new Dictionary<(int, int), int>(); int erosionLevel(int x, int y) { var key = (x, y); if (!erosionLevelCache.ContainsKey(key)) { - if (x == targetX && y == targetY) { + if (x == targetX && y == targetY) { erosionLevelCache[key] = depth; - } else if (x == 0 && y == 0) { + } else if (x == 0 && y == 0) { erosionLevelCache[key] = depth; } else if (x == 0) { erosionLevelCache[key] = ((y * 48271) + depth) % m; @@ -411,15 +411,15 @@

Mode Maze

ClimbingGear } -class PQueue { - SortedDictionary> d = new SortedDictionary>(); +class PQueue<T> { + SortedDictionary<int, Queue<T>> d = new SortedDictionary<int, Queue<T>>(); public bool Any() { return d.Any(); } public void Enqueue(int p, T t) { if (!d.ContainsKey(p)) { - d[p] = new Queue(); + d[p] = new Queue<T>(); } d[p].Enqueue(t); } diff --git a/2018/23/index.html b/2018/23/index.html index d0104dd5..08539fc5 100644 --- a/2018/23/index.html +++ b/2018/23/index.html @@ -287,19 +287,19 @@

Experimental Emergency Teleportation

namespace AdventOfCode.Y2018.Day23; -[ProblemName("Experimental Emergency Teleportation")] +[ProblemName("Experimental Emergency Teleportation")] class Solution : Solver { - int Dist((int x, int y, int z) a, (int x, int y, int z) b) => Math.Abs(a.x - b.x) + Math.Abs(a.y - b.y) + Math.Abs(a.z - b.z); + int Dist((int x, int y, int z) a, (int x, int y, int z) b) => Math.Abs(a.x - b.x) + Math.Abs(a.y - b.y) + Math.Abs(a.z - b.z); public object PartOne(string input) { var drones = Parse(input); - var maxRange = drones.Select(drone => drone.r).Max(); - var maxDrone = drones.Single(drone => drone.r == maxRange); - return drones.Count(drone => Dist(drone.pos, maxDrone.pos) <= maxRange); + var maxRange = drones.Select(drone => drone.r).Max(); + var maxDrone = drones.Single(drone => drone.r == maxRange); + return drones.Count(drone => Dist(drone.pos, maxDrone.pos) <= maxRange); } - IEnumerable<(int x, int y, int z)> Corners(Drone[] drones) => ( + IEnumerable<(int x, int y, int z)> Corners(Drone[] drones) => ( from drone in drones from dx in new[] { -1, 0, 1 } from dy in new[] { -1, 0, 1 } @@ -308,38 +308,38 @@

Experimental Emergency Teleportation

select (drone.pos.x + dx * drone.r, drone.pos.y + dy * drone.r, drone.pos.z + dz * drone.r) ).ToArray(); - Drone[] Parse(string input) => ( - from line in input.Split("\n") - let parts = Regex.Matches(line, @"-?\d+").Select(x => int.Parse(x.Value)).ToArray() + Drone[] Parse(string input) => ( + from line in input.Split("\n") + let parts = Regex.Matches(line, @"-?\d+").Select(x => int.Parse(x.Value)).ToArray() select new Drone((parts[0], parts[1], parts[2]), parts[3]) ).ToArray(); public object PartTwo(string input) { var drones = Parse(input); - var minX = drones.Select(drone => drone.pos.x).Min(); - var minY = drones.Select(drone => drone.pos.y).Min(); - var minZ = drones.Select(drone => drone.pos.z).Min(); + var minX = drones.Select(drone => drone.pos.x).Min(); + var minY = drones.Select(drone => drone.pos.y).Min(); + var minZ = drones.Select(drone => drone.pos.z).Min(); - var maxX = drones.Select(drone => drone.pos.x).Max(); - var maxY = drones.Select(drone => drone.pos.y).Max(); - var maxZ = drones.Select(drone => drone.pos.z).Max(); + var maxX = drones.Select(drone => drone.pos.x).Max(); + var maxY = drones.Select(drone => drone.pos.y).Max(); + var maxZ = drones.Select(drone => drone.pos.z).Max(); return Solve(new Box((minX, minY, minZ), (maxX - minX + 1, maxY - minY + 1, maxZ - minZ + 1)), drones).pt; } (int drones, int pt) Solve(Box box, Drone[] drones) { - var q = new PQueue<(int, int), (Box box, Drone[] drones)>(); + var q = new PQueue<(int, int), (Box box, Drone[] drones)>(); q.Enqueue((0, 0), (box, drones)); while (q.Any()) { (box, drones) = q.Dequeue(); if (box.Size() == 1) { - return (drones.Count(drone => drone.Contains(box)), box.Dist()); + return (drones.Count(drone => drone.Contains(box)), box.Dist()); } else { foreach (var subBox in box.Divide()) { - var intersectingDrones = drones.Where(drone => drone.Intersects(subBox)).ToArray(); + var intersectingDrones = drones.Where(drone => drone.Intersects(subBox)).ToArray(); q.Enqueue((-intersectingDrones.Count(), subBox.Dist()), (subBox, intersectingDrones)); } } @@ -359,7 +359,7 @@

Experimental Emergency Teleportation

this.size = size; } - public IEnumerable<(int x, int y, int z)> Corners() { + public IEnumerable<(int x, int y, int z)> Corners() { yield return (min.x, min.y, min.z); yield return (max.x, min.y, min.z); yield return (min.x, max.y, min.z); @@ -371,7 +371,7 @@

Experimental Emergency Teleportation

yield return (max.x, max.y, max.z); } - public IEnumerable Divide() { + public IEnumerable<Box> Divide() { var sx = size.sx / 2; var tx = size.sx - sx; var sy = size.sy / 2; @@ -390,11 +390,11 @@

Experimental Emergency Teleportation

new Box((min.x, min.y + sy, min.z + sz), (sx, ty, tz)), new Box((min.x + sx, min.y + sy, min.z + sz), (tx, ty, tz)), - }.Where(box => box.size.sx > 0 && box.size.sy > 0 && box.size.sz > 0); + }.Where(box => box.size.sx > 0 && box.size.sy > 0 && box.size.sz > 0); } public int Dist() { - return Corners().Select(pt => Math.Abs(pt.x) + Math.Abs(pt.y) + Math.Abs(pt.z)).Min(); + return Corners().Select(pt => Math.Abs(pt.x) + Math.Abs(pt.y) + Math.Abs(pt.z)).Min(); } public BigInteger Size() { @@ -417,18 +417,18 @@

Experimental Emergency Teleportation

var dy = Math.Max(0, Math.Max(box.min.y - pos.y, pos.y - box.max.y)); var dz = Math.Max(0, Math.Max(box.min.z - pos.z, pos.z - box.max.z)); - return Math.Abs(dx) + Math.Abs(dy) + Math.Abs(dz) <= r; + return Math.Abs(dx) + Math.Abs(dy) + Math.Abs(dz) <= r; } public bool Contains(Box box) { return box .Corners() - .All(pt => Math.Abs(pt.x - pos.x) + Math.Abs(pt.y - pos.y) + Math.Abs(pt.z - pos.z) <= r); + .All(pt => Math.Abs(pt.x - pos.x) + Math.Abs(pt.y - pos.y) + Math.Abs(pt.z - pos.z) <= r); } } -class PQueue where K : IComparable { - SortedDictionary> d = new SortedDictionary>(); +class PQueue<K, T> where K : IComparable { + SortedDictionary<K, Queue<T>> d = new SortedDictionary<K, Queue<T>>(); int c = 0; public bool Any() { return d.Any(); @@ -436,7 +436,7 @@

Experimental Emergency Teleportation

public void Enqueue(K p, T t) { if (!d.ContainsKey(p)) { - d[p] = new Queue(); + d[p] = new Queue<T>(); } d[p].Enqueue(t); c++; diff --git a/2018/24/index.html b/2018/24/index.html index 8835e696..113e2d37 100644 --- a/2018/24/index.html +++ b/2018/24/index.html @@ -286,7 +286,7 @@

Immune System Simulator 20XX

namespace AdventOfCode.Y2018.Day24; -[ProblemName("Immune System Simulator 20XX")] +[ProblemName("Immune System Simulator 20XX")] class Solution : Solver { (bool immuneSystem, long units) Fight(string input, int boost) { @@ -299,40 +299,40 @@

Immune System Simulator 20XX

var attack = true; while (attack) { attack = false; - var remainingTarget = new HashSet(army); - var targets = new Dictionary(); - foreach (var g in army.OrderByDescending(g => (g.effectivePower, g.initiative))) { - var maxDamage = remainingTarget.Select(t => g.DamageDealtTo(t)).Max(); - if (maxDamage > 0) { - var possibleTargets = remainingTarget.Where(t => g.DamageDealtTo(t) == maxDamage); - targets[g] = possibleTargets.OrderByDescending(t => (t.effectivePower, t.initiative)).First(); + var remainingTarget = new HashSet<Group>(army); + var targets = new Dictionary<Group, Group>(); + foreach (var g in army.OrderByDescending(g => (g.effectivePower, g.initiative))) { + var maxDamage = remainingTarget.Select(t => g.DamageDealtTo(t)).Max(); + if (maxDamage > 0) { + var possibleTargets = remainingTarget.Where(t => g.DamageDealtTo(t) == maxDamage); + targets[g] = possibleTargets.OrderByDescending(t => (t.effectivePower, t.initiative)).First(); remainingTarget.Remove(targets[g]); } } - foreach (var g in targets.Keys.OrderByDescending(g => g.initiative)) { - if (g.units > 0) { + foreach (var g in targets.Keys.OrderByDescending(g => g.initiative)) { + if (g.units > 0) { var target = targets[g]; var damage = g.DamageDealtTo(target); - if (damage > 0 && target.units > 0) { + if (damage > 0 && target.units > 0) { var dies = damage / target.hp; target.units = Math.Max(0, target.units - dies); - if (dies > 0) { + if (dies > 0) { attack = true; } } } } - army = army.Where(g => g.units > 0).ToList(); + army = army.Where(g => g.units > 0).ToList(); } - return (army.All(x => x.immuneSystem), army.Select(x => x.units).Sum()); + return (army.All(x => x.immuneSystem), army.Select(x => x.units).Sum()); } - public object PartOne(string input) => Fight(input, 0).units; + public object PartOne(string input) => Fight(input, 0).units; public object PartTwo(string input) { var l = 0; var h = int.MaxValue / 2; - while (h - l > 1) { + while (h - l > 1) { var m = (h + l) / 2; if (Fight(input, m).immuneSystem) { h = m; @@ -343,18 +343,18 @@

Immune System Simulator 20XX

return Fight(input, h).units; } - List Parse(string input) { - var lines = input.Split("\n"); + List<Group> Parse(string input) { + var lines = input.Split("\n"); var immuneSystem = false; - var res = new List(); + var res = new List<Group>(); foreach (var line in lines) - if (line == "Immune System:") { + if (line == "Immune System:") { immuneSystem = true; - } else if (line == "Infection:") { + } else if (line == "Infection:") { immuneSystem = false; - } else if (line != "") { + } else if (line != "") { //643 units each with 9928 hit points (immune to fire; weak to slashing, bludgeoning) with an attack that does 149 fire damage at initiative 14 - var rx = @"(\d+) units each with (\d+) hit points(.*)with an attack that does (\d+)(.*)damage at initiative (\d+)"; + var rx = @"(\d+) units each with (\d+) hit points(.*)with an attack that does (\d+)(.*)damage at initiative (\d+)"; var m = Regex.Match(line, rx); if (m.Success) { Group g = new Group(); @@ -365,15 +365,15 @@

Immune System Simulator 20XX

g.attackType = m.Groups[5].Value.Trim(); g.initiative = int.Parse(m.Groups[6].Value); var st = m.Groups[3].Value.Trim(); - if (st != "") { + if (st != "") { st = st.Substring(1, st.Length - 2); - foreach (var part in st.Split(";")) { - var k = part.Split(" to "); - var set = new HashSet(k[1].Split(", ")); + foreach (var part in st.Split(";")) { + var k = part.Split(" to "); + var set = new HashSet<string>(k[1].Split(", ")); var w = k[0].Trim(); - if (w == "immune") { + if (w == "immune") { g.immuneTo = set; - } else if (w == "weak") { + } else if (w == "weak") { g.weakTo = set; } else { throw new Exception(); @@ -398,8 +398,8 @@

Immune System Simulator 20XX

public int damage; public int initiative; public string attackType; - public HashSet immuneTo = new HashSet(); - public HashSet weakTo = new HashSet(); + public HashSet<string> immuneTo = new HashSet<string>(); + public HashSet<string> weakTo = new HashSet<string>(); public long effectivePower { get { diff --git a/2018/25/index.html b/2018/25/index.html index ac3f4a3f..adfa14c4 100644 --- a/2018/25/index.html +++ b/2018/25/index.html @@ -285,29 +285,29 @@

Four-Dimensional Adventure

namespace AdventOfCode.Y2018.Day25; -[ProblemName("Four-Dimensional Adventure")] +[ProblemName("Four-Dimensional Adventure")] class Solution : Solver { public object PartOne(string input) { - var sets = new List>(); + var sets = new List<HashSet<int[]>>(); - foreach (var line in input.Split("\n")) { - var set = new HashSet(); - set.Add(line.Split(",").Select(int.Parse).ToArray()); + foreach (var line in input.Split("\n")) { + var set = new HashSet<int[]>(); + set.Add(line.Split(",").Select(int.Parse).ToArray()); sets.Add(set); } foreach (var set in sets.ToList()) { var pt = set.Single(); - var closeSets = new List>(); + var closeSets = new List<HashSet<int[]>>(); foreach (var setB in sets) { foreach (var ptB in setB) { - if (Dist(pt, ptB) <= 3) { + if (Dist(pt, ptB) <= 3) { closeSets.Add(setB); } } } - var mergedSet = new HashSet(); + var mergedSet = new HashSet<int[]>(); foreach (var setB in closeSets) { foreach (var ptB in setB) { mergedSet.Add(ptB); @@ -320,7 +320,7 @@

Four-Dimensional Adventure

return sets.Count; } - int Dist(int[] a, int[] b) => Enumerable.Range(0, a.Length).Select(i => Math.Abs(a[i] - b[i])).Sum(); + int Dist(int[] a, int[] b) => Enumerable.Range(0, a.Length).Select(i => Math.Abs(a[i] - b[i])).Sum(); } diff --git a/2018/3/index.html b/2018/3/index.html index 617e28ca..32eefb7c 100644 --- a/2018/3/index.html +++ b/2018/3/index.html @@ -285,33 +285,33 @@

No Matter How You Slice It

namespace AdventOfCode.Y2018.Day03; -[ProblemName("No Matter How You Slice It")] +[ProblemName("No Matter How You Slice It")] class Solution : Solver { - public object PartOne(string input) => Decorate(input).overlapArea; + public object PartOne(string input) => Decorate(input).overlapArea; - public object PartTwo(string input) => Decorate(input).intactId; + public object PartTwo(string input) => Decorate(input).intactId; (int overlapArea, int intactId) Decorate(string input) { // #1 @ 55,885: 22x10 - var rx = new Regex(@"(?\d+) @ (?\d+),(?\d+): (?\d+)x(?\d+)"); + var rx = new Regex(@"(?<id>\d+) @ (?<x>\d+),(?<y>\d+): (?<width>\d+)x(?<height>\d+)"); var mtx = new int[1000, 1000]; var overlapArea = 0; - var ids = new HashSet(); - foreach (var line in input.Split("\n")) { + var ids = new HashSet<int>(); + foreach (var line in input.Split("\n")) { var parts = rx.Match(line); - var id = int.Parse(parts.Groups["id"].Value); - var x = int.Parse(parts.Groups["x"].Value); - var y = int.Parse(parts.Groups["y"].Value); - var width = int.Parse(parts.Groups["width"].Value); - var height = int.Parse(parts.Groups["height"].Value); + var id = int.Parse(parts.Groups["id"].Value); + var x = int.Parse(parts.Groups["x"].Value); + var y = int.Parse(parts.Groups["y"].Value); + var width = int.Parse(parts.Groups["width"].Value); + var height = int.Parse(parts.Groups["height"].Value); ids.Add(id); - for (var i = 0; i < width; i++) { - for (var j = 0; j < height; j++) { + for (var i = 0; i < width; i++) { + for (var j = 0; j < height; j++) { if (mtx[x + i, y + j] == 0) { mtx[x + i, y + j] = id; } else if (mtx[x + i, y + j] == -1) { diff --git a/2018/4/index.html b/2018/4/index.html index 9550f5f6..c61595f8 100644 --- a/2018/4/index.html +++ b/2018/4/index.html @@ -286,7 +286,7 @@

Repose Record

namespace AdventOfCode.Y2018.Day04; -[ProblemName("Repose Record")] +[ProblemName("Repose Record")] class Solution : Solver { public object PartOne(string input) { @@ -294,13 +294,13 @@

Repose Record

group day by day.guard into g select new { guard = g.Key, - totalSleeps = g.Select(day => day.totalSleep).Sum(), - sleepByMin = Enumerable.Range(0, 60).Select(minT => g.Sum(day => day.sleep[minT])).ToArray() + totalSleeps = g.Select(day => day.totalSleep).Sum(), + sleepByMin = Enumerable.Range(0, 60).Select(minT => g.Sum(day => day.sleep[minT])).ToArray() }; - var maxSleep = foo.Max(x => x.totalSleeps); - var fooT = foo.Single(g => g.totalSleeps == maxSleep); - var maxSleepByMin = Enumerable.Range(0, 60).Max(minT => fooT.sleepByMin[minT]); - var min = Enumerable.Range(0, 60).Single(minT => fooT.sleepByMin[minT] == maxSleepByMin); + var maxSleep = foo.Max(x => x.totalSleeps); + var fooT = foo.Single(g => g.totalSleeps == maxSleep); + var maxSleepByMin = Enumerable.Range(0, 60).Max(minT => fooT.sleepByMin[minT]); + var min = Enumerable.Range(0, 60).Single(minT => fooT.sleepByMin[minT] == maxSleepByMin); return fooT.guard * min; } @@ -309,32 +309,32 @@

Repose Record

group day by day.guard into g select new { guard = g.Key, - totalSleeps = g.Select(day => day.totalSleep).Sum(), - sleepByMin = Enumerable.Range(0, 60).Select(minT => g.Sum(day => day.sleep[minT])).ToArray() + totalSleeps = g.Select(day => day.totalSleep).Sum(), + sleepByMin = Enumerable.Range(0, 60).Select(minT => g.Sum(day => day.sleep[minT])).ToArray() }; - var maxMaxSleep = foo.Max(x => x.sleepByMin.Max()); - var fooT = foo.Single(x => x.sleepByMin.Max() == maxMaxSleep); - var min = Enumerable.Range(0, 60).Single(minT => fooT.sleepByMin[minT] == maxMaxSleep); + var maxMaxSleep = foo.Max(x => x.sleepByMin.Max()); + var fooT = foo.Single(x => x.sleepByMin.Max() == maxMaxSleep); + var min = Enumerable.Range(0, 60).Single(minT => fooT.sleepByMin[minT] == maxMaxSleep); return fooT.guard * min; } - IEnumerable Parse(string input) { - var lines = input.Split("\n").ToList(); - lines.Sort((x, y) => DateTime.Parse(x.Substring(1, "1518-03-25 00:01".Length)).CompareTo(DateTime.Parse(y.Substring(1, "1518-03-25 00:01".Length)))); + IEnumerable<Day> Parse(string input) { + var lines = input.Split("\n").ToList(); + lines.Sort((x, y) => DateTime.Parse(x.Substring(1, "1518-03-25 00:01".Length)).CompareTo(DateTime.Parse(y.Substring(1, "1518-03-25 00:01".Length)))); var iline = 0; - while (Int(@"Guard #(\d+) begins shift", out var guard)) { + while (Int(@"Guard #(\d+) begins shift", out var guard)) { var sleep = new int[60]; - while (Date(@"\[(.*)\] falls asleep", out var fallsAsleap)) { - Date(@"\[(.*)\] wakes up", out var wakesUp); + while (Date(@"\[(.*)\] falls asleep", out var fallsAsleap)) { + Date(@"\[(.*)\] wakes up", out var wakesUp); var from = fallsAsleap.Hour != 0 ? 0 : fallsAsleap.Minute; var to = wakesUp.Hour != 0 ? 0 : wakesUp.Minute; - for (var min = from; min < to; min++) { + for (var min = from; min < to; min++) { sleep[min] = 1; } } @@ -347,17 +347,17 @@

Repose Record

} bool Int(string pattern, out int r) { r = 0; - return String(pattern, out string st) && int.TryParse(st, out r); + return String(pattern, out string st) && int.TryParse(st, out r); } bool Date(string pattern, out DateTime r) { r = DateTime.MinValue; - return String(pattern, out string st) && DateTime.TryParse(st, out r); + return String(pattern, out string st) && DateTime.TryParse(st, out r); } bool String(string pattern, out string st) { st = null; - if (iline >= lines.Count) { + if (iline >= lines.Count) { return false; } var m = Regex.Match(lines[iline], pattern); @@ -374,7 +374,7 @@

Repose Record

class Day { public int guard; public int[] sleep; - public int totalSleep => sleep.Sum(); + public int totalSleep => sleep.Sum(); }

Please ☆ my repo if you like it!

diff --git a/2018/5/index.html b/2018/5/index.html index b57082ce..3ca0870e 100644 --- a/2018/5/index.html +++ b/2018/5/index.html @@ -284,23 +284,23 @@

Alchemical Reduction

namespace AdventOfCode.Y2018.Day05; -[ProblemName("Alchemical Reduction")] +[ProblemName("Alchemical Reduction")] class Solution : Solver { - public object PartOne(string input) => React(input); + public object PartOne(string input) => React(input); - public object PartTwo(string input) => (from ch in "abcdefghijklmnopqrstuvwxyz" select React(input, ch)).Min(); + public object PartTwo(string input) => (from ch in "abcdefghijklmnopqrstuvwxyz" select React(input, ch)).Min(); - char ToLower(char ch) => ch <= 'Z' ? (char)(ch - 'A' + 'a') : ch; + char ToLower(char ch) => ch <= 'Z' ? (char)(ch - 'A' + 'a') : ch; int React(string input, char? skip = null) { - var stack = new Stack("⊥"); + var stack = new Stack<char>("⊥"); foreach (var ch in input) { var top = stack.Peek(); if (ToLower(ch) == skip) { continue; - } else if (top != ch && ToLower(ch) == ToLower(top)) { + } else if (top != ch && ToLower(ch) == ToLower(top)) { stack.Pop(); } else { stack.Push(ch); diff --git a/2018/6/index.html b/2018/6/index.html index 697944d8..34d359ca 100644 --- a/2018/6/index.html +++ b/2018/6/index.html @@ -284,23 +284,23 @@

Chronal Coordinates

namespace AdventOfCode.Y2018.Day06; -[ProblemName("Chronal Coordinates")] +[ProblemName("Chronal Coordinates")] class Solution : Solver { public object PartOne(string input) { var coords = Parse(input); - var minX = coords.Min(coord => coord.x) - 1; - var maxX = coords.Max(coord => coord.x) + 1; - var minY = coords.Min(coord => coord.y) - 1; - var maxY = coords.Max(coord => coord.y) + 1; + var minX = coords.Min(coord => coord.x) - 1; + var maxX = coords.Max(coord => coord.x) + 1; + var minY = coords.Min(coord => coord.y) - 1; + var maxY = coords.Max(coord => coord.y) + 1; var area = new int[coords.Length]; foreach (var x in Enumerable.Range(minX, maxX - minX + 1)) { foreach (var y in Enumerable.Range(minY, maxY - minX + 1)) { - var d = coords.Select(coord => Dist((x, y), coord)).Min(); - var closest = Enumerable.Range(0, coords.Length).Where(i => Dist((x, y), coords[i]) == d).ToArray(); + var d = coords.Select(coord => Dist((x, y), coord)).Min(); + var closest = Enumerable.Range(0, coords.Length).Where(i => Dist((x, y), coords[i]) == d).ToArray(); if (closest.Length != 1) { continue; @@ -327,17 +327,17 @@

Chronal Coordinates

public object PartTwo(string input) { var coords = Parse(input); - var minX = coords.Min(coord => coord.x) - 1; - var maxX = coords.Max(coord => coord.x) + 1; - var minY = coords.Min(coord => coord.y) - 1; - var maxY = coords.Max(coord => coord.y) + 1; + var minX = coords.Min(coord => coord.x) - 1; + var maxX = coords.Max(coord => coord.x) + 1; + var minY = coords.Min(coord => coord.y) - 1; + var maxY = coords.Max(coord => coord.y) + 1; var area = 0; foreach (var x in Enumerable.Range(minX, maxX - minX + 1)) { foreach (var y in Enumerable.Range(minY, maxY - minX + 1)) { - var d = coords.Select(coord => Dist((x, y), coord)).Sum(); - if (d < 10000) + var d = coords.Select(coord => Dist((x, y), coord)).Sum(); + if (d < 10000) area++; } } @@ -348,9 +348,9 @@

Chronal Coordinates

return Math.Abs(c1.x - c2.x) + Math.Abs(c1.y - c2.y); } - (int x, int y)[] Parse(string input) => ( - from line in input.Split("\n") - let coords = line.Split(", ").Select(int.Parse).ToArray() + (int x, int y)[] Parse(string input) => ( + from line in input.Split("\n") + let coords = line.Split(", ").Select(int.Parse).ToArray() select (coords[0], coords[1]) ).ToArray(); } diff --git a/2018/7/index.html b/2018/7/index.html index cc40452a..771cdcff 100644 --- a/2018/7/index.html +++ b/2018/7/index.html @@ -285,7 +285,7 @@

The Sum of Its Parts

namespace AdventOfCode.Y2018.Day07; -[ProblemName("The Sum of Its Parts")] +[ProblemName("The Sum of Its Parts")] class Solution : Solver { public object PartOne(string input) { @@ -296,7 +296,7 @@

The Sum of Its Parts

char minKey = char.MaxValue; foreach (var key in graph.Keys) { if (graph[key].Count == 0) { - if (key < minKey) { + if (key < minKey) { minKey = key; } } @@ -317,20 +317,20 @@

The Sum of Its Parts

var works = new int[5]; var items = new char[works.Length]; - while (graph.Any() || works.Any(work => work > 0)) { - for (var i = 0; i < works.Length && graph.Any(); i++) { + while (graph.Any() || works.Any(work => work > 0)) { + for (var i = 0; i < works.Length && graph.Any(); i++) { // start working if (works[i] == 0) { char minKey = char.MaxValue; foreach (var key in graph.Keys) { if (graph[key].Count == 0) { - if (key < minKey) { + if (key < minKey) { minKey = key; } } } if (minKey != char.MaxValue) { - works[i] = 60 + minKey - 'A' + 1; + works[i] = 60 + minKey - 'A' + 1; items[i] = minKey; graph.Remove(items[i]); } @@ -339,7 +339,7 @@

The Sum of Its Parts

time++; - for (var i = 0; i < works.Length; i++) { + for (var i = 0; i < works.Length; i++) { if (works[i] == 0) { // wait continue; @@ -350,7 +350,7 @@

The Sum of Its Parts

graph[key].Remove(items[i]); } - } else if (works[i] > 0) { + } else if (works[i] > 0) { // step works[i]--; } @@ -360,20 +360,20 @@

The Sum of Its Parts

return time; } - Dictionary> Parse(string input) { + Dictionary<char, List<char>> Parse(string input) { var dict = ( - from line in input.Split("\n") - let parts = line.Split(" ") + from line in input.Split("\n") + let parts = line.Split(" ") let part = parts[7][0] let partDependsOn = parts[1][0] group partDependsOn by part into g select g - ).ToDictionary(g => g.Key, g => g.ToList()); + ).ToDictionary(g => g.Key, g => g.ToList()); - foreach (var key in new List(dict.Keys)) { + foreach (var key in new List<char>(dict.Keys)) { foreach (var d in dict[key]) { if (!dict.ContainsKey(d)) { - dict.Add(d, new List()); + dict.Add(d, new List<char>()); } } } diff --git a/2018/8/index.html b/2018/8/index.html index 3aebc44b..f2a3f78d 100644 --- a/2018/8/index.html +++ b/2018/8/index.html @@ -284,11 +284,11 @@

Memory Maneuver

namespace AdventOfCode.Y2018.Day08; -[ProblemName("Memory Maneuver")] +[ProblemName("Memory Maneuver")] class Solution : Solver { - public object PartOne(string input) => - Parse(input).fold(0, (cur, node) => cur + node.metadata.Sum()); + public object PartOne(string input) => + Parse(input).fold(0, (cur, node) => cur + node.metadata.Sum()); public object PartTwo(string input) { @@ -296,22 +296,22 @@

Memory Maneuver

} Node Parse(string input) { - var nums = input.Split(" ").Select(int.Parse).GetEnumerator(); - Func next = () => { + var nums = input.Split(" ").Select(int.Parse).GetEnumerator(); + Func<int> next = () => { nums.MoveNext(); return nums.Current; }; - Func read = null; - read = () => { + Func<Node> read = null; + read = () => { var node = new Node() { children = new Node[next()], metadata = new int[next()] }; - for (var i = 0; i < node.children.Length; i++) { + for (var i = 0; i < node.children.Length; i++) { node.children[i] = read(); } - for (var i = 0; i < node.metadata.Length; i++) { + for (var i = 0; i < node.metadata.Length; i++) { node.metadata[i] = next(); } return node; @@ -325,8 +325,8 @@

Memory Maneuver

class Node { public Node[] children; public int[] metadata; - public T fold(T seed, Func aggregate) { - return children.Aggregate(aggregate(seed, this), (cur, child) => child.fold(cur, aggregate)); + public T fold<T>(T seed, Func<T, Node, T> aggregate) { + return children.Aggregate(aggregate(seed, this), (cur, child) => child.fold(cur, aggregate)); } public int value() { @@ -336,7 +336,7 @@

Memory Maneuver

var res = 0; foreach(var i in metadata){ - if(i >= 1 && i <= children.Length){ + if(i >= 1 && i <= children.Length){ res += children[i-1].value(); } } diff --git a/2018/9/index.html b/2018/9/index.html index 707a0810..b4ef2c51 100644 --- a/2018/9/index.html +++ b/2018/9/index.html @@ -284,18 +284,18 @@

Marble Mania

namespace AdventOfCode.Y2018.Day09; -[ProblemName("Marble Mania")] +[ProblemName("Marble Mania")] class Solution : Solver { - public object PartOne(string input) => Solve(input, 1); + public object PartOne(string input) => Solve(input, 1); - public object PartTwo(string input) => Solve(input, 100); + public object PartTwo(string input) => Solve(input, 100); long Solve(string input, int mul) { - var match = Regex.Match(input, @"(?\d+) players; last marble is worth (?\d+) points"); - var players = new long[int.Parse(match.Groups["players"].Value)]; - var targetPoints = int.Parse(match.Groups["points"].Value) * mul; + var match = Regex.Match(input, @"(?<players>\d+) players; last marble is worth (?<points>\d+) points"); + var players = new long[int.Parse(match.Groups["players"].Value)]; + var targetPoints = int.Parse(match.Groups["points"].Value) * mul; var current = new Node { value = 0 }; current.left = current; @@ -303,10 +303,10 @@

Marble Mania

var points = 1; var iplayer = 1; - while (points <= targetPoints) { + while (points <= targetPoints) { if (points % 23 == 0) { - for (var i = 0; i < 7; i++) { + for (var i = 0; i < 7; i++) { current = current.left; } diff --git a/2019/1/index.html b/2019/1/index.html index 54252e5e..b127e33b 100644 --- a/2019/1/index.html +++ b/2019/1/index.html @@ -285,19 +285,19 @@

The Tyranny of the Rocket Equation

namespace AdventOfCode.Y2019.Day01; -[ProblemName("The Tyranny of the Rocket Equation")] +[ProblemName("The Tyranny of the Rocket Equation")] class Solution : Solver { - public object PartOne(string input) => Solve(input, false); - public object PartTwo(string input) => Solve(input, true); + public object PartOne(string input) => Solve(input, false); + public object PartTwo(string input) => Solve(input, true); int Solve(string input, bool recursive) { - var weights = new Queue(input.Split("\n").Select(x => int.Parse(x))); + var weights = new Queue<int>(input.Split("\n").Select(x => int.Parse(x))); var res = 0; while (weights.Any()) { var weight = weights.Dequeue(); var fuel = (int)(Math.Floor(weight / 3.0) - 2); - if (fuel > 0) { + if (fuel > 0) { if (recursive) { weights.Enqueue(fuel); } diff --git a/2019/10/index.html b/2019/10/index.html index a6cead44..5d2347fc 100644 --- a/2019/10/index.html +++ b/2019/10/index.html @@ -282,28 +282,28 @@

Monitoring Station

using System;
 using System.Collections.Generic;
 using System.Linq;
-using AsteroidsByDir = System.Collections.Generic.Dictionary<
-(int drow, int dcol), System.Collections.Generic.List<(int irow, int icol)>
->;
+using AsteroidsByDir = System.Collections.Generic.Dictionary<
+(int drow, int dcol), System.Collections.Generic.List<(int irow, int icol)>
+>;
 
 namespace AdventOfCode.Y2019.Day10;
 
-[ProblemName("Monitoring Station")]
+[ProblemName("Monitoring Station")]
 class Solution : Solver {
 
-    public object PartOne(string input) => SelectStationPosition(input).asteroidsByDir.Count;
+    public object PartOne(string input) => SelectStationPosition(input).asteroidsByDir.Count;
 
     public object PartTwo(string input) {
         var asteroid = Destroy(input).ElementAt(199);
         return (asteroid.icol * 100 + asteroid.irow);
     }
 
-    IEnumerable<(int irow, int icol)> Destroy(string input) {
+    IEnumerable<(int irow, int icol)> Destroy(string input) {
         var (station, asteroidsByDir) = SelectStationPosition(input);
 
         foreach (var dir in asteroidsByDir.Keys.ToArray()) {
             asteroidsByDir[dir] = asteroidsByDir[dir]
-                .OrderBy(a => Math.Abs(a.irow - station.irow) + Math.Abs(a.icol - station.icol))
+                .OrderBy(a => Math.Abs(a.irow - station.irow) + Math.Abs(a.icol - station.icol))
                 .ToList();
         }
 
@@ -321,8 +321,8 @@ 

Monitoring Station

} } - IEnumerable<(int drow, int dcol)> Rotate(IEnumerable<(int drow, int dcol)> dirs) { - var ordered = dirs.OrderBy(dir => -Math.Atan2(dir.dcol, dir.drow)).ToList(); + IEnumerable<(int drow, int dcol)> Rotate(IEnumerable<(int drow, int dcol)> dirs) { + var ordered = dirs.OrderBy(dir => -Math.Atan2(dir.dcol, dir.drow)).ToList(); for (var i = 0; ; i++) { yield return ordered[i % ordered.Count]; } @@ -342,12 +342,12 @@

Monitoring Station

var dir = (rowDir / gcd, colDir / gcd); if (!asteroidsByDir.ContainsKey(dir)) { - asteroidsByDir[dir] = new List<(int irow, int icol)>(); + asteroidsByDir[dir] = new List<(int irow, int icol)>(); } asteroidsByDir[dir].Add(asteroid); } } - if (asteroidsByDir.Count > res.asteroidsByDir.Count) { + if (asteroidsByDir.Count > res.asteroidsByDir.Count) { res = (station, asteroidsByDir); } } @@ -355,19 +355,19 @@

Monitoring Station

return res; } - List<(int irow, int icol)> Asteroids(string input) { - var map = input.Split("\n"); + List<(int irow, int icol)> Asteroids(string input) { + var map = input.Split("\n"); var (crow, ccol) = (map.Length, map[0].Length); return ( from irow in Enumerable.Range(0, crow) from icol in Enumerable.Range(0, ccol) - where map[irow][icol] == '#' + where map[irow][icol] == '#' select (irow, icol) ).ToList(); } - int Gcd(int a, int b) => b == 0 ? a : Gcd(b, a % b); + int Gcd(int a, int b) => b == 0 ? a : Gcd(b, a % b); }

Please ☆ my repo if you like it!

diff --git a/2019/11/index.html b/2019/11/index.html index a8d19ef7..52ffe068 100644 --- a/2019/11/index.html +++ b/2019/11/index.html @@ -285,32 +285,32 @@

Space Police

namespace AdventOfCode.Y2019.Day11; -[ProblemName("Space Police")] +[ProblemName("Space Police")] class Solution : Solver { - public object PartOne(string input) => Run(input, 0).Count; + public object PartOne(string input) => Run(input, 0).Count; public object PartTwo(string input) { var dict = Run(input, 1); - var irowMin = dict.Keys.Select(pos => pos.irow).Min(); - var icolMin = dict.Keys.Select(pos => pos.icol).Min(); - var irowMax = dict.Keys.Select(pos => pos.irow).Max(); - var icolMax = dict.Keys.Select(pos => pos.icol).Max(); + var irowMin = dict.Keys.Select(pos => pos.irow).Min(); + var icolMin = dict.Keys.Select(pos => pos.icol).Min(); + var irowMax = dict.Keys.Select(pos => pos.irow).Max(); + var icolMax = dict.Keys.Select(pos => pos.icol).Max(); var crow = irowMax - irowMin + 1; var ccol = icolMax - icolMin + 1; - var st = ""; - for (var irow = 0; irow < crow; irow++) { - for (var icol = 0; icol < ccol; icol++) { - st += " #"[dict.GetValueOrDefault((irowMin + irow, icolMin + icol), 0)]; + var st = ""; + for (var irow = 0; irow < crow; irow++) { + for (var icol = 0; icol < ccol; icol++) { + st += " #"[dict.GetValueOrDefault((irowMin + irow, icolMin + icol), 0)]; } - st += "\n"; + st += "\n"; } return st.Ocr(); } - Dictionary<(int irow, int icol), int> Run(string input, int startColor) { - var mtx = new Dictionary<(int irow, int icol), int>(); + Dictionary<(int irow, int icol), int> Run(string input, int startColor) { + var mtx = new Dictionary<(int irow, int icol), int>(); (int irow, int icol) pos = (0, 0); (int drow, int dcol) dir = (-1, 0); mtx[(0, 0)] = startColor; @@ -322,9 +322,9 @@

Space Police

} mtx[pos] = (int)output[0]; dir = output[1] switch { - 0 => (-dir.dcol, dir.drow), - 1 => (dir.dcol, -dir.drow), - _ => throw new ArgumentException() + 0 => (-dir.dcol, dir.drow), + 1 => (dir.dcol, -dir.drow), + _ => throw new ArgumentException() }; pos = (pos.irow + dir.drow, pos.icol + dir.dcol); } diff --git a/2019/12/index.html b/2019/12/index.html index 33c88ff3..b9016cf9 100644 --- a/2019/12/index.html +++ b/2019/12/index.html @@ -286,10 +286,10 @@

The N-Body Problem

namespace AdventOfCode.Y2019.Day12; -[ProblemName("The N-Body Problem")] +[ProblemName("The N-Body Problem")] class Solution : Solver { - public object PartOne(string input) => ( + public object PartOne(string input) => ( from planet in Simulate(input).ElementAt(999) let pot = planet.pos.Select(Math.Abs).Sum() let kin = planet.vel.Select(Math.Abs).Sum() @@ -298,8 +298,8 @@

The N-Body Problem

public object PartTwo(string input) { var statesByDim = new long[3]; - for (var dim = 0; dim < 3; dim++) { - var states = new HashSet<(int,int,int,int,int,int,int,int)>(); + for (var dim = 0; dim < 3; dim++) { + var states = new HashSet<(int,int,int,int,int,int,int,int)>(); foreach (var planets in Simulate(input)) { var state = (planets[0].pos[dim], planets[1].pos[dim], planets[2].pos[dim], planets[3].pos[dim], planets[0].vel[dim], planets[1].vel[dim], planets[2].vel[dim], planets[3].vel[dim]); @@ -314,13 +314,13 @@

The N-Body Problem

return Lcm(statesByDim[0], Lcm(statesByDim[1], statesByDim[2])); } - long Lcm(long a, long b) => a * b / Gcd(a, b); - long Gcd(long a, long b) => b == 0 ? a : Gcd(b, a % b); + long Lcm(long a, long b) => a * b / Gcd(a, b); + long Gcd(long a, long b) => b == 0 ? a : Gcd(b, a % b); - IEnumerable<(int[] pos, int[] vel)[]> Simulate(string input) { + IEnumerable<(int[] pos, int[] vel)[]> Simulate(string input) { var planets = ( - from line in input.Split("\n") - let m = Regex.Matches(line, @"-?\d+") + from line in input.Split("\n") + let m = Regex.Matches(line, @"-?\d+") let pos = (from v in m select int.Parse(v.Value)).ToArray() let vel = new int[3] select (pos, vel) @@ -329,14 +329,14 @@

The N-Body Problem

while (true) { foreach (var planetA in planets) { foreach (var planetB in planets) { - for (var dim = 0; dim < 3; dim++) { + for (var dim = 0; dim < 3; dim++) { planetA.vel[dim] += Math.Sign(planetB.pos[dim] - planetA.pos[dim]); } } } foreach (var planet in planets) { - for (var dim = 0; dim < 3; dim++) { + for (var dim = 0; dim < 3; dim++) { planet.pos[dim] += planet.vel[dim]; } } diff --git a/2019/13/index.html b/2019/13/index.html index 2d928445..5bfa437d 100644 --- a/2019/13/index.html +++ b/2019/13/index.html @@ -284,14 +284,14 @@

Care Package

namespace AdventOfCode.Y2019.Day13; -[ProblemName("Care Package")] +[ProblemName("Care Package")] class Solution : Solver { public object PartOne(string input) { var icm = new IntCodeMachine(input); var output = icm.Run(); var chunks = Chunk(output, 3); - return chunks.Count(x => x[2] == 2); + return chunks.Count(x => x[2] == 2); } public object PartTwo(string input) { @@ -320,16 +320,16 @@

Care Package

} dir = - icolBall < icolPaddle ? -1 : - icolBall > icolPaddle ? 1 : + icolBall < icolPaddle ? -1 : + icolBall > icolPaddle ? 1 : 0; } return score; } - public T[][] Chunk(IEnumerable source, int chunksize) { - var res = new List(); + public T[][] Chunk<T>(IEnumerable<T> source, int chunksize) { + var res = new List<T[]>(); while (source.Any()) { res.Add(source.Take(chunksize).ToArray()); source = source.Skip(chunksize); diff --git a/2019/14/index.html b/2019/14/index.html index 820182eb..8601bea8 100644 --- a/2019/14/index.html +++ b/2019/14/index.html @@ -285,10 +285,10 @@

Space Stoichiometry

namespace AdventOfCode.Y2019.Day14; -[ProblemName("Space Stoichiometry")] +[ProblemName("Space Stoichiometry")] class Solution : Solver { - public object PartOne(string input) => Parse(input)(1); + public object PartOne(string input) => Parse(input)(1); public object PartTwo(string input) { var oreForFuel = Parse(input); @@ -296,8 +296,8 @@

Space Stoichiometry

var fuel = 1L; while (true) { - // newFuel <= the amount we can produce with the given ore - // since (double)ore / oreForFuel(fuel) >= 1, fuel becomes + // newFuel <= the amount we can produce with the given ore + // since (double)ore / oreForFuel(fuel) >= 1, fuel becomes // a better estimation in each iteration until it reaches // the maximum @@ -310,30 +310,30 @@

Space Stoichiometry

} } - Func Parse(string productionRules) { + Func<long, long> Parse(string productionRules) { (string chemical, long amount) ParseReagent(string st) { - var parts = st.Split(" "); + var parts = st.Split(" "); return (parts[1], long.Parse(parts[0])); } var reactions = ( - from rule in productionRules.Split("\n") - let inout = rule.Split(" => ") - let input = inout[0].Split(", ").Select(ParseReagent).ToArray() + from rule in productionRules.Split("\n") + let inout = rule.Split(" => ") + let input = inout[0].Split(", ").Select(ParseReagent).ToArray() let output = ParseReagent(inout[1]) select (output, input) - ).ToDictionary(inout => inout.output.chemical, inout => inout); + ).ToDictionary(inout => inout.output.chemical, inout => inout); - return (fuel) => { + return (fuel) => { var ore = 0L; - var inventory = reactions.Keys.ToDictionary(chemical => chemical, _ => 0L); - var productionList = new Queue<(string chemical, long amount)>(); - productionList.Enqueue(("FUEL", fuel)); + var inventory = reactions.Keys.ToDictionary(chemical => chemical, _ => 0L); + var productionList = new Queue<(string chemical, long amount)>(); + productionList.Enqueue(("FUEL", fuel)); while (productionList.Any()) { var (chemical, amount) = productionList.Dequeue(); - if (chemical == "ORE") { + if (chemical == "ORE") { ore += amount; } else { var reaction = reactions[chemical]; @@ -342,7 +342,7 @@

Space Stoichiometry

amount -= useFromInventory; inventory[chemical] -= useFromInventory; - if (amount > 0) { + if (amount > 0) { var multiplier = (long)Math.Ceiling((decimal)amount / reaction.output.amount); inventory[chemical] = Math.Max(0, multiplier * reaction.output.amount - amount); diff --git a/2019/15/index.html b/2019/15/index.html index 55adefa3..5a9c1145 100644 --- a/2019/15/index.html +++ b/2019/15/index.html @@ -285,7 +285,7 @@

Oxygen System

namespace AdventOfCode.Y2019.Day15; -[ProblemName("Oxygen System")] +[ProblemName("Oxygen System")] class Solution : Solver { enum Tile { @@ -296,25 +296,25 @@

Oxygen System

public object PartOne(string input) { var iicm = new ImmutableIntCodeMachine(input); - return Bfs(iicm).First(s => s.tile == Tile.O2).path.Count; + return Bfs(iicm).First(s => s.tile == Tile.O2).path.Count; } public object PartTwo(string input) { - var iicm = Bfs(new ImmutableIntCodeMachine(input)).First(s => s.tile == Tile.O2).iicm; + var iicm = Bfs(new ImmutableIntCodeMachine(input)).First(s => s.tile == Tile.O2).iicm; return Bfs(iicm).Last().path.Count; } - IEnumerable<(ImmutableIntCodeMachine iicm, ImmutableList path, Tile tile)> Bfs(ImmutableIntCodeMachine startIicm) { + IEnumerable<(ImmutableIntCodeMachine iicm, ImmutableList<int> path, Tile tile)> Bfs(ImmutableIntCodeMachine startIicm) { (int dx, int dy)[] dirs = new[] { (0, -1), (0, 1), (-1, 0), (1, 0) }; - var seen = new HashSet<(int x, int y)> { (0, 0) }; - var q = new Queue<(ImmutableIntCodeMachine iicm, ImmutableList path, int x, int y)>(); - q.Enqueue((startIicm, ImmutableList.Empty, 0, 0)); + var seen = new HashSet<(int x, int y)> { (0, 0) }; + var q = new Queue<(ImmutableIntCodeMachine iicm, ImmutableList<int> path, int x, int y)>(); + q.Enqueue((startIicm, ImmutableList<int>.Empty, 0, 0)); while (q.Any()) { var current = q.Dequeue(); - for (var i = 0; i < dirs.Length; i++) { + for (var i = 0; i < dirs.Length; i++) { var (nextX, nextY) = (current.x + dirs[i].dx, current.y + dirs[i].dy); if (!seen.Contains((nextX, nextY))) { diff --git a/2019/16/index.html b/2019/16/index.html index 70587fe9..c88f3ed5 100644 --- a/2019/16/index.html +++ b/2019/16/index.html @@ -286,17 +286,17 @@

Flawed Frequency Transmission

namespace AdventOfCode.Y2019.Day16; -[ProblemName("Flawed Frequency Transmission")] +[ProblemName("Flawed Frequency Transmission")] class Solution : Solver { public object PartOne(string input) { int[] Fft(int[] digits) { - IEnumerable Pattern(int digit) { + IEnumerable<int> Pattern(int digit) { var repeat = digit + 1; while (true) { foreach (var item in new[] { 0, 1, 0, -1 }) { - for (var i = 0; i < repeat; i++) { + for (var i = 0; i < repeat; i++) { yield return item; } } @@ -311,18 +311,18 @@

Flawed Frequency Transmission

).ToArray(); } - var digits = input.Select(ch => int.Parse(ch.ToString())).ToArray(); + var digits = input.Select(ch => int.Parse(ch.ToString())).ToArray(); - for (var i = 0; i < 100; i++) { + for (var i = 0; i < 100; i++) { digits = Fft(digits); } - return string.Join("", digits.Take(8)); + return string.Join("", digits.Take(8)); } public object PartTwo(string input) { /* - Let's introduce the following matrix: + Let's introduce the following matrix: FFT = [ 1, 0, -1, 0, 1, 0, -1, 0, ... 0, 1, 1, 0, 0, -1, -1, 0, ... @@ -348,7 +348,7 @@

Flawed Frequency Transmission

] The problem asks for output components that correspond to multiplication with rows in this area. - Examining A's powers reveal that the the first row can be: + Examining A's powers reveal that the the first row can be: the numbers from 1-n, A^2 = [ 1, 2, 3, 4, ... @@ -398,8 +398,8 @@

Flawed Frequency Transmission

we need to compute [B]_{1..7} * xs % 10, where xs is the digits of input repeated 10000 times shifted with t */ - var xs = input.Select(ch => int.Parse(ch.ToString())).ToArray(); - var res = ""; + var xs = input.Select(ch => int.Parse(ch.ToString())).ToArray(); + var res = ""; var t = int.Parse(input.Substring(0, 7)); var crow = 8; @@ -407,14 +407,14 @@

Flawed Frequency Transmission

var bijMods = new int[ccol + 1]; var bij = new BigInteger(1); - for (var j = 1; j <= ccol; j++) { + for (var j = 1; j <= ccol; j++) { bijMods[j] = (int)(bij % 10); bij = bij * (j + 99) / j; } - for (var i = 1; i <= crow; i++) { + for (var i = 1; i <= crow; i++) { var s = 0; - for (var j = i; j <= ccol; j++) { + for (var j = i; j <= ccol; j++) { var x = xs[(t + j - 1) % input.Length]; s += x * bijMods[j - i + 1]; } diff --git a/2019/17/index.html b/2019/17/index.html index d9292ee5..25830282 100644 --- a/2019/17/index.html +++ b/2019/17/index.html @@ -286,7 +286,7 @@

Set and Forget

namespace AdventOfCode.Y2019.Day17; -[ProblemName("Set and Forget")] +[ProblemName("Set and Forget")] class Solution : Solver { public object PartOne(string input) { @@ -294,13 +294,13 @@

Set and Forget

var crow = mx.Length; var ccol = mx[0].Length; - var cross = ".#.\n###\n.#.".Split("\n"); + var cross = ".#.\n###\n.#.".Split("\n"); - bool crossing(int irow, int icol) => ( + bool crossing(int irow, int icol) => ( from drow in new[] { -1, 0, 1 } from dcol in new[] { -1, 0, 1 } select cross[1 + drow][1 + dcol] == mx[irow + drow][icol + dcol] - ).All(x => x); + ).All(x => x); return ( from irow in Enumerable.Range(1, crow - 2) @@ -321,17 +321,17 @@

Set and Forget

string[] Screenshot(string input) { var icm = new IntCodeMachine(input); var output = icm.Run(); - return output.ToAscii().Split("\n").Where(x => !string.IsNullOrWhiteSpace(x)).ToArray(); + return output.ToAscii().Split("\n").Where(x => !string.IsNullOrWhiteSpace(x)).ToArray(); } - IEnumerable GeneratePrograms(string path) { + IEnumerable<string> GeneratePrograms(string path) { - IEnumerable<(ImmutableList indices, ImmutableList functions)> GenerateRec(string path, ImmutableList functions) { + IEnumerable<(ImmutableList<int> indices, ImmutableList<string> functions)> GenerateRec(string path, ImmutableList<string> functions) { if (path.Length == 0) { - yield return (ImmutableList.Empty, functions); + yield return (ImmutableList<int>.Empty, functions); } - for (var i = 0; i < functions.Count; i++) { + for (var i = 0; i < functions.Count; i++) { var function = functions[i]; if (path.StartsWith(function)) { @@ -343,8 +343,8 @@

Set and Forget

} } - if (functions.Count < 3) { - for (var length = 1; length <= path.Length; length++) { + if (functions.Count < 3) { + for (var length = 1; length <= path.Length; length++) { var function = path[0..length].ToString(); var functionsT = functions.Add(function); var idx = functions.Count; @@ -356,38 +356,38 @@

Set and Forget

} } - foreach (var (indices, functions) in GenerateRec(path, ImmutableList.Empty)) { + foreach (var (indices, functions) in GenerateRec(path, ImmutableList<string>.Empty)) { var compressed = functions.Select(Compress).ToArray(); - if (indices.Count <= 20 && compressed.All(c => c.Length <= 20)) { + if (indices.Count <= 20 && compressed.All(c => c.Length <= 20)) { - var main = string.Join(",", indices.Select(i => "ABC"[i])); - yield return $"{main}\n{compressed[0]}\n{compressed[1]}\n{compressed[2]}\nn\n"; + var main = string.Join(",", indices.Select(i => "ABC"[i])); + yield return $"{main}\n{compressed[0]}\n{compressed[1]}\n{compressed[2]}\nn\n"; } } } string Compress(string st) { - var steps = new List(); + var steps = new List<string>(); var l = 0; - for (var i = 0; i < st.Length; i++) { + for (var i = 0; i < st.Length; i++) { var ch = st[i]; - if (l > 0 && ch != 'F') { + if (l > 0 && ch != 'F') { steps.Add(l.ToString()); l = 0; } - if (ch == 'R' || ch == 'L') { + if (ch == 'R' || ch == 'L') { steps.Add(ch.ToString()); } else { l++; } } - if (l > 0) { + if (l > 0) { steps.Add(l.ToString()); } - return string.Join(",", steps); + return string.Join(",", steps); } string Path(string input) { @@ -398,20 +398,20 @@

Set and Forget

var (pos, dir) = FindRobot(mx); char look((int irow, int icol) pos) { var (irow, icol) = pos; - return irow < 0 || irow >= crow || icol < 0 || icol >= ccol ? '.' : mx[irow][icol]; + return irow < 0 || irow >= crow || icol < 0 || icol >= ccol ? '.' : mx[irow][icol]; } - var path = ""; + var path = ""; var finished = false; while (!finished) { finished = true; foreach (var (nextDir, step) in new[]{ - ((drow: dir.drow, dcol: dir.dcol), "F"), - ((drow: -dir.dcol, dcol: dir.drow), "LF"), - ((drow: dir.dcol, dcol: -dir.drow), "RF") + ((drow: dir.drow, dcol: dir.dcol), "F"), + ((drow: -dir.dcol, dcol: dir.drow), "LF"), + ((drow: dir.dcol, dcol: -dir.drow), "RF") }) { var nextPos = (pos.irow + nextDir.drow, pos.icol + nextDir.dcol); - if (look(nextPos) == '#') { + if (look(nextPos) == '#') { path += step; pos = nextPos; dir = nextDir; @@ -423,18 +423,18 @@

Set and Forget

return path; } - ((int irow, int icol) pos, (int drow, int dcol) dir) FindRobot(string[] mx) => ( + ((int irow, int icol) pos, (int drow, int dcol) dir) FindRobot(string[] mx) => ( from irow in Enumerable.Range(0, mx.Length) from icol in Enumerable.Range(0, mx[0].Length) let ch = mx[irow][icol] - where "^v<>".Contains(ch) + where "^v<>".Contains(ch) let dir = mx[irow][icol] switch { - '^' => (-1, 0), - 'v' => (1, 0), - '<' => (0, -1), - '>' => (0, 1), - _ => throw new Exception() + '^' => (-1, 0), + 'v' => (1, 0), + '<' => (0, -1), + '>' => (0, 1), + _ => throw new Exception() } select ((irow, icol), dir) ).First(); diff --git a/2019/18/index.html b/2019/18/index.html index c49ae474..b6979ca6 100644 --- a/2019/18/index.html +++ b/2019/18/index.html @@ -290,17 +290,17 @@

Many-Worlds Interpretation

class Maze { string[] maze; public Maze(string st) { - this.maze = st.Split("\n"); + this.maze = st.Split("\n"); } - int ccol => maze[0].Length; - int crow => maze.Length; - Dictionary positionCache = new Dictionary(); - Dictionary<(char, char), int> distanceCache = new Dictionary<(char, char), int>(); + int ccol => maze[0].Length; + int crow => maze.Length; + Dictionary<char, (int, int)> positionCache = new Dictionary<char, (int, int)>(); + Dictionary<(char, char), int> distanceCache = new Dictionary<(char, char), int>(); public char Look((int irow, int icol) pos) { var (irow, icol) = pos; - if (irow < 0 || irow >= crow || icol < 0 || icol >= ccol) { - return '#'; + if (irow < 0 || irow >= crow || icol < 0 || icol >= ccol) { + return '#'; } return maze[irow][icol]; @@ -308,8 +308,8 @@

Many-Worlds Interpretation

public (int irow, int icol) Find(char ch) { if (!positionCache.ContainsKey(ch)) { - for (var irow = 0; irow < crow; irow++) { - for (var icol = 0; icol < ccol; icol++) { + for (var irow = 0; irow < crow; irow++) { + for (var icol = 0; icol < ccol; icol++) { if (maze[irow][icol] == ch) { positionCache[ch] = (irow, icol); return positionCache[ch]; @@ -336,11 +336,11 @@

Many-Worlds Interpretation

if (chA == chB) { return 0; } - var q = new Queue<((int irow, int icol) pos, int dist)>(); + var q = new Queue<((int irow, int icol) pos, int dist)>(); int dist = 0; q.Enqueue((pos, dist)); - var seen = new HashSet<(int irow, int icol)>(); + var seen = new HashSet<(int irow, int icol)>(); seen.Add(pos); while (q.Any()) { (pos, dist) = q.Dequeue(); @@ -349,7 +349,7 @@

Many-Worlds Interpretation

var posT = (pos.irow + drow, pos.icol + dcol); var ch = Look(posT); - if (seen.Contains(posT) || ch == '#') { + if (seen.Contains(posT) || ch == '#') { continue; } @@ -367,7 +367,7 @@

Many-Worlds Interpretation

} } -[ProblemName("Many-Worlds Interpretation")] +[ProblemName("Many-Worlds Interpretation")] class Solution : Solver { public object PartOne(string input) { @@ -390,13 +390,13 @@

Many-Worlds Interpretation

return d; } - IEnumerable GenerateSubMazes(string input) { - var mx = input.Split("\n").Select(x => x.ToCharArray()).ToArray(); + IEnumerable<string> GenerateSubMazes(string input) { + var mx = input.Split("\n").Select(x => x.ToCharArray()).ToArray(); var crow = mx.Length; var ccol = mx[0].Length; var hrow = crow / 2; var hcol = ccol / 2; - var pattern = "@#@\n###\n@#@".Split(); + var pattern = "@#@\n###\n@#@".Split(); foreach (var drow in new[] { -1, 0, 1 }) { foreach (var dcol in new[] { -1, 0, 1 }) { mx[hrow + drow][hcol + dcol] = pattern[1 + drow][1 + dcol]; @@ -404,14 +404,14 @@

Many-Worlds Interpretation

} foreach (var (drow, dcol) in new[] { (0, 0), (0, hcol + 1), (hrow + 1, 0), (hrow + 1, hcol + 1) }) { - var res = ""; - for (var irow = 0; irow < hrow; irow++) { - res += string.Join("", mx[irow + drow].Skip(dcol).Take(hcol)) + "\n"; + var res = ""; + for (var irow = 0; irow < hrow; irow++) { + res += string.Join("", mx[irow + drow].Skip(dcol).Take(hcol)) + "\n"; } - for (var ch = 'A'; ch <= 'Z'; ch++) { + for (var ch = 'A'; ch <= 'Z'; ch++) { if (!res.Contains(char.ToLower(ch))) { - res = res.Replace(ch, '.'); + res = res.Replace(ch, '.'); } } res = res.Substring(0, res.Length - 1); @@ -422,14 +422,14 @@

Many-Worlds Interpretation

int Solve(Maze maze) { var dependencies = GenerateDependencies(maze); - var cache = new Dictionary(); + var cache = new Dictionary<string, int>(); - int SolveRecursive(char currentItem, ImmutableHashSet keys + int SolveRecursive(char currentItem, ImmutableHashSet<char> keys ) { if (keys.Count == 0) { return 0; } - var cacheKey = currentItem + string.Join("", keys); + var cacheKey = currentItem + string.Join("", keys); if (!cache.ContainsKey(cacheKey)) { var result = int.MaxValue; @@ -444,17 +444,17 @@

Many-Worlds Interpretation

return cache[cacheKey]; } - return SolveRecursive('@', dependencies.Keys.ToImmutableHashSet()); + return SolveRecursive('@', dependencies.Keys.ToImmutableHashSet()); } - Dictionary> GenerateDependencies(Maze maze) { - var q = new Queue<((int irow, int icol) pos, string dependsOn)>(); - var pos = maze.Find('@'); - var dependsOn = ""; + Dictionary<char, ImmutableHashSet<char>> GenerateDependencies(Maze maze) { + var q = new Queue<((int irow, int icol) pos, string dependsOn)>(); + var pos = maze.Find('@'); + var dependsOn = ""; q.Enqueue((pos, dependsOn)); - var res = new Dictionary>(); - var seen = new HashSet<(int irow, int icol)>(); + var res = new Dictionary<char, ImmutableHashSet<char>>(); + var seen = new HashSet<(int irow, int icol)>(); seen.Add(pos); while (q.Any()) { (pos, dependsOn) = q.Dequeue(); @@ -463,7 +463,7 @@

Many-Worlds Interpretation

var posT = (pos.irow + drow, pos.icol + dcol); var ch = maze.Look(posT); - if (seen.Contains(posT) || ch == '#') { + if (seen.Contains(posT) || ch == '#') { continue; } diff --git a/2019/19/index.html b/2019/19/index.html index a6e046e1..ea95de25 100644 --- a/2019/19/index.html +++ b/2019/19/index.html @@ -284,12 +284,12 @@

Tractor Beam

namespace AdventOfCode.Y2019.Day19; -[ProblemName("Tractor Beam")] +[ProblemName("Tractor Beam")] class Solution : Solver { - Func Detector(string input) { + Func<int, int, bool> Detector(string input) { var icm = new ImmutableIntCodeMachine(input); - return (int x, int y) => { + return (int x, int y) => { var (_, output) = icm.Run(x, y); return output[0] == 1; }; @@ -314,7 +314,7 @@

Tractor Beam

} var x = xStart; while (detector(x + 99, y)) { - if (detector(x, y + 99) && detector(x + 99, y + 99)) { + if (detector(x, y + 99) && detector(x + 99, y + 99)) { return (x * 10000 + y); } x++; diff --git a/2019/2/index.html b/2019/2/index.html index df7b7a81..de54993b 100644 --- a/2019/2/index.html +++ b/2019/2/index.html @@ -283,16 +283,16 @@

1202 Program Alarm

namespace AdventOfCode.Y2019.Day02; -[ProblemName("1202 Program Alarm")] +[ProblemName("1202 Program Alarm")] class Solution : Solver { - public object PartOne(string input) => ExecIntCode(new IntCodeMachine(input), 12, 2); + public object PartOne(string input) => ExecIntCode(new IntCodeMachine(input), 12, 2); public object PartTwo(string input) { var icm = new IntCodeMachine(input); for (var sum = 0; ; sum++) { - for (var verb = 0; verb <= sum; verb++) { + for (var verb = 0; verb <= sum; verb++) { var noun = sum - verb; var res = ExecIntCode(icm, noun, verb); if (res == 19690720) { diff --git a/2019/20/index.html b/2019/20/index.html index 03ad80b0..a96afc59 100644 --- a/2019/20/index.html +++ b/2019/20/index.html @@ -289,7 +289,7 @@

Donut Maze

record Pos3(int irow, int icol, int level); record PosD(int irow, int icol, int dlevel); -[ProblemName("Donut Maze")] +[ProblemName("Donut Maze")] class Solution : Solver { public object PartOne(string input) { @@ -301,18 +301,18 @@

Donut Maze

} int Solve(string input, bool part2) { - var mx = input.Split("\n").Select(x => x.ToCharArray()).ToArray(); + var mx = input.Split("\n").Select(x => x.ToCharArray()).ToArray(); var (portals, start, end) = Explore(mx); var pos = start; var dist = 0; - var q = new Queue<(Pos3, int dist)>(); + var q = new Queue<(Pos3, int dist)>(); q.Enqueue((pos, dist)); - var seen = new HashSet(); + var seen = new HashSet<Pos3>(); seen.Add(pos); - IEnumerable Neighbours(Pos3 pos) { + IEnumerable<Pos3> Neighbours(Pos3 pos) { foreach (var (drow, dcol) in new[] { (0, -1), (0, 1), (-1, 0), (1, 0) }) { yield return new (pos.irow + drow, pos.icol + dcol, pos.level); } @@ -324,7 +324,7 @@

Donut Maze

dlevel = 0; } - if (pos.level + dlevel >= 0) { + if (pos.level + dlevel >= 0) { yield return new (irowT, icolT, pos.level + dlevel); } } @@ -339,7 +339,7 @@

Donut Maze

foreach (var posT in Neighbours(pos)) { if (!seen.Contains(posT)) { var distT = dist + 1; - if (mx[posT.irow][posT.icol] == '.') { + if (mx[posT.irow][posT.icol] == '.') { seen.Add(posT); q.Enqueue((posT, distT)); } @@ -350,17 +350,17 @@

Donut Maze

throw new Exception(); } - (Dictionary portals, Pos3 start, Pos3 goal) Explore(char[][] mx) { - var portals = new Dictionary(); - var tmp = new Dictionary(); + (Dictionary<Pos2, PosD> portals, Pos3 start, Pos3 goal) Explore(char[][] mx) { + var portals = new Dictionary<Pos2, PosD>(); + var tmp = new Dictionary<string, Pos2>(); var ccol = mx[0].Length; var crow = mx.Length; - for (var irow = 0; irow < crow - 1; irow++) { - for (var icol = 0; icol < ccol - 1; icol++) { + for (var irow = 0; irow < crow - 1; irow++) { + for (var icol = 0; icol < ccol - 1; icol++) { foreach (var (drow, dcol) in new[] { (0, 1), (1, 0) }) { - var st = $"{mx[irow][icol]}{mx[irow + drow][icol + dcol]}"; + var st = $"{mx[irow][icol]}{mx[irow + drow][icol + dcol]}"; if (st.All(char.IsLetter)) { - var portal = irow - drow >= 0 && icol - dcol >= 0 && mx[irow - drow][icol - dcol] == '.' ? + var portal = irow - drow >= 0 && icol - dcol >= 0 && mx[irow - drow][icol - dcol] == '.' ? new Pos2(irow - drow, icol - dcol) : new Pos2(irow + 2 * drow, icol + 2 * dcol); @@ -371,14 +371,14 @@

Donut Maze

} else { tmp[st] = portal; } - mx[irow][icol] = ' '; - mx[irow + drow][icol + dcol] = ' '; + mx[irow][icol] = ' '; + mx[irow + drow][icol + dcol] = ' '; } } } } - return (portals, new (tmp["AA"].irow, tmp["AA"].icol, 0), new (tmp["ZZ"].irow, tmp["ZZ"].icol, 0)); + return (portals, new (tmp["AA"].irow, tmp["AA"].icol, 0), new (tmp["ZZ"].irow, tmp["ZZ"].icol, 0)); } } diff --git a/2019/21/index.html b/2019/21/index.html index 60416f07..4db986a4 100644 --- a/2019/21/index.html +++ b/2019/21/index.html @@ -283,7 +283,7 @@

Springdroid Adventure

namespace AdventOfCode.Y2019.Day21; -[ProblemName("Springdroid Adventure")] +[ProblemName("Springdroid Adventure")] class Solution : Solver { public object PartOne(string input) { @@ -292,12 +292,12 @@

Springdroid Adventure

// J = (¬A ∨ ¬B ∨ ¬C) ∧ D // jump if no road ahead, but we can continue from D return new IntCodeMachine(input).Run( - "OR A T", - "AND B T", - "AND C T", - "NOT T J", - "AND D J", - "WALK" + "OR A T", + "AND B T", + "AND C T", + "NOT T J", + "AND D J", + "WALK" ).Last(); } @@ -306,15 +306,15 @@

Springdroid Adventure

// J = (¬A ∨ ¬B ∨ ¬C) ∧ D ∧ (H ∨ E) // same as part 1, but also check that D is not a dead end return new IntCodeMachine(input).Run( - "OR A T", - "AND B T", - "AND C T", - "NOT T J", - "AND D J", - "OR H T", - "OR E T", - "AND T J", - "RUN" + "OR A T", + "AND B T", + "AND C T", + "NOT T J", + "AND D J", + "OR H T", + "OR E T", + "AND T J", + "RUN" ).Last(); } } diff --git a/2019/22/index.html b/2019/22/index.html index 9fd38f04..6a2c5bfa 100644 --- a/2019/22/index.html +++ b/2019/22/index.html @@ -285,7 +285,7 @@

Slam Shuffle

namespace AdventOfCode.Y2019.Day22; -[ProblemName("Slam Shuffle")] +[ProblemName("Slam Shuffle")] class Solution : Solver { public object PartOne(string input) { @@ -303,22 +303,22 @@

Slam Shuffle

return Mod(ModInv(a, m) * (2020 - b), m); } - BigInteger Mod(BigInteger a, BigInteger m) => ((a % m) + m) % m; - BigInteger ModInv(BigInteger a, BigInteger m) => BigInteger.ModPow(a, m - 2, m); + BigInteger Mod(BigInteger a, BigInteger m) => ((a % m) + m) % m; + BigInteger ModInv(BigInteger a, BigInteger m) => BigInteger.ModPow(a, m - 2, m); (BigInteger a, BigInteger big) Parse(string input, long m, long n) { var a = new BigInteger(1); var b = new BigInteger(0); - foreach (var line in input.Split('\n')) { - if (line.Contains("into new stack")) { + foreach (var line in input.Split('\n')) { + if (line.Contains("into new stack")) { a = -a; b = m - b - 1; - } else if (line.Contains("cut")) { - var i = long.Parse(Regex.Match(line, @"-?\d+").Value); + } else if (line.Contains("cut")) { + var i = long.Parse(Regex.Match(line, @"-?\d+").Value); b = m + b - i; - } else if (line.Contains("increment")) { - var i = long.Parse(Regex.Match(line, @"-?\d+").Value); + } else if (line.Contains("increment")) { + var i = long.Parse(Regex.Match(line, @"-?\d+").Value); a *= i; b *= i; } else { diff --git a/2019/23/index.html b/2019/23/index.html index 02a5e45b..8399aadc 100644 --- a/2019/23/index.html +++ b/2019/23/index.html @@ -283,15 +283,15 @@

Category Six

using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using Packets = System.Collections.Generic.List<(long address, long x, long y)>; +using Packets = System.Collections.Generic.List<(long address, long x, long y)>; namespace AdventOfCode.Y2019.Day23; -[ProblemName("Category Six")] +[ProblemName("Category Six")] class Solution : Solver { - public object PartOne(string input) => Solve(input, false); - public object PartTwo(string input) => Solve(input, true); + public object PartOne(string input) => Solve(input, false); + public object PartTwo(string input) => Solve(input, true); long Solve(string input, bool hasNat) { var machines = ( @@ -306,17 +306,17 @@

Category Six

} var packets = new Packets(); - while (!packets.Any(packet => packet.address == natAddress)) { + while (!packets.Any(packet => packet.address == natAddress)) { foreach (var machine in machines) { packets = machine(packets); } } - return packets.Single(packet => packet.address == natAddress).y; + return packets.Single(packet => packet.address == natAddress).y; } - (List data, Packets packets) Receive(Packets packets, int address) { + (List<long> data, Packets packets) Receive(Packets packets, int address) { var filteredPackets = new Packets(); - var data = new List(); + var data = new List<long>(); foreach (var packet in packets) { if (packet.address == address) { data.Add(packet.x); @@ -328,35 +328,35 @@

Category Six

return (data, filteredPackets); } - Func Nic(string program, int address) { + Func<Packets, Packets> Nic(string program, int address) { var icm = new IntCodeMachine(program); var output = icm.Run(address); Debug.Assert(output.Count == 0); - return (input) => { + return (input) => { var (data, packets) = Receive(input, address); if (!data.Any()) { data.Add(-1); } var output = icm.Run(data.ToArray()); - for (var d = 0; d < output.Count; d += 3) { + for (var d = 0; d < output.Count; d += 3) { packets.Add((output[d], output[d + 1], output[d + 2])); } return packets; }; } - Func Nat(int address) { + Func<Packets, Packets> Nat(int address) { long? yLastSent = null; long? x = null; long? y = null; - return (input) => { + return (input) => { var (data, packets) = Receive(input, address); if (data.Any()) { (x, y) = (data[^2], data[^1]); } if (packets.Count == 0) { - Debug.Assert(x.HasValue && y.HasValue); + Debug.Assert(x.HasValue && y.HasValue); packets.Add((y == yLastSent ? 255 : 0, x.Value, y.Value)); yLastSent = y; } diff --git a/2019/24/index.html b/2019/24/index.html index 8db3815c..b4970eb1 100644 --- a/2019/24/index.html +++ b/2019/24/index.html @@ -287,18 +287,18 @@

Planet of Discord

record Position(int ilevel, int irow, int icol); -[ProblemName("Planet of Discord")] +[ProblemName("Planet of Discord")] class Solution : Solver { public object PartOne(string input) { int[] levels = Parse(input); - var seen = new HashSet(); + var seen = new HashSet<int>(); var biodiversity = levels[0]; while (!seen.Contains(biodiversity)) { seen.Add(biodiversity); levels = Step(levels, FlatNeighbours); - biodiversity = levels[levels.Length >> 1]; + biodiversity = levels[levels.Length >> 1]; } return biodiversity; } @@ -306,14 +306,14 @@

Planet of Discord

public object PartTwo(string input) { int[] levels = Parse(input); - for (var i = 0; i < 200; i++) { + for (var i = 0; i < 200; i++) { levels = Step(levels, RecursiveNeighbours); } return ( from level in levels from pos in Positions() - where pos != (2,2) && HasBug(level, pos.irow, pos.icol) + where pos != (2,2) && HasBug(level, pos.irow, pos.icol) select 1 ).Count(); } @@ -321,44 +321,44 @@

Planet of Discord

int[] Parse(string input) { var biodiversity = 0; var m = 1; - foreach (var ch in input.Replace("\n", "")) { - if (ch == '#') { + foreach (var ch in input.Replace("\n", "")) { + if (ch == '#') { biodiversity += m; } - m <<= 1; + m <<= 1; } return new[] { biodiversity }; } - IEnumerable<(int irow, int icol)> Positions() { - for (var irow = 0; irow < 5; irow++) { - for (var icol = 0; icol < 5; icol++) { + IEnumerable<(int irow, int icol)> Positions() { + for (var irow = 0; irow < 5; irow++) { + for (var icol = 0; icol < 5; icol++) { yield return (irow, icol); } } } bool HasBug(int biodiversity, int irow, int icol) { - return ((biodiversity >> (irow * 5 + icol)) & 1) == 1; + return ((biodiversity >> (irow * 5 + icol)) & 1) == 1; } int SetBug(int biodiversity, int irow, int icol) { - return biodiversity | (1 << (irow * 5 + icol)); + return biodiversity | (1 << (irow * 5 + icol)); } - int[] Step(int[] oldLevelsT, Func> neighbours) { + int[] Step(int[] oldLevelsT, Func<Position, IEnumerable<Position>> neighbours) { var oldLevels = oldLevelsT.ToList(); oldLevels.Insert(0, 0); oldLevels.Add(0); - var newLevels = new List(); - for (var ilevel = 0; ilevel < oldLevels.Count; ilevel++) { + var newLevels = new List<int>(); + for (var ilevel = 0; ilevel < oldLevels.Count; ilevel++) { var newLevel = 0; foreach (var (irow, icol) in Positions()) { var bugCount = 0; foreach (var (ilevelT, irowT, icolT) in neighbours(new Position(ilevel, irow, icol))) { - if (ilevelT >= 0 && ilevelT < oldLevels.Count) { + if (ilevelT >= 0 && ilevelT < oldLevels.Count) { bugCount += HasBug(oldLevels[ilevelT], irowT, icolT) ? 1 : 0; } } @@ -380,16 +380,16 @@

Planet of Discord

} - IEnumerable FlatNeighbours(Position pos) { + IEnumerable<Position> FlatNeighbours(Position pos) { foreach (var (drow, dcol) in new[] { (0, 1), (0, -1), (-1, 0), (1, 0) }) { var (irowT, icolT) = (pos.irow + drow, pos.icol + dcol); - if (icolT >= 0 && icolT <= 4 && irowT >= 0 && irowT <= 4) { + if (icolT >= 0 && icolT <= 4 && irowT >= 0 && irowT <= 4) { yield return new Position(pos.ilevel, irowT, icolT); } } } - IEnumerable RecursiveNeighbours(Position pos) { + IEnumerable<Position> RecursiveNeighbours(Position pos) { var (ilevel, irow, icol) = pos; foreach (var (drow, dcol) in new[] { (0, 1), (0, -1), (-1, 0), (1, 0) }) { var posMin = (irow: irow + drow, icol: icol + dcol); @@ -419,8 +419,8 @@

Planet of Discord

} } - for (var irowT = posMin.irow; irowT <= posMax.irow; irowT++) { - for (var icolT = posMin.icol; icolT <= posMax.icol; icolT++) { + for (var irowT = posMin.irow; irowT <= posMax.irow; irowT++) { + for (var icolT = posMin.icol; icolT <= posMax.icol; icolT++) { yield return new Position(ilevelT, irowT, icolT); } } diff --git a/2019/25/index.html b/2019/25/index.html index 1b881dfa..9587dcd3 100644 --- a/2019/25/index.html +++ b/2019/25/index.html @@ -286,21 +286,21 @@

Cryostasis

namespace AdventOfCode.Y2019.Day25; -[ProblemName("Cryostasis")] +[ProblemName("Cryostasis")] class Solution : Solver { public object PartOne(string input) { - var securityRoom = "== Security Checkpoint =="; + var securityRoom = "== Security Checkpoint =="; var icm = new IntCodeMachine(input); var description = icm.Run().ToAscii(); - VisitRooms(securityRoom, icm, description, args => { + VisitRooms(securityRoom, icm, description, args => { foreach (var item in args.items) { - if (item != "infinite loop") { - var takeCmd = "take " + item; + if (item != "infinite loop") { + var takeCmd = "take " + item; var clone = icm.Clone(); clone.Run(takeCmd); - if (!clone.Halted() && Inventory(clone).Contains(item)) { + if (!clone.Halted() && Inventory(clone).Contains(item)) { icm.Run(takeCmd); } } @@ -308,45 +308,45 @@

Cryostasis

return null; }); - var door = VisitRooms(securityRoom, icm, description, args => - args.room == securityRoom ? args.doors.Single(door => door != ReverseDir(args.doorTaken)) : null); + var door = VisitRooms(securityRoom, icm, description, args => + args.room == securityRoom ? args.doors.Single(door => door != ReverseDir(args.doorTaken)) : null); Random r = new Random(); - void TakeOrDrop(string cmd, List from, List to) { + void TakeOrDrop(string cmd, List<string> from, List<string> to) { var i = r.Next(from.Count); var item = from[i]; from.RemoveAt(i); to.Add(item); - icm.Run(cmd + " " + item); + icm.Run(cmd + " " + item); } var inventory = Inventory(icm).ToList(); - var floor = new List(); + var floor = new List<string>(); while (true) { var output = icm.Run(door).ToAscii(); - if (output.Contains("heavier")) { - TakeOrDrop("take", floor, inventory); - } else if (output.Contains("lighter")) { - TakeOrDrop("drop", inventory, floor); + if (output.Contains("heavier")) { + TakeOrDrop("take", floor, inventory); + } else if (output.Contains("lighter")) { + TakeOrDrop("drop", inventory, floor); } else { - return long.Parse(Regex.Match(output, @"\d+").Value); + return long.Parse(Regex.Match(output, @"\d+").Value); } } } - List directions = new List() { "south", "east", "west", "north" }; - string ReverseDir(string direction) => directions[3 - directions.IndexOf(direction)]; + List<string> directions = new List<string>() { "south", "east", "west", "north" }; + string ReverseDir(string direction) => directions[3 - directions.IndexOf(direction)]; string VisitRooms( string securityRoom, IntCodeMachine icm, string description, - Func<(IEnumerable items, string room, string doorTaken, IEnumerable doors), string> callback + Func<(IEnumerable<string> items, string room, string doorTaken, IEnumerable<string> doors), string> callback ) { - var roomsSeen = new HashSet(); + var roomsSeen = new HashSet<string>(); string DFS(string description, string doorTaken) { - var room = description.Split("\n").Single(x => x.Contains("==")); + var room = description.Split("\n").Single(x => x.Contains("==")); var listing = GetListItems(description).ToHashSet(); var doors = listing.Intersect(directions); var items = listing.Except(doors); @@ -374,11 +374,11 @@

Cryostasis

return DFS(description, null); } - IEnumerable Inventory(IntCodeMachine icm) => GetListItems(icm.Run("inv").ToAscii()); + IEnumerable<string> Inventory(IntCodeMachine icm) => GetListItems(icm.Run("inv").ToAscii()); - IEnumerable GetListItems(string description) => - from line in description.Split("\n") - where line.StartsWith("- ") + IEnumerable<string> GetListItems(string description) => + from line in description.Split("\n") + where line.StartsWith("- ") select line.Substring(2); } diff --git a/2019/3/index.html b/2019/3/index.html index 11d56210..19c691e6 100644 --- a/2019/3/index.html +++ b/2019/3/index.html @@ -285,15 +285,15 @@

Crossed Wires

namespace AdventOfCode.Y2019.Day03; -[ProblemName("Crossed Wires")] +[ProblemName("Crossed Wires")] class Solution : Solver { - public object PartOne(string input) => Solve(input, (x) => Math.Abs(x.irow) + Math.Abs(x.icol)); + public object PartOne(string input) => Solve(input, (x) => Math.Abs(x.irow) + Math.Abs(x.icol)); - public object PartTwo(string input) => Solve(input, (x) => x.distance1 + x.distance2); + public object PartTwo(string input) => Solve(input, (x) => x.distance1 + x.distance2); - int Solve(string input, Func<(int irow, int icol, int distance1, int distance2), int> distance) { - var paths = input.Split("\n"); + int Solve(string input, Func<(int irow, int icol, int distance1, int distance2), int> distance) { + var paths = input.Split("\n"); var trace1 = Trace(paths[0]); var trace2 = Trace(paths[1]); @@ -304,20 +304,20 @@

Crossed Wires

return distances.Min(); } - Dictionary<(int irow, int icol), int> Trace(string path) { - var res = new Dictionary<(int irow, int icol), int>(); + Dictionary<(int irow, int icol), int> Trace(string path) { + var res = new Dictionary<(int irow, int icol), int>(); var (irow, icol, distance) = (0, 0, 0); - foreach (var step in path.Split(",")) { + foreach (var step in path.Split(",")) { var (drow, dcol) = step[0] switch { - 'U' => (-1, 0), - 'D' => (1, 0), - 'R' => (0, -1), - 'L' => (0, 1), - _ => throw new ArgumentException() + 'U' => (-1, 0), + 'D' => (1, 0), + 'R' => (0, -1), + 'L' => (0, 1), + _ => throw new ArgumentException() }; - for (var i = 0; i < int.Parse(step.Substring(1)); i++) { + for (var i = 0; i < int.Parse(step.Substring(1)); i++) { (irow, icol, distance) = (irow + drow, icol + dcol, distance + 1); if (!res.ContainsKey((irow, icol))) { diff --git a/2019/4/index.html b/2019/4/index.html index 40e9eecb..fcc1ec4f 100644 --- a/2019/4/index.html +++ b/2019/4/index.html @@ -285,14 +285,14 @@

Secure Container

namespace AdventOfCode.Y2019.Day04; -[ProblemName("Secure Container")] +[ProblemName("Secure Container")] class Solution : Solver { - public object PartOne(string input) => Solve(input, true); - public object PartTwo(string input) => Solve(input, false); + public object PartOne(string input) => Solve(input, true); + public object PartTwo(string input) => Solve(input, false); private int Solve(string input, bool trippletsAllowed) { - var args = input.Split("-").Select(int.Parse).ToArray(); + var args = input.Split("-").Select(int.Parse).ToArray(); return ( from i in Enumerable.Range(args[0], args[1] - args[0] + 1) where OK(i.ToString(), trippletsAllowed) @@ -302,21 +302,21 @@

Secure Container

private bool OK(string password, bool trippletsAllowed) { - if (string.Join("", password.OrderBy(ch => ch)) != password) { + if (string.Join("", password.OrderBy(ch => ch)) != password) { return false; } return ( from sequence in Split(password) - where sequence.Length >= 2 && (trippletsAllowed || sequence.Length == 2) + where sequence.Length >= 2 && (trippletsAllowed || sequence.Length == 2) select sequence ).Any(); } - private IEnumerable Split(string st) { + private IEnumerable<string> Split(string st) { var ich = 0; - while (ich < st.Length) { - var sequence = Regex.Match(st.Substring(ich), @$"[{st[ich]}]+").Value; + while (ich < st.Length) { + var sequence = Regex.Match(st.Substring(ich), @$"[{st[ich]}]+").Value; yield return sequence; ich += sequence.Length; } diff --git a/2019/5/index.html b/2019/5/index.html index 5878f996..5b0c8342 100644 --- a/2019/5/index.html +++ b/2019/5/index.html @@ -283,12 +283,12 @@

Sunny with a Chance of Asteroids

namespace AdventOfCode.Y2019.Day05; -[ProblemName("Sunny with a Chance of Asteroids")] +[ProblemName("Sunny with a Chance of Asteroids")] class Solution : Solver { - public object PartOne(string input) => new IntCodeMachine(input).Run(1).Last(); + public object PartOne(string input) => new IntCodeMachine(input).Run(1).Last(); - public object PartTwo(string input) => new IntCodeMachine(input).Run(5).Last(); + public object PartTwo(string input) => new IntCodeMachine(input).Run(5).Last(); } diff --git a/2019/6/index.html b/2019/6/index.html index dbfc4db4..204bb8eb 100644 --- a/2019/6/index.html +++ b/2019/6/index.html @@ -281,11 +281,11 @@

Universal Orbit Map

using System.Collections.Generic;
 using System.Linq;
-using ChildToParent = System.Collections.Generic.Dictionary;
+using ChildToParent = System.Collections.Generic.Dictionary<string, string>;
 
 namespace AdventOfCode.Y2019.Day06;
 
-[ProblemName("Universal Orbit Map")]
+[ProblemName("Universal Orbit Map")]
 class Solution : Solver {
 
     public object PartOne(string input) {
@@ -298,8 +298,8 @@ 

Universal Orbit Map

public object PartTwo(string input) { var childToParent = ParseTree(input); - var ancestors1 = new Stack(GetAncestors(childToParent, "YOU")); - var ancestors2 = new Stack(GetAncestors(childToParent, "SAN")); + var ancestors1 = new Stack<string>(GetAncestors(childToParent, "YOU")); + var ancestors2 = new Stack<string>(GetAncestors(childToParent, "SAN")); while (ancestors1.Peek() == ancestors2.Peek()) { ancestors1.Pop(); ancestors2.Pop(); @@ -307,16 +307,16 @@

Universal Orbit Map

return ancestors1.Count + ancestors2.Count; } - ChildToParent ParseTree(string input) => + ChildToParent ParseTree(string input) => input - .Split("\n") - .Select(line => line.Split(")")) + .Split("\n") + .Select(line => line.Split(")")) .ToDictionary( - parent_child => parent_child[1], - parent_child => parent_child[0] + parent_child => parent_child[1], + parent_child => parent_child[0] ); - IEnumerable GetAncestors(ChildToParent childToParent, string node) { + IEnumerable<string> GetAncestors(ChildToParent childToParent, string node) { for ( var parent = childToParent[node]; parent != null; diff --git a/2019/7/index.html b/2019/7/index.html index 757007d8..99ed1d07 100644 --- a/2019/7/index.html +++ b/2019/7/index.html @@ -285,14 +285,14 @@

Amplification Circuit

namespace AdventOfCode.Y2019.Day07; -[ProblemName("Amplification Circuit")] +[ProblemName("Amplification Circuit")] class Solution : Solver { - public object PartOne(string prg) => Solve(prg, false, new[] { 0, 1, 2, 3, 4 }); - public object PartTwo(string prg) => Solve(prg, true, new[] { 5, 6, 7, 8, 9 }); + public object PartOne(string prg) => Solve(prg, false, new[] { 0, 1, 2, 3, 4 }); + public object PartTwo(string prg) => Solve(prg, true, new[] { 5, 6, 7, 8, 9 }); long Solve(string prg, bool loop, int[] prgids) { - var amps = Enumerable.Range(0, 5).Select(x => new IntCodeMachine(prg)).ToArray(); + var amps = Enumerable.Range(0, 5).Select(x => new IntCodeMachine(prg)).ToArray(); var max = 0L; foreach (var perm in Permutations(prgids)) { @@ -303,7 +303,7 @@

Amplification Circuit

long ExecAmps(IntCodeMachine[] amps, int[] prgid, bool loop) { - for (var i = 0; i < amps.Length; i++) { + for (var i = 0; i < amps.Length; i++) { amps[i].Reset(); amps[i].input.Enqueue(prgid[i]); } @@ -311,10 +311,10 @@

Amplification Circuit

var data = new[] { 0L }; while (true) { - for (var i = 0; i < amps.Length; i++) { + for (var i = 0; i < amps.Length; i++) { data = amps[i].Run(data).ToArray(); } - if (amps.All(amp => amp.Halted())) { + if (amps.All(amp => amp.Halted())) { return data.Last(); } if (!loop) { @@ -323,14 +323,14 @@

Amplification Circuit

} } - IEnumerable Permutations(T[] rgt) { + IEnumerable<T[]> Permutations<T>(T[] rgt) { - IEnumerable PermutationsRec(int i) { + IEnumerable<T[]> PermutationsRec(int i) { if (i == rgt.Length) { yield return rgt.ToArray(); } - for (var j = i; j < rgt.Length; j++) { + for (var j = i; j < rgt.Length; j++) { (rgt[i], rgt[j]) = (rgt[j], rgt[i]); foreach (var perm in PermutationsRec(i + 1)) { yield return perm; diff --git a/2019/8/index.html b/2019/8/index.html index a203018c..f5f6095e 100644 --- a/2019/8/index.html +++ b/2019/8/index.html @@ -285,18 +285,18 @@

Space Image Format

namespace AdventOfCode.Y2019.Day08; -[ProblemName("Space Image Format")] +[ProblemName("Space Image Format")] class Solution : Solver { public object PartOne(string input) { var zeroMin = int.MaxValue; var checksum = 0; foreach (var layer in Layers(input)) { - var zero = layer.Count(item => item == 0); - var ones = layer.Count(item => item == 1); - var twos = layer.Count(item => item == 2); + var zero = layer.Count(item => item == 0); + var ones = layer.Count(item => item == 1); + var twos = layer.Count(item => item == 2); - if (zeroMin > zero) { + if (zeroMin > zero) { zeroMin = zero; checksum = ones * twos; } @@ -307,21 +307,21 @@

Space Image Format

public object PartTwo(string input) { var img = new char[6 * 25]; foreach (var layer in Layers(input).Reverse()) { - for (var i = 0; i < img.Length; i++) { + for (var i = 0; i < img.Length; i++) { img[i] = layer[i] switch { - 0 => ' ', - 1 => '#', - _ => img[i] + 0 => ' ', + 1 => '#', + _ => img[i] }; } } - return string.Join("", - img.Chunk(25).Select(line => string.Join("", line)+"\n") + return string.Join("", + img.Chunk(25).Select(line => string.Join("", line)+"\n") ).Ocr(); } - int[][] Layers(string input) => - input.Select(ch => ch - '0').Chunk(6 * 25).ToArray(); + int[][] Layers(string input) => + input.Select(ch => ch - '0').Chunk(6 * 25).ToArray(); }

Please ☆ my repo if you like it!

diff --git a/2019/9/index.html b/2019/9/index.html index ff938604..fe679228 100644 --- a/2019/9/index.html +++ b/2019/9/index.html @@ -283,11 +283,11 @@

Sensor Boost

namespace AdventOfCode.Y2019.Day09; -[ProblemName("Sensor Boost")] +[ProblemName("Sensor Boost")] class Solution : Solver { - public object PartOne(string input) => new IntCodeMachine(input).Run(1).Single(); - public object PartTwo(string input) => new IntCodeMachine(input).Run(2).Single(); + public object PartOne(string input) => new IntCodeMachine(input).Run(1).Single(); + public object PartTwo(string input) => new IntCodeMachine(input).Run(2).Single(); }

Please ☆ my repo if you like it!

diff --git a/2020/1/index.html b/2020/1/index.html index 05bbf455..007cf82b 100644 --- a/2020/1/index.html +++ b/2020/1/index.html @@ -284,7 +284,7 @@

Report Repair

namespace AdventOfCode.Y2020.Day01; -[ProblemName("Report Repair")] +[ProblemName("Report Repair")] class Solution : Solver { public object PartOne(string input) { @@ -308,8 +308,8 @@

Report Repair

).First(); } - HashSet Numbers(string input) { - return input.Split('\n').Select(int.Parse).ToHashSet(); + HashSet<int> Numbers(string input) { + return input.Split('\n').Select(int.Parse).ToHashSet<int>(); } } diff --git a/2020/10/index.html b/2020/10/index.html index 91ff46c2..bdefb715 100644 --- a/2020/10/index.html +++ b/2020/10/index.html @@ -284,16 +284,16 @@

Adapter Array

namespace AdventOfCode.Y2020.Day10; -[ProblemName("Adapter Array")] +[ProblemName("Adapter Array")] class Solution : Solver { public object PartOne(string input) { var jolts = Parse(input); - var window = jolts.Skip(1).Zip(jolts).Select(p => (current: p.First, prev: p.Second)); + var window = jolts.Skip(1).Zip(jolts).Select(p => (current: p.First, prev: p.Second)); return - window.Count(pair => pair.current - pair.prev == 1) * - window.Count(pair => pair.current - pair.prev == 3); + window.Count(pair => pair.current - pair.prev == 1) * + window.Count(pair => pair.current - pair.prev == 3); } public object PartTwo(string input) { @@ -301,18 +301,18 @@

Adapter Array

// dynamic programming with rolling variables a, b, c for the function values at i + 1, i + 2 and i + 3. var (a, b, c) = (1L, 0L, 0L); - for (var i = jolts.Count - 2; i >= 0; i--) { + for (var i = jolts.Count - 2; i >= 0; i--) { var s = - (i + 1 < jolts.Count && jolts[i + 1] - jolts[i] <= 3 ? a : 0) + - (i + 2 < jolts.Count && jolts[i + 2] - jolts[i] <= 3 ? b : 0) + - (i + 3 < jolts.Count && jolts[i + 3] - jolts[i] <= 3 ? c : 0); + (i + 1 < jolts.Count && jolts[i + 1] - jolts[i] <= 3 ? a : 0) + + (i + 2 < jolts.Count && jolts[i + 2] - jolts[i] <= 3 ? b : 0) + + (i + 3 < jolts.Count && jolts[i + 3] - jolts[i] <= 3 ? c : 0); (a, b, c) = (s, a, b); } return a; } - ImmutableList Parse(string input) { - var num = input.Split("\n").Select(int.Parse).OrderBy(x => x); + ImmutableList<int> Parse(string input) { + var num = input.Split("\n").Select(int.Parse).OrderBy(x => x); return ImmutableList .Create(0) .AddRange(num) diff --git a/2020/11/index.html b/2020/11/index.html index a566f2cb..ce55d590 100644 --- a/2020/11/index.html +++ b/2020/11/index.html @@ -284,22 +284,22 @@

Seating System

namespace AdventOfCode.Y2020.Day11; -[ProblemName("Seating System")] +[ProblemName("Seating System")] class Solution : Solver { - public object PartOne(string input) => Solve(input, 4, _ => true); - public object PartTwo(string input) => Solve(input, 5, place => place != '.'); + public object PartOne(string input) => Solve(input, 4, _ => true); + public object PartTwo(string input) => Solve(input, 5, place => place != '.'); - int Solve(string input, int occupiedLimit, Func placeToCheck) { - var (crow, ccol) = (input.Split("\n").Length, input.IndexOf('\n')); + int Solve(string input, int occupiedLimit, Func<char, bool> placeToCheck) { + var (crow, ccol) = (input.Split("\n").Length, input.IndexOf('\n')); char PlaceInDirection(char[] st, int idx, int drow, int dcol) { var (irow, icol) = (idx / ccol, idx % ccol); while (true) { (irow, icol) = (irow + drow, icol + dcol); var place = - irow < 0 || irow >= crow ? 'L' : - icol < 0 || icol >= ccol ? 'L' : + irow < 0 || irow >= crow ? 'L' : + icol < 0 || icol >= ccol ? 'L' : st[irow * ccol + icol]; if (placeToCheck(place)) { return place; @@ -311,7 +311,7 @@

Seating System

var directions = new[] { (0, -1), (0, 1), (-1, 0), (1, 0), (-1, -1), (-1, 1), (1, -1), (1, 1) }; var occupied = 0; foreach (var (drow, dcol) in directions) { - if (PlaceInDirection(st, idx, drow, dcol) == '#') { + if (PlaceInDirection(st, idx, drow, dcol) == '#') { occupied++; } } @@ -319,16 +319,16 @@

Seating System

} var prevState = new char[0]; - var state = input.Replace("\n", "").Replace("L", "#").ToArray(); + var state = input.Replace("\n", "").Replace("L", "#").ToArray(); while (!prevState.SequenceEqual(state)) { prevState = state; - state = state.Select((place, i) => - place == '#' && OccupiedPlacesAround(state, i) >= occupiedLimit ? 'L' : - place == 'L' && OccupiedPlacesAround(state, i) == 0 ? '#' : + state = state.Select((place, i) => + place == '#' && OccupiedPlacesAround(state, i) >= occupiedLimit ? 'L' : + place == 'L' && OccupiedPlacesAround(state, i) == 0 ? '#' : place /*otherwise*/ ).ToArray(); } - return state.Count(place => place == '#'); + return state.Count(place => place == '#'); } } diff --git a/2020/12/index.html b/2020/12/index.html index dccd7469..15d94386 100644 --- a/2020/12/index.html +++ b/2020/12/index.html @@ -287,35 +287,35 @@

Rain Risk

record State(Complex pos, Complex dir); -[ProblemName("Rain Risk")] +[ProblemName("Rain Risk")] class Solution : Solver { - public object PartOne(string input) => MoveShip(input, true); - public object PartTwo(string input) => MoveShip(input, false); + public object PartOne(string input) => MoveShip(input, true); + public object PartTwo(string input) => MoveShip(input, false); - double MoveShip(string input, bool part1) => + double MoveShip(string input, bool part1) => input - .Split("\n") - .Select(line => (line[0], int.Parse(line.Substring(1)))) + .Split("\n") + .Select(line => (line[0], int.Parse(line.Substring(1)))) .Aggregate( new State(pos: Complex.Zero, dir: part1 ? Complex.One : new Complex(10, 1)), - (state, line) => + (state, line) => line switch { - ('N', var arg) when part1 => state with {pos = state.pos + arg * Complex.ImaginaryOne}, - ('N', var arg) => state with {dir = state.dir + arg * Complex.ImaginaryOne}, - ('S', var arg) when part1 => state with {pos = state.pos - arg * Complex.ImaginaryOne}, - ('S', var arg) => state with {dir = state.dir - arg * Complex.ImaginaryOne}, - ('E', var arg) when part1 => state with {pos = state.pos + arg}, - ('E', var arg) => state with {dir = state.dir + arg}, - ('W', var arg) when part1 => state with {pos = state.pos - arg}, - ('W', var arg) => state with {dir = state.dir - arg}, - ('F', var arg) => state with {pos = state.pos + arg * state.dir}, - ('L', 90) or ('R', 270) => state with {dir = state.dir * Complex.ImaginaryOne}, - ('L', 270) or ('R', 90) => state with {dir = -state.dir * Complex.ImaginaryOne}, - ('L', 180) or ('R', 180) => state with {dir = -state.dir}, - _ => throw new Exception() + ('N', var arg) when part1 => state with {pos = state.pos + arg * Complex.ImaginaryOne}, + ('N', var arg) => state with {dir = state.dir + arg * Complex.ImaginaryOne}, + ('S', var arg) when part1 => state with {pos = state.pos - arg * Complex.ImaginaryOne}, + ('S', var arg) => state with {dir = state.dir - arg * Complex.ImaginaryOne}, + ('E', var arg) when part1 => state with {pos = state.pos + arg}, + ('E', var arg) => state with {dir = state.dir + arg}, + ('W', var arg) when part1 => state with {pos = state.pos - arg}, + ('W', var arg) => state with {dir = state.dir - arg}, + ('F', var arg) => state with {pos = state.pos + arg * state.dir}, + ('L', 90) or ('R', 270) => state with {dir = state.dir * Complex.ImaginaryOne}, + ('L', 270) or ('R', 90) => state with {dir = -state.dir * Complex.ImaginaryOne}, + ('L', 180) or ('R', 180) => state with {dir = -state.dir}, + _ => throw new Exception() }, - state => Math.Abs(state.pos.Imaginary) + Math.Abs(state.pos.Real)); + state => Math.Abs(state.pos.Imaginary) + Math.Abs(state.pos.Real)); }

Please ☆ my repo if you like it!

diff --git a/2020/13/index.html b/2020/13/index.html index 927586d6..05e7b62e 100644 --- a/2020/13/index.html +++ b/2020/13/index.html @@ -284,43 +284,43 @@

Shuttle Search

namespace AdventOfCode.Y2020.Day13; -[ProblemName("Shuttle Search")] +[ProblemName("Shuttle Search")] class Solution : Solver { public object PartOne(string input) { var problem = Parse(input); return problem.buses.Aggregate( (wait: long.MaxValue, bus: long.MaxValue), - (min, bus) => { + (min, bus) => { var wait = bus.period - (problem.earliestDepart % bus.period); - return wait < min.wait ? (wait, bus.period) : min; + return wait < min.wait ? (wait, bus.period) : min; }, - min => min.wait * min.bus + min => min.wait * min.bus ); } - public object PartTwo(string input) => + public object PartTwo(string input) => ChineseRemainderTheorem( Parse(input).buses - .Select(bus => (mod: bus.period, a: bus.period - bus.delay)) + .Select(bus => (mod: bus.period, a: bus.period - bus.delay)) .ToArray() ); (int earliestDepart, (long period, int delay)[] buses) Parse(string input) { - var lines = input.Split("\n"); + var lines = input.Split("\n"); var earliestDepart = int.Parse(lines[0]); - var buses = lines[1].Split(",") - .Select((part, idx) => (part, idx)) - .Where(item => item.part != "x") - .Select(item => (period: long.Parse(item.part), delay: item.idx)) + var buses = lines[1].Split(",") + .Select((part, idx) => (part, idx)) + .Where(item => item.part != "x") + .Select(item => (period: long.Parse(item.part), delay: item.idx)) .ToArray(); return (earliestDepart, buses); } // https://rosettacode.org/wiki/Chinese_remainder_theorem#C.23 long ChineseRemainderTheorem((long mod, long a)[] items) { - var prod = items.Aggregate(1L, (acc, item) => acc * item.mod); - var sum = items.Select((item, i) => { + var prod = items.Aggregate(1L, (acc, item) => acc * item.mod); + var sum = items.Select((item, i) => { var p = prod / item.mod; return item.a * ModInv(p, item.mod) * p; }).Sum(); @@ -328,7 +328,7 @@

Shuttle Search

return sum % prod; } - long ModInv(long a, long m) => (long)BigInteger.ModPow(a, m - 2, m); + long ModInv(long a, long m) => (long)BigInteger.ModPow(a, m - 2, m); }

Please ☆ my repo if you like it!

diff --git a/2020/14/index.html b/2020/14/index.html index 37fde67b..fc829b10 100644 --- a/2020/14/index.html +++ b/2020/14/index.html @@ -286,34 +286,34 @@

Docking Data

namespace AdventOfCode.Y2020.Day14; -[ProblemName("Docking Data")] +[ProblemName("Docking Data")] class Solution : Solver { public object PartOne(string input) { - var mem = new Dictionary(); + var mem = new Dictionary<long, long>(); var orMask = 0L; var andMask = 0xffffffffffffffL; - foreach (var line in input.Split("\n")) { - if (line.StartsWith("mask")) { - var mask = line.Split(" = ")[1]; - andMask = Convert.ToInt64(mask.Replace("X", "1"), 2); - orMask = Convert.ToInt64(mask.Replace("X", "0"), 2); + foreach (var line in input.Split("\n")) { + if (line.StartsWith("mask")) { + var mask = line.Split(" = ")[1]; + andMask = Convert.ToInt64(mask.Replace("X", "1"), 2); + orMask = Convert.ToInt64(mask.Replace("X", "0"), 2); } else { - var num = Regex.Matches(line, "\\d+").Select(match => long.Parse(match.Value)).ToArray(); - mem[num[0]] = num[1] & andMask | orMask; + var num = Regex.Matches(line, "\\d+").Select(match => long.Parse(match.Value)).ToArray(); + mem[num[0]] = num[1] & andMask | orMask; } } return mem.Values.Sum(); } public object PartTwo(string input) { - var mem = new Dictionary(); - var mask = ""; - foreach (var line in input.Split("\n")) { - if (line.StartsWith("mask")) { - mask = line.Split(" = ")[1]; + var mem = new Dictionary<long, long>(); + var mask = ""; + foreach (var line in input.Split("\n")) { + if (line.StartsWith("mask")) { + mask = line.Split(" = ")[1]; } else { - var num = Regex.Matches(line, "\\d+").Select(match => long.Parse(match.Value)).ToArray(); + var num = Regex.Matches(line, "\\d+").Select(match => long.Parse(match.Value)).ToArray(); var (baseAddr, value) = (num[0], num[1]); foreach (var addr in Addresses(baseAddr, mask, 35)) { mem[addr] = value; @@ -324,18 +324,18 @@

Docking Data

return mem.Values.Sum(); } - IEnumerable Addresses(long baseAddr, string mask, int i) { + IEnumerable<long> Addresses(long baseAddr, string mask, int i) { if (i == -1) { yield return 0; } else { foreach (var prefix in Addresses(baseAddr, mask, i - 1)) { - if (mask[i] == '0') { - yield return (prefix << 1) + ((baseAddr >> 35 - i) & 1); - } else if (mask[i] == '1') { - yield return (prefix << 1) + 1; + if (mask[i] == '0') { + yield return (prefix << 1) + ((baseAddr >> 35 - i) & 1); + } else if (mask[i] == '1') { + yield return (prefix << 1) + 1; } else { - yield return (prefix << 1); - yield return (prefix << 1) + 1; + yield return (prefix << 1); + yield return (prefix << 1) + 1; } } } diff --git a/2020/15/index.html b/2020/15/index.html index c491e8a7..5f152618 100644 --- a/2020/15/index.html +++ b/2020/15/index.html @@ -283,18 +283,18 @@

Rambunctious Recitation

namespace AdventOfCode.Y2020.Day15; -[ProblemName("Rambunctious Recitation")] +[ProblemName("Rambunctious Recitation")] class Solution : Solver { - public object PartOne(string input) => NumberAt(input, 2020); - public object PartTwo(string input) => NumberAt(input, 30000000); + public object PartOne(string input) => NumberAt(input, 2020); + public object PartTwo(string input) => NumberAt(input, 30000000); public int NumberAt(string input, int count) { - var numbers = input.Split(",").Select(int.Parse).ToArray(); + var numbers = input.Split(",").Select(int.Parse).ToArray(); var (lastSeen, number) = (new int[count], numbers[0]); - for (var round = 0; round < count; round++) { + for (var round = 0; round < count; round++) { (lastSeen[number], number) = (round, - round < numbers.Length ? numbers[round] : + round < numbers.Length ? numbers[round] : lastSeen[number] == 0 ? 0 : /* otherwise */ round - lastSeen[number]); } diff --git a/2020/16/index.html b/2020/16/index.html index 1a1668e9..28899b48 100644 --- a/2020/16/index.html +++ b/2020/16/index.html @@ -286,14 +286,14 @@

Ticket Translation

namespace AdventOfCode.Y2020.Day16; -record Field(string name, Func isValid); +record Field(string name, Func<int, bool> isValid); record Problem(Field[] fields, int[][] tickets); -[ProblemName("Ticket Translation")] +[ProblemName("Ticket Translation")] class Solution : Solver { - Field[] FieldCandidates(IEnumerable fields, params int[] values) => - fields.Where(field => values.All(field.isValid)).ToArray(); + Field[] FieldCandidates(IEnumerable<Field> fields, params int[] values) => + fields.Where(field => values.All(field.isValid)).ToArray(); public object PartOne(string input) { var problem = Parse(input); @@ -312,7 +312,7 @@

Ticket Translation

// keep valid tickets only var tickets = ( from ticket in problem.tickets - where ticket.All(value => FieldCandidates(problem.fields, value).Any()) + where ticket.All(value => FieldCandidates(problem.fields, value).Any()) select ticket ).ToArray(); @@ -331,7 +331,7 @@

Ticket Translation

var field = candidates.Single(); fields.Remove(field); columns.Remove(column); - if (field.name.StartsWith("departure")) { + if (field.name.StartsWith("departure")) { res *= valuesInColumn.First(); } break; @@ -342,32 +342,32 @@

Ticket Translation

} Problem Parse(string input) { - int[] parseNumbers(string line) => ( - from m in Regex.Matches(line, "\\d+") // take the consecutive ranges of digits + int[] parseNumbers(string line) => ( + from m in Regex.Matches(line, "\\d+") // take the consecutive ranges of digits select int.Parse(m.Value) // convert them to numbers ).ToArray(); var blocks = ( - from block in input.Split("\n\n") // blocks are delimited by empty lines - select block.Split("\n") // convert them to lines + from block in input.Split("\n\n") // blocks are delimited by empty lines + select block.Split("\n") // convert them to lines ).ToArray(); var fields = ( - from line in blocks.First() // line <- ["departure location: 49-920 or 932-950", ...] + from line in blocks.First() // line <- ["departure location: 49-920 or 932-950", ...] let bounds = parseNumbers(line) // bounds = [49, 920, 932, 950] select new Field( - line.Split(":")[0], // "departure location" - n => - n >= bounds[0] && n <= bounds[1] || - n >= bounds[2] && n <= bounds[3] + line.Split(":")[0], // "departure location" + n => + n >= bounds[0] && n <= bounds[1] || + n >= bounds[2] && n <= bounds[3] ) ).ToArray(); var tickets = ( from block in blocks.Skip(1) // ticket information is in the second and third blocks - let numbers = block.Skip(1) // skip "your ticket:" / "nearby tickets:" - from line in numbers // line <- ["337,687,...", "223,323,...", ...] + let numbers = block.Skip(1) // skip "your ticket:" / "nearby tickets:" + from line in numbers // line <- ["337,687,...", "223,323,...", ...] select parseNumbers(line) // [337, 687, 607] ).ToArray(); diff --git a/2020/17/index.html b/2020/17/index.html index 05e80b7a..bf92d189 100644 --- a/2020/17/index.html +++ b/2020/17/index.html @@ -285,7 +285,7 @@

Conway Cubes

namespace AdventOfCode.Y2020.Day17; -[ProblemName("Conway Cubes")] +[ProblemName("Conway Cubes")] class Solution : Solver { public object PartOne(string input) { var ds = (from dx in new[] { -1, 0, 1 } @@ -295,8 +295,8 @@

Conway Cubes

select (dx, dy, dz)).ToArray(); return Solve( input, - (x, y) => (x: x, y: y, z: 0), - (p) => ds.Select(d => (p.x + d.dx, p.y + d.dy, p.z + d.dz))); + (x, y) => (x: x, y: y, z: 0), + (p) => ds.Select(d => (p.x + d.dx, p.y + d.dy, p.z + d.dz))); } public object PartTwo(string input) { @@ -309,23 +309,23 @@

Conway Cubes

return Solve( input, - (x, y) => (x: x, y: y, z: 0, w: 0), - (p) => ds.Select(d => (p.x + d.dx, p.y + d.dy, p.z + d.dz, p.w + d.dw))); + (x, y) => (x: x, y: y, z: 0, w: 0), + (p) => ds.Select(d => (p.x + d.dx, p.y + d.dy, p.z + d.dz, p.w + d.dw))); } - private int Solve(string input, Func create, Func> neighbours) { - var lines = input.Split("\n"); + private int Solve<T>(string input, Func<int, int, T> create, Func<T, IEnumerable<T>> neighbours) { + var lines = input.Split("\n"); var (width, height) = (lines[0].Length, lines.Length); - var activePoints = new HashSet( + var activePoints = new HashSet<T>( from x in Enumerable.Range(0, width) from y in Enumerable.Range(0, height) - where lines[y][x] == '#' + where lines[y][x] == '#' select create(x,y) ); - for (var i = 0; i < 6; i++) { - var newActivePoints = new HashSet(); - var inactivePoints = new Dictionary(); + for (var i = 0; i < 6; i++) { + var newActivePoints = new HashSet<T>(); + var inactivePoints = new Dictionary<T, int>(); foreach (var point in activePoints) { var activeNeighbours = 0; diff --git a/2020/18/index.html b/2020/18/index.html index 44d130c0..001d1343 100644 --- a/2020/18/index.html +++ b/2020/18/index.html @@ -285,23 +285,23 @@

Operation Order

namespace AdventOfCode.Y2020.Day18; -[ProblemName("Operation Order")] +[ProblemName("Operation Order")] class Solution : Solver { - public object PartOne(string input) => Solve(input, true); - public object PartTwo(string input) => Solve(input, false); + public object PartOne(string input) => Solve(input, true); + public object PartTwo(string input) => Solve(input, false); long Solve(string input, bool part1) { var sum = 0L; - foreach (var line in input.Split("\n")) { + foreach (var line in input.Split("\n")) { // https://en.wikipedia.org/wiki/Shunting-yard_algorithm - var opStack = new Stack(); - var valStack = new Stack(); + var opStack = new Stack<char>(); + var valStack = new Stack<long>(); void evalUntil(string ops) { while (!ops.Contains(opStack.Peek())) { - if (opStack.Pop() == '+') { + if (opStack.Pop() == '+') { valStack.Push(valStack.Pop() + valStack.Pop()); } else { valStack.Push(valStack.Pop() * valStack.Pop()); @@ -309,25 +309,25 @@

Operation Order

} } - opStack.Push('('); + opStack.Push('('); foreach (var ch in line) { switch (ch) { - case ' ': + case ' ': break; - case '*': - evalUntil("("); - opStack.Push('*'); + case '*': + evalUntil("("); + opStack.Push('*'); break; - case '+': - evalUntil(part1 ? "(" : "(*"); - opStack.Push('+'); + case '+': + evalUntil(part1 ? "(" : "(*"); + opStack.Push('+'); break; - case '(': - opStack.Push('('); + case '(': + opStack.Push('('); break; - case ')': - evalUntil("("); + case ')': + evalUntil("("); opStack.Pop(); break; default: @@ -336,7 +336,7 @@

Operation Order

} } - evalUntil("("); + evalUntil("("); sum += valStack.Single(); } diff --git a/2020/19/index.html b/2020/19/index.html index ad9d502f..2c4b99fd 100644 --- a/2020/19/index.html +++ b/2020/19/index.html @@ -281,50 +281,50 @@

Monster Messages

using System.Collections.Generic;
 using System.Linq;
-using Parser = System.Func>;
+using Parser = System.Func<string, System.Collections.Generic.IEnumerable<string>>;
 
 namespace AdventOfCode.Y2020.Day19;
 
-[ProblemName("Monster Messages")]
+[ProblemName("Monster Messages")]
 class Solution : Solver {
 
-    public object PartOne(string input) => Solve(input, true);
-    public object PartTwo(string input) => Solve(input, false);
+    public object PartOne(string input) => Solve(input, true);
+    public object PartTwo(string input) => Solve(input, false);
 
     int Solve(string input, bool part1) {
         var blocks = (
-            from block in input.Split("\n\n") 
-            select block.Split("\n")
+            from block in input.Split("\n\n") 
+            select block.Split("\n")
         ).ToArray();
 
-        var rules = new Dictionary(
+        var rules = new Dictionary<int, string>(
             from line in blocks[0]
-                let parts = line.Split(": ")
+                let parts = line.Split(": ")
                 let index = int.Parse(parts[0])
                 let rule = parts[1]
             select 
-                new KeyValuePair(index, rule)
+                new KeyValuePair<int, string>(index, rule)
         );
 
         if (!part1) {
-            rules[8] = "42 | 42 8";
-            rules[11] = "42 31 | 42 11 31";
+            rules[8] = "42 | 42 8";
+            rules[11] = "42 31 | 42 11 31";
         }
 
         // a parser will process some prefix of the input and return the possible remainders (nothing in case of error).
-        var parsers = new Dictionary();
+        var parsers = new Dictionary<int, Parser>();
         Parser getParser(int index) {
             if (!parsers.ContainsKey(index)) {
-                parsers[index] = (input) => getParser(index)(input); //avoid stack overflows in case of recursion in the grammar
+                parsers[index] = (input) => getParser(index)(input); //avoid stack overflows in case of recursion in the grammar
 
                 parsers[index] = 
                     alt(
-                        from sequence in rules[index].Split(" | ") 
+                        from sequence in rules[index].Split(" | ") 
                         select 
                             seq(
-                                from item in sequence.Split(" ") 
+                                from item in sequence.Split(" ") 
                                 select
-                                    int.TryParse(item, out var i) ? getParser(i) : literal(item.Trim('"'))
+                                    int.TryParse(item, out var i) ? getParser(i) : literal(item.Trim('"'))
                             )
                     );
             }
@@ -332,14 +332,14 @@ 

Monster Messages

} var parser = getParser(0); - return blocks[1].Count(data => parser(data).Any(st => st == "")); + return blocks[1].Count(data => parser(data).Any(st => st == "")); } // Parser combinators - static Parser literal(string st) => - input => input.StartsWith(st) ? new[] { input.Substring(st.Length) } : new string[0]; + static Parser literal(string st) => + input => input.StartsWith(st) ? new[] { input.Substring(st.Length) } : new string[0]; - static Parser seq(IEnumerable parsers) { + static Parser seq(IEnumerable<Parser> parsers) { if (parsers.Count() == 1) { return parsers.Single(); } @@ -347,19 +347,19 @@

Monster Messages

var parseHead = parsers.First(); var parseTail = seq(parsers.Skip(1)); - return input => + return input => from tail in parseHead(input) from rest in parseTail(tail) select rest; } - static Parser alt(IEnumerable parsers) { + static Parser alt(IEnumerable<Parser> parsers) { if (parsers.Count() == 1) { return parsers.Single(); } - var arr = parsers.ToArray(); // don't recalc the enumerable in the parse phase - return input => + var arr = parsers.ToArray(); // don't recalc the enumerable in the parse phase + return input => from parser in arr from rest in parser(input) select rest; diff --git a/2020/2/index.html b/2020/2/index.html index 5d44fd65..8b6e7ab0 100644 --- a/2020/2/index.html +++ b/2020/2/index.html @@ -286,24 +286,24 @@

Password Philosophy

record PasswordEntry(int a, int b, char ch, string password); -[ProblemName("Password Philosophy")] +[ProblemName("Password Philosophy")] class Solution : Solver { - public object PartOne(string input) => ValidCount(input, (PasswordEntry pe) => { - var count = pe.password.Count(ch => ch == pe.ch); - return pe.a <= count && count <= pe.b; + public object PartOne(string input) => ValidCount(input, (PasswordEntry pe) => { + var count = pe.password.Count(ch => ch == pe.ch); + return pe.a <= count && count <= pe.b; }); - public object PartTwo(string input) => ValidCount(input, (PasswordEntry pe) => { + public object PartTwo(string input) => ValidCount(input, (PasswordEntry pe) => { return (pe.password[pe.a - 1] == pe.ch) ^ (pe.password[pe.b - 1] == pe.ch); }); - int ValidCount(string input, Func isValid) => + int ValidCount(string input, Func<PasswordEntry, bool> isValid) => input - .Split("\n") - .Select(line => { - var parts = line.Split(' '); - var range = parts[0].Split('-').Select(int.Parse).ToArray(); + .Split("\n") + .Select(line => { + var parts = line.Split(' '); + var range = parts[0].Split('-').Select(int.Parse).ToArray(); var ch = parts[1][0]; return new PasswordEntry(range[0], range[1], ch, parts[2]); }) diff --git a/2020/20/index.html b/2020/20/index.html index 0bf815ae..2c92a497 100644 --- a/2020/20/index.html +++ b/2020/20/index.html @@ -286,7 +286,7 @@

Jurassic Jigsaw

namespace AdventOfCode.Y2020.Day20; -[ProblemName("Jurassic Jigsaw")] +[ProblemName("Jurassic Jigsaw")] class Solution : Solver { public object PartOne(string input) { @@ -302,16 +302,16 @@

Jurassic Jigsaw

var image = MergeTiles(AssemblePuzzle(input)); var monster = new string[]{ - " # ", - "# ## ## ###", - " # # # # # # " + " # ", + "# ## ## ###", + " # # # # # # " }; while (true) { var monsterCount = MatchCount(image, monster); - if (monsterCount > 0) { - var hashCountInImage = image.ToString().Count(ch => ch == '#'); - var hashCountInMonster = string.Join("\n", monster).Count(ch => ch == '#'); + if (monsterCount > 0) { + var hashCountInImage = image.ToString().Count(ch => ch == '#'); + var hashCountInMonster = string.Join("\n", monster).Count(ch => ch == '#'); return hashCountInImage - monsterCount * hashCountInMonster; } image.ChangeOrientation(); @@ -320,10 +320,10 @@

Jurassic Jigsaw

private Tile[] ParseTiles(string input) { return ( - from block in input.Split("\n\n") - let lines = block.Split("\n") - let id = Regex.Match(lines[0], "\\d+").Value - let image = lines.Skip(1).Where(x => x != "").ToArray() + from block in input.Split("\n\n") + let lines = block.Split("\n") + let id = Regex.Match(lines[0], "\\d+").Value + let image = lines.Skip(1).Where(x => x != "").ToArray() select new Tile(int.Parse(id), image) ).ToArray(); } @@ -335,27 +335,27 @@

Jurassic Jigsaw

// Due to the way the input is created, the list contains // - one item for tiles on the edge or // - two for inner pieces. - var pairs = new Dictionary>(); + var pairs = new Dictionary<string, List<Tile>>(); foreach (var tile in tiles) { - for (var i = 0; i < 8; i++) { + for (var i = 0; i < 8; i++) { var pattern = tile.Top(); if (!pairs.ContainsKey(pattern)) { - pairs[pattern] = new List(); + pairs[pattern] = new List<Tile>(); } pairs[pattern].Add(tile); tile.ChangeOrientation(); } } - bool isEdge(string pattern) => pairs[pattern].Count == 1; - Tile getNeighbour(Tile tile, string pattern) => pairs[pattern].SingleOrDefault(other => other != tile); + bool isEdge(string pattern) => pairs[pattern].Count == 1; + Tile getNeighbour(Tile tile, string pattern) => pairs[pattern].SingleOrDefault(other => other != tile); Tile putTileInPlace(Tile above, Tile left) { - if (above == null && left == null) { + if (above == null && left == null) { // find top-left corner foreach (var tile in tiles) { - for (var i = 0; i < 8; i++) { - if (isEdge(tile.Top()) && isEdge(tile.Left())) { + for (var i = 0; i < 8; i++) { + if (isEdge(tile.Top()) && isEdge(tile.Left())) { return tile; } tile.ChangeOrientation(); @@ -368,7 +368,7 @@

Jurassic Jigsaw

var topMatch = above == null ? isEdge(tile.Top()) : tile.Top() == above.Bottom(); var leftMatch = left == null ? isEdge(tile.Left()) : tile.Left() == left.Right(); - if (topMatch && leftMatch) { + if (topMatch && leftMatch) { return tile; } tile.ChangeOrientation(); @@ -378,13 +378,13 @@

Jurassic Jigsaw

throw new Exception(); } - // once the corner is fixed we can always find a unique tile that matches the one to the left & above + // once the corner is fixed we can always find a unique tile that matches the one to the left & above // just fill up the tileset one by one var size = (int)Math.Sqrt(tiles.Length); var puzzle = new Tile[size][]; - for (var irow = 0; irow < size; irow++) { + for (var irow = 0; irow < size; irow++) { puzzle[irow] = new Tile[size]; - for (var icol = 0; icol < size; icol++) { + for (var icol = 0; icol < size; icol++) { var above = irow == 0 ? null : puzzle[irow - 1][icol]; var left = icol == 0 ? null : puzzle[irow][icol - 1]; puzzle[irow][icol] = putTileInPlace(above, left); @@ -395,13 +395,13 @@

Jurassic Jigsaw

private Tile MergeTiles(Tile[][] tiles) { // create a big tile leaving out the borders - var image = new List(); + var image = new List<string>(); var tileSize = tiles[0][0].size; var tileCount = tiles.Length; - for (var irow = 0; irow < tileCount; irow++) { - for (var i = 1; i < tileSize - 1; i++) { - var st = ""; - for (var icol = 0; icol < tileCount; icol++) { + for (var irow = 0; irow < tileCount; irow++) { + for (var i = 1; i < tileSize - 1; i++) { + var st = ""; + for (var icol = 0; icol < tileCount; icol++) { st += tiles[irow][icol].Row(i).Substring(1, tileSize - 2); } image.Add(st); @@ -413,12 +413,12 @@

Jurassic Jigsaw

int MatchCount(Tile image, params string[] pattern) { var res = 0; var (ccolP, crowP) = (pattern[0].Length, pattern.Length); - for (var irow = 0; irow < image.size - crowP; irow++) - for (var icol = 0; icol < image.size - ccolP ; icol++) { + for (var irow = 0; irow < image.size - crowP; irow++) + for (var icol = 0; icol < image.size - ccolP ; icol++) { bool match() { - for (var icolP = 0; icolP < ccolP; icolP++) - for (var irowP = 0; irowP < crowP; irowP++) { - if (pattern[irowP][icolP] == '#' && image[irow + irowP, icol + icolP] != '#') { + for (var icolP = 0; icolP < ccolP; icolP++) + for (var irowP = 0; irowP < crowP; irowP++) { + if (pattern[irowP][icolP] == '#' && image[irow + irowP, icol + icolP] != '#') { return false; } } @@ -440,7 +440,7 @@

Jurassic Jigsaw

// This is a bit tricky, but makes operations fast and easy to implement. // // - orentation % 4 specifies the rotation of the tile - // - orientation % 8 >= 4 means the tile is flipped. + // - orientation % 8 >= 4 means the tile is flipped. // // The actual rotation and flipping happens in the indexer, // where the input coordinates are adjusted accordingly. @@ -460,11 +460,11 @@

Jurassic Jigsaw

public char this[int irow, int icol] { get { - for (var i = 0; i < orentation % 4; i++) { + for (var i = 0; i < orentation % 4; i++) { (irow, icol) = (icol, size - 1 - irow); // rotate } - if (orentation % 8 >= 4) { + if (orentation % 8 >= 4) { icol = size - 1 - icol; // flip vertical axis } @@ -472,20 +472,20 @@

Jurassic Jigsaw

} } - public string Row(int irow) => GetSlice(irow, 0, 0, 1); - public string Col(int icol) => GetSlice(0, icol, 1, 0); - public string Top() => Row(0); - public string Bottom() => Row(size - 1); - public string Left() => Col(0); - public string Right() => Col(size - 1); + public string Row(int irow) => GetSlice(irow, 0, 0, 1); + public string Col(int icol) => GetSlice(0, icol, 1, 0); + public string Top() => Row(0); + public string Bottom() => Row(size - 1); + public string Left() => Col(0); + public string Right() => Col(size - 1); public override string ToString() { - return $"Tile {id}:\n" + string.Join("\n", Enumerable.Range(0, size).Select(i => Row(i))); + return $"Tile {id}:\n" + string.Join("\n", Enumerable.Range(0, size).Select(i => Row(i))); } string GetSlice(int irow, int icol, int drow, int dcol) { - var st = ""; - for (var i = 0; i < size; i++) { + var st = ""; + for (var i = 0; i < size; i++) { st += this[irow, icol]; irow += drow; icol += dcol; diff --git a/2020/21/index.html b/2020/21/index.html index eea257ea..ec68af1e 100644 --- a/2020/21/index.html +++ b/2020/21/index.html @@ -285,18 +285,18 @@

Allergen Assessment

namespace AdventOfCode.Y2020.Day21; record Problem( - HashSet allergens, - HashSet ingredients, - (HashSet ingredients, HashSet allergens)[] mapping); + HashSet<string> allergens, + HashSet<string> ingredients, + (HashSet<string> ingredients, HashSet<string> allergens)[] mapping); -[ProblemName("Allergen Assessment")] +[ProblemName("Allergen Assessment")] class Solution : Solver { public object PartOne(string input) { var problem = Parse(input); - var suspiciousIngredients = GetIngredientsByAllergene(problem).SelectMany(kvp => kvp.Value).ToHashSet(); + var suspiciousIngredients = GetIngredientsByAllergene(problem).SelectMany(kvp => kvp.Value).ToHashSet(); return problem.mapping - .Select(entry => entry.ingredients.Count(ingredient => !suspiciousIngredients.Contains(ingredient))) + .Select(entry => entry.ingredients.Count(ingredient => !suspiciousIngredients.Contains(ingredient))) .Sum(); } @@ -305,7 +305,7 @@

Allergen Assessment

var ingredientsByAllergene = GetIngredientsByAllergene(problem); // The problem is set up in a way that we can identify the allergene - ingredient pairs one by one. - while (ingredientsByAllergene.Values.Any(ingredients => ingredients.Count > 1)) { + while (ingredientsByAllergene.Values.Any(ingredients => ingredients.Count > 1)) { foreach (var allergen in problem.allergens) { var candidates = ingredientsByAllergene[allergen]; if (candidates.Count == 1) { @@ -318,33 +318,33 @@

Allergen Assessment

} } - return string.Join(",", problem.allergens.OrderBy(a => a).Select(a => ingredientsByAllergene[a].Single())); + return string.Join(",", problem.allergens.OrderBy(a => a).Select(a => ingredientsByAllergene[a].Single())); } private Problem Parse(string input) { var mapping = ( - from line in input.Split("\n") - let parts = line.Trim(')').Split(" (contains ") - let ingredients = parts[0].Split(" ").ToHashSet() - let allergens = parts[1].Split(", ").ToHashSet() + from line in input.Split("\n") + let parts = line.Trim(')').Split(" (contains ") + let ingredients = parts[0].Split(" ").ToHashSet() + let allergens = parts[1].Split(", ").ToHashSet() select (ingredients, allergens) ).ToArray(); return new Problem( - mapping.SelectMany(entry => entry.allergens).ToHashSet(), - mapping.SelectMany(entry => entry.ingredients).ToHashSet(), + mapping.SelectMany(entry => entry.allergens).ToHashSet(), + mapping.SelectMany(entry => entry.ingredients).ToHashSet(), mapping ); } - private Dictionary> GetIngredientsByAllergene(Problem problem) => + private Dictionary<string, HashSet<string>> GetIngredientsByAllergene(Problem problem) => problem.allergens.ToDictionary( - allergene => allergene, - allergene => problem.mapping - .Where(entry => entry.allergens.Contains(allergene)) + allergene => allergene, + allergene => problem.mapping + .Where(entry => entry.allergens.Contains(allergene)) .Aggregate( - problem.ingredients as IEnumerable, - (res, entry) => res.Intersect(entry.ingredients)) + problem.ingredients as IEnumerable<string>, + (res, entry) => res.Intersect(entry.ingredients)) .ToHashSet()); }
diff --git a/2020/22/index.html b/2020/22/index.html index 7255dff6..d426c9cd 100644 --- a/2020/22/index.html +++ b/2020/22/index.html @@ -285,16 +285,16 @@

Crab Combat

namespace AdventOfCode.Y2020.Day22; -[ProblemName("Crab Combat")] +[ProblemName("Crab Combat")] class Solution : Solver { public object PartOne(string input) { var (deck1, deck2) = Parse(input); - while (deck1.Any() && deck2.Any()) { + while (deck1.Any() && deck2.Any()) { var (card1, card2) = (deck1.Dequeue(), deck2.Dequeue()); - bool player1Wins = card1 > card2; + bool player1Wins = card1 > card2; if (player1Wins) { deck1.Enqueue(card1); @@ -311,11 +311,11 @@

Crab Combat

var (deck1, deck2) = Parse(input); - bool Game(Queue deck1, Queue deck2) { - var seen = new HashSet(); + bool Game(Queue<int> deck1, Queue<int> deck2) { + var seen = new HashSet<string>(); - while (deck1.Any() && deck2.Any()) { - var hash = string.Join(",", deck1) + ";" + string.Join(",", deck2); + while (deck1.Any() && deck2.Any()) { + var hash = string.Join(",", deck1) + ";" + string.Join(",", deck2); if (seen.Contains(hash)) { return true; // player 1 wins; } @@ -324,10 +324,10 @@

Crab Combat

var (card1, card2) = (deck1.Dequeue(), deck2.Dequeue()); bool player1Wins; - if (deck1.Count >= card1 && deck2.Count >= card2) { - player1Wins = Game(new Queue(deck1.Take(card1)), new Queue(deck2.Take(card2))); + if (deck1.Count >= card1 && deck2.Count >= card2) { + player1Wins = Game(new Queue<int>(deck1.Take(card1)), new Queue<int>(deck2.Take(card2))); } else { - player1Wins = card1 > card2; + player1Wins = card1 > card2; } if (player1Wins) { @@ -346,15 +346,15 @@

Crab Combat

return Answer(deck1, deck2); } - int Answer(Queue deck1, Queue deck2) => - deck1.Concat(deck2).Reverse().Select((c, i) => c * (i + 1)).Sum(); + int Answer(Queue<int> deck1, Queue<int> deck2) => + deck1.Concat(deck2).Reverse().Select((c, i) => c * (i + 1)).Sum(); - (Queue deck1, Queue deck2) Parse(string input) { + (Queue<int> deck1, Queue<int> deck2) Parse(string input) { - var decks = input.Split("\n\n"); + var decks = input.Split("\n\n"); return ( - new Queue(decks[0].Split("\n").Skip(1).Select(int.Parse)), - new Queue(decks[1].Split("\n").Skip(1).Select(int.Parse)) + new Queue<int>(decks[0].Split("\n").Skip(1).Select(int.Parse)), + new Queue<int>(decks[1].Split("\n").Skip(1).Select(int.Parse)) ); } } diff --git a/2020/23/index.html b/2020/23/index.html index 5754aa12..1e3c18bc 100644 --- a/2020/23/index.html +++ b/2020/23/index.html @@ -284,36 +284,36 @@

Crab Cups

namespace AdventOfCode.Y2020.Day23; -[ProblemName("Crab Cups")] +[ProblemName("Crab Cups")] class Solution : Solver { - public object PartOne(string input) => - string.Join("", Solve(input, 9, 100).Take(8)); + public object PartOne(string input) => + string.Join("", Solve(input, 9, 100).Take(8)); public object PartTwo(string input) { var labels = Solve(input, 1000000, 10000000).Take(2).ToArray(); return labels[0] * labels[1]; } - private IEnumerable Solve(string input, int maxLabel, int rotate) { - var digits = input.Select(d => int.Parse(d.ToString())).ToArray(); + private IEnumerable<long> Solve(string input, int maxLabel, int rotate) { + var digits = input.Select(d => int.Parse(d.ToString())).ToArray(); - // A compact linked list representation. The cup's label can be used as the index into the array. + // A compact linked list representation. The cup's label can be used as the index into the array. int[] next = Enumerable.Range(1, maxLabel + 1).ToArray(); next[0] = -1; // not used - for (var i = 0; i < digits.Length; i++) { + for (var i = 0; i < digits.Length; i++) { next[digits[i]] = digits[(i + 1) % digits.Length]; } - if (maxLabel > input.Length) { + if (maxLabel > input.Length) { next[maxLabel] = next[digits.Last()]; next[digits.Last()] = input.Length + 1; } var current = digits.First(); - for (var i = 0; i < rotate; i++) { + for (var i = 0; i < rotate; i++) { var removed1 = next[current]; var removed2 = next[removed1]; var removed3 = next[removed2]; diff --git a/2020/24/index.html b/2020/24/index.html index a6f924d5..81df3edd 100644 --- a/2020/24/index.html +++ b/2020/24/index.html @@ -287,30 +287,30 @@

Lobby Layout

record Tile(int x, int y); -[ProblemName("Lobby Layout")] +[ProblemName("Lobby Layout")] class Solution : Solver { - public object PartOne(string input) => ParseBlackTiles(input).Count(); + public object PartOne(string input) => ParseBlackTiles(input).Count(); - public object PartTwo(string input) => + public object PartTwo(string input) => Enumerable.Range(0, 100) - .Aggregate(ParseBlackTiles(input), (blackTiles, _) => Flip(blackTiles)) + .Aggregate(ParseBlackTiles(input), (blackTiles, _) => Flip(blackTiles)) .Count(); - Dictionary HexDirections = new Dictionary { - {"o", ( 0, 0)}, - {"ne", ( 1, 1)}, - {"nw", (-1, 1)}, - {"e", ( 2, 0)}, - {"w", (-2, 0)}, - {"se", ( 1, -1)}, - {"sw", (-1, -1)}, + Dictionary<string, (int x, int y)> HexDirections = new Dictionary<string, (int x, int y)> { + {"o", ( 0, 0)}, + {"ne", ( 1, 1)}, + {"nw", (-1, 1)}, + {"e", ( 2, 0)}, + {"w", (-2, 0)}, + {"se", ( 1, -1)}, + {"sw", (-1, -1)}, }; - IEnumerable Neighbourhood(Tile tile) => + IEnumerable<Tile> Neighbourhood(Tile tile) => from dir in HexDirections.Values select new Tile(tile.x + dir.x, tile.y + dir.y); - HashSet Flip(HashSet blackTiles) { + HashSet<Tile> Flip(HashSet<Tile> blackTiles) { var tiles = ( from black in blackTiles from tile in Neighbourhood(black) @@ -319,16 +319,16 @@

Lobby Layout

return ( from tile in tiles - let blacks = Neighbourhood(tile).Count(n => blackTiles.Contains(n)) - where blacks == 2 || blacks == 3 && blackTiles.Contains(tile) + let blacks = Neighbourhood(tile).Count(n => blackTiles.Contains(n)) + where blacks == 2 || blacks == 3 && blackTiles.Contains(tile) select tile ).ToHashSet(); } - HashSet ParseBlackTiles(string input) { - var tiles = new Dictionary(); + HashSet<Tile> ParseBlackTiles(string input) { + var tiles = new Dictionary<Tile, bool>(); - foreach (var line in input.Split("\n")) { + foreach (var line in input.Split("\n")) { var tile = Walk(line); tiles[tile] = !tiles.GetValueOrDefault(tile); } @@ -338,7 +338,7 @@

Lobby Layout

Tile Walk(string line) { var (x, y) = (0, 0); - while (line != "") { + while (line != "") { foreach (var kvp in HexDirections) { if (line.StartsWith(kvp.Key)) { line = line.Substring(kvp.Key.Length); diff --git a/2020/25/index.html b/2020/25/index.html index f2110cb8..bf4a7cc7 100644 --- a/2020/25/index.html +++ b/2020/25/index.html @@ -283,24 +283,24 @@

Combo Breaker

namespace AdventOfCode.Y2020.Day25; -[ProblemName("Combo Breaker")] +[ProblemName("Combo Breaker")] class Solution : Solver { public object PartOne(string input) { // https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange - var numbers = input.Split("\n").Select(int.Parse).ToArray(); + var numbers = input.Split("\n").Select(int.Parse).ToArray(); var mod = 20201227; var pow = 0; var subj = 7L; var num = subj; - while (num != numbers[0] && num != numbers[1]) { + while (num != numbers[0] && num != numbers[1]) { num = (num * subj) % mod; pow++; } subj = num == numbers[0] ? numbers[1] : numbers[0]; num = subj; - while (pow > 0) { + while (pow > 0) { num = (num * subj) % mod; pow--; } diff --git a/2020/3/index.html b/2020/3/index.html index 3b3f1f3b..280812cd 100644 --- a/2020/3/index.html +++ b/2020/3/index.html @@ -281,22 +281,22 @@

Toboggan Trajectory

namespace AdventOfCode.Y2020.Day03;
 
-[ProblemName("Toboggan Trajectory")]
+[ProblemName("Toboggan Trajectory")]
 class Solution : Solver {
 
-    public object PartOne(string input) => TreeCount(input, (1, 3));
-    public object PartTwo(string input) => TreeCount(input, (1, 1), (1, 3), (1, 5), (1, 7), (2, 1));
+    public object PartOne(string input) => TreeCount(input, (1, 3));
+    public object PartTwo(string input) => TreeCount(input, (1, 1), (1, 3), (1, 5), (1, 7), (2, 1));
 
     long TreeCount(string input, params (int drow, int dcol)[] slopes) {
-        var lines = input.Split("\n");
+        var lines = input.Split("\n");
         var (crow, ccol) = (lines.Length, lines[0].Length);
         var mul = 1L;
 
         foreach (var (drow, dcol) in slopes) {
             var (irow, icol) = (drow, dcol);
             var trees = 0;
-            while (irow < crow) {
-                if (lines[irow][icol % ccol] == '#') {
+            while (irow < crow) {
+                if (lines[irow][icol % ccol] == '#') {
                     trees++;
                 }
                 (irow, icol) = (irow + drow, icol + dcol);
diff --git a/2020/4/index.html b/2020/4/index.html
index 7e643c03..1c9b83c1 100644
--- a/2020/4/index.html
+++ b/2020/4/index.html
@@ -286,36 +286,36 @@ 

Passport Processing

namespace AdventOfCode.Y2020.Day04; -[ProblemName("Passport Processing")] +[ProblemName("Passport Processing")] class Solution : Solver { - public object PartOne(string input) => ValidCount(input, cred => - rxs.All(kvp => cred.ContainsKey(kvp.Key)) + public object PartOne(string input) => ValidCount(input, cred => + rxs.All(kvp => cred.ContainsKey(kvp.Key)) ); - public object PartTwo(string input) => ValidCount(input, cred => - rxs.All(kvp => - cred.TryGetValue(kvp.Key, out var value) && Regex.IsMatch(value, "^(" + kvp.Value + ")$") + public object PartTwo(string input) => ValidCount(input, cred => + rxs.All(kvp => + cred.TryGetValue(kvp.Key, out var value) && Regex.IsMatch(value, "^(" + kvp.Value + ")$") ) ); - Dictionary rxs = new Dictionary(){ - {"byr", "19[2-9][0-9]|200[0-2]"}, - {"iyr", "201[0-9]|2020"}, - {"eyr", "202[0-9]|2030"}, - {"hgt", "1[5-8][0-9]cm|19[0-3]cm|59in|6[0-9]in|7[0-6]in"}, - {"hcl", "#[0-9a-f]{6}"}, - {"ecl", "amb|blu|brn|gry|grn|hzl|oth"}, - {"pid", "[0-9]{9}"}, + Dictionary<string, string> rxs = new Dictionary<string, string>(){ + {"byr", "19[2-9][0-9]|200[0-2]"}, + {"iyr", "201[0-9]|2020"}, + {"eyr", "202[0-9]|2030"}, + {"hgt", "1[5-8][0-9]cm|19[0-3]cm|59in|6[0-9]in|7[0-6]in"}, + {"hcl", "#[0-9a-f]{6}"}, + {"ecl", "amb|blu|brn|gry|grn|hzl|oth"}, + {"pid", "[0-9]{9}"}, }; - int ValidCount(string input, Func, bool> isValid) => + int ValidCount(string input, Func<Dictionary<string, string>, bool> isValid) => input - .Split("\n\n") - .Select(block => block - .Split("\n ".ToCharArray()) - .Select(part => part.Split(":")) - .ToDictionary(parts => parts[0], parts => parts[1])) + .Split("\n\n") + .Select(block => block + .Split("\n ".ToCharArray()) + .Select(part => part.Split(":")) + .ToDictionary(parts => parts[0], parts => parts[1])) .Count(isValid); }
diff --git a/2020/5/index.html b/2020/5/index.html index f04fade9..43f17cc6 100644 --- a/2020/5/index.html +++ b/2020/5/index.html @@ -285,25 +285,25 @@

Binary Boarding

namespace AdventOfCode.Y2020.Day05; -[ProblemName("Binary Boarding")] +[ProblemName("Binary Boarding")] class Solution : Solver { - public object PartOne(string input) => Seats(input).Max(); + public object PartOne(string input) => Seats(input).Max(); public object PartTwo(string input) { var seats = Seats(input); var (min, max) = (seats.Min(), seats.Max()); - return Enumerable.Range(min, max - min + 1).Single(id => !seats.Contains(id)); + return Enumerable.Range(min, max - min + 1).Single(id => !seats.Contains(id)); } - HashSet Seats(string input) => + HashSet<int> Seats(string input) => input - .Replace("B", "1") - .Replace("F", "0") - .Replace("R", "1") - .Replace("L", "0") - .Split("\n") - .Select(row => Convert.ToInt32(row, 2)) + .Replace("B", "1") + .Replace("F", "0") + .Replace("R", "1") + .Replace("L", "0") + .Split("\n") + .Select(row => Convert.ToInt32(row, 2)) .ToHashSet(); } diff --git a/2020/6/index.html b/2020/6/index.html index a79b744f..6ed0ce3c 100644 --- a/2020/6/index.html +++ b/2020/6/index.html @@ -285,16 +285,16 @@

Custom Customs

namespace AdventOfCode.Y2020.Day06; -[ProblemName("Custom Customs")] +[ProblemName("Custom Customs")] class Solution : Solver { - public object PartOne(string input) => Solve(input, (a,b) => a.Union(b)); - public object PartTwo(string input) => Solve(input, (a,b) => a.Intersect(b)); + public object PartOne(string input) => Solve(input, (a,b) => a.Union(b)); + public object PartTwo(string input) => Solve(input, (a,b) => a.Intersect(b)); - int Solve(string input, Func, ImmutableHashSet, ImmutableHashSet> combine) { + int Solve(string input, Func<ImmutableHashSet<char>, ImmutableHashSet<char>, ImmutableHashSet<char>> combine) { return ( - from grp in input.Split("\n\n") - let answers = from line in grp.Split("\n") select line.ToImmutableHashSet() + from grp in input.Split("\n\n") + let answers = from line in grp.Split("\n") select line.ToImmutableHashSet() select answers.Aggregate(combine).Count ).Sum(); } diff --git a/2020/7/index.html b/2020/7/index.html index 03f040a7..ce9fd230 100644 --- a/2020/7/index.html +++ b/2020/7/index.html @@ -285,23 +285,23 @@

Handy Haversacks

namespace AdventOfCode.Y2020.Day07; -[ProblemName("Handy Haversacks")] +[ProblemName("Handy Haversacks")] class Solution : Solver { public object PartOne(string input) { - var parentsOf = new Dictionary>(); - foreach (var line in input.Split("\n")) { + var parentsOf = new Dictionary<string, HashSet<string>>(); + foreach (var line in input.Split("\n")) { var descr = ParseLine(line); foreach (var (_, bag) in descr.children) { if (!parentsOf.ContainsKey(bag)) { - parentsOf[bag] = new HashSet(); + parentsOf[bag] = new HashSet<string>(); } parentsOf[bag].Add(descr.bag); } } - IEnumerable PathsToRoot(string bag) { + IEnumerable<string> PathsToRoot(string bag) { yield return bag; if (parentsOf.ContainsKey(bag)) { @@ -313,29 +313,29 @@

Handy Haversacks

} } - return PathsToRoot("shiny gold bag").ToHashSet().Count - 1; + return PathsToRoot("shiny gold bag").ToHashSet().Count - 1; } public object PartTwo(string input) { - var childrenOf = new Dictionary>(); - foreach (var line in input.Split("\n")) { + var childrenOf = new Dictionary<string, List<(int count, string bag)>>(); + foreach (var line in input.Split("\n")) { var descr = ParseLine(line); childrenOf[descr.bag] = descr.children; } - long CountWithChildren(string bag) => + long CountWithChildren(string bag) => 1 + (from child in childrenOf[bag] select child.count * CountWithChildren(child.bag)).Sum(); - return CountWithChildren("shiny gold bag") - 1; + return CountWithChildren("shiny gold bag") - 1; } - (string bag, List<(int count, string bag)> children) ParseLine(string line){ - var bag = Regex.Match(line, "^[a-z]+ [a-z]+ bag").Value; + (string bag, List<(int count, string bag)> children) ParseLine(string line){ + var bag = Regex.Match(line, "^[a-z]+ [a-z]+ bag").Value; var children = Regex - .Matches(line, "(\\d+) ([a-z]+ [a-z]+ bag)") - .Select(x => (count: int.Parse(x.Groups[1].Value), bag: x.Groups[2].Value)) + .Matches(line, "(\\d+) ([a-z]+ [a-z]+ bag)") + .Select(x => (count: int.Parse(x.Groups[1].Value), bag: x.Groups[2].Value)) .ToList(); return (bag, children); diff --git a/2020/8/index.html b/2020/8/index.html index 17161697..dfae9323 100644 --- a/2020/8/index.html +++ b/2020/8/index.html @@ -287,39 +287,39 @@

Handheld Halting

record Stm(string op, int arg); -[ProblemName("Handheld Halting")] +[ProblemName("Handheld Halting")] class Solution : Solver { - public object PartOne(string input) => Run(Parse(input)).acc; + public object PartOne(string input) => Run(Parse(input)).acc; - public object PartTwo(string input) => + public object PartTwo(string input) => Patches(Parse(input)) .Select(Run) - .First(res => res.terminated).acc; + .First(res => res.terminated).acc; - Stm[] Parse(string input) => - input.Split("\n") - .Select(line => line.Split(" ")) - .Select(parts => new Stm(parts[0], int.Parse(parts[1]))) + Stm[] Parse(string input) => + input.Split("\n") + .Select(line => line.Split(" ")) + .Select(parts => new Stm(parts[0], int.Parse(parts[1]))) .ToArray(); - IEnumerable Patches(Stm[] program) => + IEnumerable<Stm[]> Patches(Stm[] program) => Enumerable.Range(0, program.Length) - .Where(line => program[line].op != "acc") - .Select(lineToPatch => - program.Select((stm, line) => + .Where(line => program[line].op != "acc") + .Select(lineToPatch => + program.Select((stm, line) => line != lineToPatch ? stm : - stm.op == "jmp" ? stm with { op = "nop" } : - stm.op == "nop" ? stm with { op = "jmp" } : + stm.op == "jmp" ? stm with { op = "nop" } : + stm.op == "nop" ? stm with { op = "jmp" } : throw new Exception() ).ToArray() ); (int acc, bool terminated) Run(Stm[] program) { - var (ip, acc, seen) = (0, 0, new HashSet()); + var (ip, acc, seen) = (0, 0, new HashSet<int>()); while (true) { - if (ip >= program.Length) { + if (ip >= program.Length) { return (acc, true); } else if (seen.Contains(ip)) { return (acc, false); @@ -327,9 +327,9 @@

Handheld Halting

seen.Add(ip); var stm = program[ip]; switch (stm.op) { - case "nop": ip++; break; - case "acc": ip++; acc += stm.arg; break; - case "jmp": ip += stm.arg; break; + case "nop": ip++; break; + case "acc": ip++; acc += stm.arg; break; + case "jmp": ip += stm.arg; break; }; } } diff --git a/2020/9/index.html b/2020/9/index.html index 6e2ab90c..c2d9b17b 100644 --- a/2020/9/index.html +++ b/2020/9/index.html @@ -285,32 +285,32 @@

Encoding Error

namespace AdventOfCode.Y2020.Day09; -[ProblemName("Encoding Error")] +[ProblemName("Encoding Error")] class Solution : Solver { - IEnumerable Range(int min, int lim) => Enumerable.Range(min, lim - min); + IEnumerable<int> Range(int min, int lim) => Enumerable.Range(min, lim - min); public object PartOne(string input) { - var numbers = input.Split("\n").Select(long.Parse).ToArray(); + var numbers = input.Split("\n").Select(long.Parse).ToArray(); - bool Mismatch(int i) => ( + bool Mismatch(int i) => ( from j in Range(i - 25, i) from k in Range(j + 1, i) select numbers[j] + numbers[k] - ).All(sum => sum != numbers[i]); + ).All(sum => sum != numbers[i]); return numbers[Range(25, input.Length).First(Mismatch)]; } public object PartTwo(string input) { var d = (long)PartOne(input); - var lines = input.Split("\n").Select(long.Parse).ToList(); + var lines = input.Split("\n").Select(long.Parse).ToList(); foreach (var j in Range(0, lines.Count)) { var s = lines[j]; foreach (var k in Range(j + 1, lines.Count)) { s += lines[k]; - if (s > d) { + if (s > d) { break; } else if (s == d) { var range = lines.GetRange(j, k - j + 1); diff --git a/2021/1/index.html b/2021/1/index.html index a04d34be..a9670f0c 100644 --- a/2021/1/index.html +++ b/2021/1/index.html @@ -284,27 +284,27 @@

Sonar Sweep

namespace AdventOfCode.Y2021.Day01; -[ProblemName("Sonar Sweep")] +[ProblemName("Sonar Sweep")] class Solution : Solver { - public object PartOne(string input) => DepthIncrease(Numbers(input)); + public object PartOne(string input) => DepthIncrease(Numbers(input)); - public object PartTwo(string input) => DepthIncrease(ThreeMeasurements(Numbers(input))); + public object PartTwo(string input) => DepthIncrease(ThreeMeasurements(Numbers(input))); - int DepthIncrease(IEnumerable ns) => ( + int DepthIncrease(IEnumerable<int> ns) => ( from p in Enumerable.Zip(ns, ns.Skip(1)) - where p.First < p.Second + where p.First < p.Second select 1 ).Count(); // the sum of elements in a sliding window of 3 - IEnumerable ThreeMeasurements(IEnumerable ns) => + IEnumerable<int> ThreeMeasurements(IEnumerable<int> ns) => from t in Enumerable.Zip(ns, ns.Skip(1), ns.Skip(2)) // ⭐ .Net 6 comes with three way zip select t.First + t.Second + t.Third; // parse input to array of numbers - IEnumerable Numbers(string input) => - from n in input.Split('\n') + IEnumerable<int> Numbers(string input) => + from n in input.Split('\n') select int.Parse(n); } diff --git a/2021/10/index.html b/2021/10/index.html index 3b46aaaf..20ea4a20 100644 --- a/2021/10/index.html +++ b/2021/10/index.html @@ -287,35 +287,35 @@

Syntax Scoring

namespace AdventOfCode.Y2021.Day10; -[ProblemName("Syntax Scoring")] +[ProblemName("Syntax Scoring")] class Solution : Solver { - public object PartOne(string input) => GetScores(input, getSyntaxErrorScore: true).Sum(); - public object PartTwo(string input) => Median(GetScores(input, getSyntaxErrorScore: false)); + public object PartOne(string input) => GetScores(input, getSyntaxErrorScore: true).Sum(); + public object PartTwo(string input) => Median(GetScores(input, getSyntaxErrorScore: false)); - public long Median(IEnumerable items) => - items.OrderBy(x => x).ElementAt(items.Count() / 2); + public long Median(IEnumerable<long> items) => + items.OrderBy(x => x).ElementAt(items.Count() / 2); - IEnumerable GetScores(string input, bool getSyntaxErrorScore) => - input.Split("\n").Select(line => GetScore(line, getSyntaxErrorScore)).Where(score => score > 0); + IEnumerable<long> GetScores(string input, bool getSyntaxErrorScore) => + input.Split("\n").Select(line => GetScore(line, getSyntaxErrorScore)).Where(score => score > 0); long GetScore(string line, bool getSyntaxErrorScore) { // standard stack based approach - var stack = new Stack(); + var stack = new Stack<char>(); foreach (var ch in line) { switch ((stack.FirstOrDefault(), ch)) { // matching closing parenthesis: - case ('(', ')'): stack.Pop(); break; - case ('[', ']'): stack.Pop(); break; - case ('{', '}'): stack.Pop(); break; - case ('<', '>'): stack.Pop(); break; + case ('(', ')'): stack.Pop(); break; + case ('[', ']'): stack.Pop(); break; + case ('{', '}'): stack.Pop(); break; + case ('<', '>'): stack.Pop(); break; // return early if syntax error found: - case (_, ')'): return getSyntaxErrorScore ? 3 : 0; - case (_, ']'): return getSyntaxErrorScore ? 57 : 0; - case (_, '}'): return getSyntaxErrorScore ? 1197 : 0; - case (_, '>'): return getSyntaxErrorScore ? 25137 : 0; - // otherwise, it's an opening parenthesis: + case (_, ')'): return getSyntaxErrorScore ? 3 : 0; + case (_, ']'): return getSyntaxErrorScore ? 57 : 0; + case (_, '}'): return getSyntaxErrorScore ? 1197 : 0; + case (_, '>'): return getSyntaxErrorScore ? 25137 : 0; + // otherwise, it's an opening parenthesis: case (_, _): stack.Push(ch); break; } } @@ -324,8 +324,8 @@

Syntax Scoring

return 0; } else { return stack - .Select(item => 1 + "([{<".IndexOf(item)) // convert chars to digits - .Aggregate(0L, (acc, item) => acc * 5 + item); // get base 5 number + .Select(item => 1 + "([{<".IndexOf(item)) // convert chars to digits + .Aggregate(0L, (acc, item) => acc * 5 + item); // get base 5 number } } } diff --git a/2021/11/index.html b/2021/11/index.html index 4d55e4ca..e37193bd 100644 --- a/2021/11/index.html +++ b/2021/11/index.html @@ -284,21 +284,21 @@

Dumbo Octopus

namespace AdventOfCode.Y2021.Day11; -[ProblemName("Dumbo Octopus")] +[ProblemName("Dumbo Octopus")] class Solution : Solver { - public object PartOne(string input) => Simulate(input).Take(100).Sum(); - public object PartTwo(string input) => Simulate(input).TakeWhile(flash => flash != 100).Count() + 1; + public object PartOne(string input) => Simulate(input).Take(100).Sum(); + public object PartTwo(string input) => Simulate(input).TakeWhile(flash => flash != 100).Count() + 1; // run the simulation in an endless loop, yield flash counts in each step - IEnumerable Simulate(string input) { + IEnumerable<int> Simulate(string input) { var map = GetMap(input); while (true) { - var queue = new Queue(); - var flashed = new HashSet(); + var queue = new Queue<Pos>(); + var flashed = new HashSet<Pos>(); // increase the energy level of each octopus: foreach (var key in map.Keys) { @@ -312,7 +312,7 @@

Dumbo Octopus

while (queue.Any()) { var pos = queue.Dequeue(); flashed.Add(pos); - foreach (var n in Neighbours(pos).Where(x => map.ContainsKey(x))) { + foreach (var n in Neighbours(pos).Where(x => map.ContainsKey(x))) { map[n]++; if (map[n] == 10) { queue.Enqueue(n); @@ -331,16 +331,16 @@

Dumbo Octopus

// store the points in a dictionary so that we can iterate over them and // to easily deal with points outside the area using ContainsKey - Dictionary GetMap(string input) { - var map = input.Split("\n"); - return new Dictionary( + Dictionary<Pos, int> GetMap(string input) { + var map = input.Split("\n"); + return new Dictionary<Pos, int>( from y in Enumerable.Range(0, map.Length) from x in Enumerable.Range(0, map[0].Length) - select new KeyValuePair(new Pos(x, y), map[y][x] - '0') + select new KeyValuePair<Pos, int>(new Pos(x, y), map[y][x] - '0') ); } - IEnumerable Neighbours(Pos pos) => + IEnumerable<Pos> Neighbours(Pos pos) => from dx in new int[] { -1, 0, 1 } from dy in new int[] { -1, 0, 1 } where dx != 0 || dy != 0 diff --git a/2021/12/index.html b/2021/12/index.html index 89637680..7801b868 100644 --- a/2021/12/index.html +++ b/2021/12/index.html @@ -285,19 +285,19 @@

Passage Pathing

namespace AdventOfCode.Y2021.Day12; -[ProblemName("Passage Pathing")] +[ProblemName("Passage Pathing")] class Solution : Solver { - public object PartOne(string input) => Explore(input, false); - public object PartTwo(string input) => Explore(input, true); + public object PartOne(string input) => Explore(input, false); + public object PartTwo(string input) => Explore(input, true); int Explore(string input, bool part2) { var map = GetMap(input); // Recursive approach this time. - int pathCount(string currentCave, ImmutableHashSet visitedCaves, bool anySmallCaveWasVisitedTwice) { + int pathCount(string currentCave, ImmutableHashSet<string> visitedCaves, bool anySmallCaveWasVisitedTwice) { - if (currentCave == "end") { + if (currentCave == "end") { return 1; } @@ -309,7 +309,7 @@

Passage Pathing

if (!seen || isBigCave) { // we can visit big caves any number of times, small caves only once res += pathCount(cave, visitedCaves.Add(cave), anySmallCaveWasVisitedTwice); - } else if (part2 && !isBigCave && cave != "start" && !anySmallCaveWasVisitedTwice) { + } else if (part2 && !isBigCave && cave != "start" && !anySmallCaveWasVisitedTwice) { // part 2 also lets us to visit a single small cave twice (except for start and end) res += pathCount(cave, visitedCaves, true); } @@ -317,25 +317,25 @@

Passage Pathing

return res; } - return pathCount("start", ImmutableHashSet.Create("start"), false); + return pathCount("start", ImmutableHashSet.Create<string>("start"), false); } - Dictionary GetMap(string input) { - // taking all connections 'there and back': + Dictionary<string, string[]> GetMap(string input) { + // taking all connections 'there and back': var connections = - from line in input.Split("\n") - let parts = line.Split("-") + from line in input.Split("\n") + let parts = line.Split("-") let caveA = parts[0] let caveB = parts[1] from connection in new[] { (From: caveA, To: caveB), (From: caveB, To: caveA) } select connection; - // grouped by "from": + // grouped by "from": return ( from p in connections group p by p.From into g select g - ).ToDictionary(g => g.Key, g => g.Select(connnection => connnection.To).ToArray()); + ).ToDictionary(g => g.Key, g => g.Select(connnection => connnection.To).ToArray()); } } diff --git a/2021/13/index.html b/2021/13/index.html index 61f4853b..194129f7 100644 --- a/2021/13/index.html +++ b/2021/13/index.html @@ -284,25 +284,25 @@

Transparent Origami

namespace AdventOfCode.Y2021.Day13; -[ProblemName("Transparent Origami")] +[ProblemName("Transparent Origami")] class Solution : Solver { - public object PartOne(string input) => GetFolds(input).First().Count(); - public object PartTwo(string input) => ToString(GetFolds(input).Last()).Ocr(); + public object PartOne(string input) => GetFolds(input).First().Count(); + public object PartTwo(string input) => ToString(GetFolds(input).Last()).Ocr(); - IEnumerable> GetFolds(string input) { - var blocks = input.Split("\n\n"); + IEnumerable<HashSet<Point>> GetFolds(string input) { + var blocks = input.Split("\n\n"); // parse points into a hashset var points = ( - from line in blocks[0].Split("\n") - let coords = line.Split(",") + from line in blocks[0].Split("\n") + let coords = line.Split(",") select new Point(int.Parse(coords[0]), int.Parse(coords[1])) ).ToHashSet(); // fold line by line, yielding a new hashset - foreach (var line in blocks[1].Split("\n")) { - var rule = line.Split("="); - if (rule[0].EndsWith("x")) { + foreach (var line in blocks[1].Split("\n")) { + var rule = line.Split("="); + if (rule[0].EndsWith("x")) { points = FoldX(int.Parse(rule[1]), points); } else { points = FoldY(int.Parse(rule[1]), points); @@ -311,24 +311,24 @@

Transparent Origami

} } - string ToString(HashSet d) { - var res = ""; - var height = d.MaxBy(p=>p.y).y; - var width = d.MaxBy(p=>p.x).x; - for (var y = 0; y <= height; y++) { - for (var x = 0; x <= width; x++) { - res += d.Contains(new Point(x, y)) ? '#' : ' '; + string ToString(HashSet<Point> d) { + var res = ""; + var height = d.MaxBy(p=>p.y).y; + var width = d.MaxBy(p=>p.x).x; + for (var y = 0; y <= height; y++) { + for (var x = 0; x <= width; x++) { + res += d.Contains(new Point(x, y)) ? '#' : ' '; } - res += "\n"; + res += "\n"; } return res; } - HashSet FoldX(int x, HashSet d) => - d.Select(p => p.x > x ? p with { x = 2 * x - p.x } : p).ToHashSet(); + HashSet<Point> FoldX(int x, HashSet<Point> d) => + d.Select(p => p.x > x ? p with { x = 2 * x - p.x } : p).ToHashSet(); - HashSet FoldY(int y, HashSet d) => - d.Select(p => p.y > y ? p with { y = 2 * y - p.y } : p).ToHashSet(); + HashSet<Point> FoldY(int y, HashSet<Point> d) => + d.Select(p => p.y > y ? p with { y = 2 * y - p.y } : p).ToHashSet(); } diff --git a/2021/14/index.html b/2021/14/index.html index a5f09d50..7884ea77 100644 --- a/2021/14/index.html +++ b/2021/14/index.html @@ -284,47 +284,47 @@

Extended Polymerization

namespace AdventOfCode.Y2021.Day14; -[ProblemName("Extended Polymerization")] +[ProblemName("Extended Polymerization")] class Solution : Solver { - public object PartOne(string input) => Solve(input, 10); - public object PartTwo(string input) => Solve(input, 40); + public object PartOne(string input) => Solve(input, 10); + public object PartTwo(string input) => Solve(input, 40); long Solve(string input, int steps) { - var blocks = input.Split("\n\n"); + var blocks = input.Split("\n\n"); // We will start with this polymer: var polymer = blocks[0]; - // These are the 'molecule -> new element' rules + // These are the 'molecule -> new element' rules var generatedElement = ( - from line in blocks[1].Split("\n") - let parts = line.Split(" -> ") + from line in blocks[1].Split("\n") + let parts = line.Split(" -> ") select (molecule: parts[0], element: parts[1]) - ).ToDictionary(p => p.molecule, p => p.element); + ).ToDictionary(p => p.molecule, p => p.element); // H H H H H H // H-C-C-C-C-C- ....... -C-H // H H H H H H - // It's enough to maintain the molecule counts, no need to deal with them individually. + // It's enough to maintain the molecule counts, no need to deal with them individually. // Cut the polymer into molecules first: - var moleculeCount = new Dictionary(); + var moleculeCount = new Dictionary<string, long>(); foreach (var i in Enumerable.Range(0, polymer.Length - 1)) { var ab = polymer.Substring(i, 2); moleculeCount[ab] = moleculeCount.GetValueOrDefault(ab) + 1; } // Update the map in a loop: - for (var i = 0; i < steps; i++) { - var updated = new Dictionary(); + for (var i = 0; i < steps; i++) { + var updated = new Dictionary<string, long>(); foreach (var (molecule, count) in moleculeCount) { var (a, n, b) = (molecule[0], generatedElement[molecule], molecule[1]); - updated[$"{a}{n}"] = updated.GetValueOrDefault($"{a}{n}") + count; - updated[$"{n}{b}"] = updated.GetValueOrDefault($"{n}{b}") + count; + updated[$"{a}{n}"] = updated.GetValueOrDefault($"{a}{n}") + count; + updated[$"{n}{b}"] = updated.GetValueOrDefault($"{n}{b}") + count; } moleculeCount = updated; } @@ -334,7 +334,7 @@

Extended Polymerization

// H H H H H H // To count the elements consider just one end of each molecule: - var elementCounts = new Dictionary(); + var elementCounts = new Dictionary<char, long>(); foreach (var (molecule, count) in moleculeCount) { var a = molecule[0]; elementCounts[a] = elementCounts.GetValueOrDefault(a) + count; diff --git a/2021/15/index.html b/2021/15/index.html index d4642eb8..a71e357d 100644 --- a/2021/15/index.html +++ b/2021/15/index.html @@ -285,22 +285,22 @@

Chiton

namespace AdventOfCode.Y2021.Day15; -[ProblemName("Chiton")] +[ProblemName("Chiton")] class Solution : Solver { - public object PartOne(string input) => Solve(GetRiskLevelMap(input)); - public object PartTwo(string input) => Solve(ScaleUp(GetRiskLevelMap(input))); + public object PartOne(string input) => Solve(GetRiskLevelMap(input)); + public object PartTwo(string input) => Solve(ScaleUp(GetRiskLevelMap(input))); - int Solve(Dictionary riskMap) { + int Solve(Dictionary<Point, int> riskMap) { // Disjktra algorithm var topLeft = new Point(0, 0); - var bottomRight = new Point(riskMap.Keys.MaxBy(p => p.x).x, riskMap.Keys.MaxBy(p => p.y).y); + var bottomRight = new Point(riskMap.Keys.MaxBy(p => p.x).x, riskMap.Keys.MaxBy(p => p.y).y); // Visit points in order of cumulated risk // ⭐ .Net 6 finally has a PriorityQueue collection :) - var q = new PriorityQueue(); - var totalRiskMap = new Dictionary(); + var q = new PriorityQueue<Point, int>(); + var totalRiskMap = new Dictionary<Point, int>(); totalRiskMap[topLeft] = 0; q.Enqueue(topLeft, 0); @@ -316,7 +316,7 @@

Chiton

foreach (var n in Neighbours(p)) { if (riskMap.ContainsKey(n)) { var totalRiskThroughP = totalRiskMap[p] + riskMap[n]; - if (totalRiskThroughP < totalRiskMap.GetValueOrDefault(n, int.MaxValue)) { + if (totalRiskThroughP < totalRiskMap.GetValueOrDefault(n, int.MaxValue)) { totalRiskMap[n] = totalRiskThroughP; q.Enqueue(n, totalRiskThroughP); } @@ -324,15 +324,15 @@

Chiton

} } - // return bottom right corner's total risk: + // return bottom right corner's total risk: return totalRiskMap[bottomRight]; } // Create an 5x scaled up map, as described in part 2 - Dictionary ScaleUp(Dictionary map) { - var (ccol, crow) = (map.Keys.MaxBy(p => p.x).x + 1, map.Keys.MaxBy(p => p.y).y + 1); + Dictionary<Point, int> ScaleUp(Dictionary<Point, int> map) { + var (ccol, crow) = (map.Keys.MaxBy(p => p.x).x + 1, map.Keys.MaxBy(p => p.y).y + 1); - var res = new Dictionary( + var res = new Dictionary<Point, int>( from y in Enumerable.Range(0, crow * 5) from x in Enumerable.Range(0, ccol * 5) @@ -346,7 +346,7 @@

Chiton

// risk level wraps around from 9 to 1: let riskLevel = (tileRiskLevel + tileDistance - 1) % 9 + 1 - select new KeyValuePair(new Point(x, y), riskLevel) + select new KeyValuePair<Point, int>(new Point(x, y), riskLevel) ); return res; @@ -354,16 +354,16 @@

Chiton

// store the points in a dictionary so that we can iterate over them and // to easily deal with points outside the area - Dictionary GetRiskLevelMap(string input) { - var map = input.Split("\n"); - return new Dictionary( + Dictionary<Point, int> GetRiskLevelMap(string input) { + var map = input.Split("\n"); + return new Dictionary<Point, int>( from y in Enumerable.Range(0, map.Length) from x in Enumerable.Range(0, map[0].Length) - select new KeyValuePair(new Point(x, y), map[y][x] - '0') + select new KeyValuePair<Point, int>(new Point(x, y), map[y][x] - '0') ); } - IEnumerable Neighbours(Point point) => + IEnumerable<Point> Neighbours(Point point) => new[] { point with {y = point.y + 1}, point with {y = point.y - 1}, diff --git a/2021/16/index.html b/2021/16/index.html index 584ed1f2..12a4b4b3 100644 --- a/2021/16/index.html +++ b/2021/16/index.html @@ -286,17 +286,17 @@

Packet Decoder

namespace AdventOfCode.Y2021.Day16; -[ProblemName("Packet Decoder")] +[ProblemName("Packet Decoder")] class Solution : Solver { - public object PartOne(string input) => + public object PartOne(string input) => GetTotalVersion(GetPacket(GetReader(input))); - public object PartTwo(string input) => + public object PartTwo(string input) => Evaluate(GetPacket(GetReader(input))); // recursively sum the versions of a packet and its content for part 1: - int GetTotalVersion(Packet packet) => + int GetTotalVersion(Packet packet) => packet.version + packet.packets.Select(GetTotalVersion).Sum(); // recursively evaluate the packet and its contents based on the type tag for part 2: @@ -304,27 +304,27 @@

Packet Decoder

var parts = packet.packets.Select(Evaluate).ToArray(); return packet.type switch { - 0 => parts.Sum(), - 1 => parts.Aggregate(1L, (acc, x) => acc * x), - 2 => parts.Min(), - 3 => parts.Max(), - 4 => packet.payload, // <--- literal packet is handled uniformly - 5 => parts[0] > parts[1] ? 1 : 0, - 6 => parts[0] < parts[1] ? 1 : 0, - 7 => parts[0] == parts[1] ? 1 : 0, - _ => throw new Exception() + 0 => parts.Sum(), + 1 => parts.Aggregate(1L, (acc, x) => acc * x), + 2 => parts.Min(), + 3 => parts.Max(), + 4 => packet.payload, // <--- literal packet is handled uniformly + 5 => parts[0] > parts[1] ? 1 : 0, + 6 => parts[0] < parts[1] ? 1 : 0, + 7 => parts[0] == parts[1] ? 1 : 0, + _ => throw new Exception() }; } // convert hex string to bit sequence reader - BitSequenceReader GetReader(string input) => new BitSequenceReader( + BitSequenceReader GetReader(string input) => new BitSequenceReader( new BitArray(( from hexChar in input // get the 4 bits out of a hex char: let value = Convert.ToInt32(hexChar.ToString(), 16) // convert to bitmask from mask in new []{8,4,2,1} - select (mask & value) != 0 + select (mask & value) != 0 ).ToArray() )); @@ -332,7 +332,7 @@

Packet Decoder

Packet GetPacket(BitSequenceReader reader) { var version = reader.ReadInt(3); var type = reader.ReadInt(3); - var packets = new List(); + var packets = new List<Packet>(); var payload = 0L; if (type == 0x4) { @@ -345,14 +345,14 @@

Packet Decoder

} } } else if (reader.ReadInt(1) == 0) { - // operator, the next 'length' long bit sequence encodes the sub packages: + // operator, the next 'length' long bit sequence encodes the sub packages: var length = reader.ReadInt(15); var subPackages = reader.GetBitSequenceReader(length); while (subPackages.Any()) { packets.Add(GetPacket(subPackages)); } } else { - // operator with 'packetCount' sub packages: + // operator with 'packetCount' sub packages: var packetCount = reader.ReadInt(11); packets.AddRange(from _ in Enumerable.Range(0, packetCount) select GetPacket(reader)); } @@ -371,12 +371,12 @@

Packet Decoder

} public bool Any() { - return ptr < bits.Length; + return ptr < bits.Length; } public BitSequenceReader GetBitSequenceReader(int bitCount) { var bitArray = new BitArray(bitCount); - for (var i = 0; i < bitCount; i++) { + for (var i = 0; i < bitCount; i++) { bitArray.Set(i, bits[ptr++]); } return new BitSequenceReader(bitArray); @@ -384,7 +384,7 @@

Packet Decoder

public int ReadInt(int bitCount) { var res = 0; - for (var i = 0; i < bitCount; i++) { + for (var i = 0; i < bitCount; i++) { res = res * 2 + (bits[ptr++] ? 1 : 0); } return res; diff --git a/2021/17/index.html b/2021/17/index.html index d892f9b9..96ceb30c 100644 --- a/2021/17/index.html +++ b/2021/17/index.html @@ -286,16 +286,16 @@

Trick Shot

namespace AdventOfCode.Y2021.Day17; -[ProblemName("Trick Shot")] +[ProblemName("Trick Shot")] class Solution : Solver { - public object PartOne(string input) => Solve(input).Max(); - public object PartTwo(string input) => Solve(input).Count(); + public object PartOne(string input) => Solve(input).Max(); + public object PartTwo(string input) => Solve(input).Count(); // For each vx0, vy0 combination that reaches the target, yield the highest y value of the trajectory: - IEnumerable Solve(string input) { + IEnumerable<int> Solve(string input) { // Parse the (signed) integers - var m = Regex.Matches(input, "-?[0-9]+").Select(m => int.Parse(m.Value)).ToArray(); + var m = Regex.Matches(input, "-?[0-9]+").Select(m => int.Parse(m.Value)).ToArray(); // Get the target rectangle var (xMin, xMax) = (m[0], m[1]); @@ -305,18 +305,18 @@

Trick Shot

var vx0Min = 0; // Because vx is non negative var vx0Max = xMax; // For bigger values we jump too much to the right in the first step var vy0Min = yMin; // For smaller values we jump too deep in the first step - var vy0Max = -yMin; // 🍎 Newton says that when the falling probe reaches y = 0, it's speed is -vy0. + var vy0Max = -yMin; // 🍎 Newton says that when the falling probe reaches y = 0, it's speed is -vy0. // In the next step we go down to -vy0, which should not be deeper than yMin. // Run the simulation in the given bounds, maintaining maxY - for (var vx0 = vx0Min; vx0 <= vx0Max; vx0++) { - for (var vy0 = vy0Min; vy0 <= vy0Max; vy0++) { + for (var vx0 = vx0Min; vx0 <= vx0Max; vx0++) { + for (var vy0 = vy0Min; vy0 <= vy0Max; vy0++) { var (x, y, vx, vy) = (0, 0, vx0, vy0); var maxY = 0; // as long as there is any chance to reach the target rectangle: - while (x <= xMax && y >= yMin) { + while (x <= xMax && y >= yMin) { x += vx; y += vy; @@ -325,7 +325,7 @@

Trick Shot

maxY = Math.Max(y, maxY); // if we are within target, yield maxY: - if (x >= xMin && x <= xMax && y >= yMin && y <= yMax) { + if (x >= xMin && x <= xMax && y >= yMin && y <= yMax) { yield return maxY; break; } diff --git a/2021/18/index.html b/2021/18/index.html index 677bfe91..6472cefb 100644 --- a/2021/18/index.html +++ b/2021/18/index.html @@ -284,32 +284,32 @@

Snailfish

namespace AdventOfCode.Y2021.Day18; -[ProblemName("Snailfish")] +[ProblemName("Snailfish")] class Solution : Solver { // WARNING: What follows is obscure nonsense. // - // .-""-. + // .-""-. // /,..___\ // () {_____} // (/-@-@-\) - // {`-=^=-'} - // { `-' } Max + // {`-=^=-'} + // { `-' } Max // { } - // `---' + // `---' public object PartOne(string input) { - // sum up all the 'numbers' in the input - return input.Split("\n").Select(ParseNumber).Aggregate( + // sum up all the 'numbers' in the input + return input.Split("\n").Select(ParseNumber).Aggregate( new Number(), - (acc, number) => !acc.Any() ? number : Sum(acc, number), + (acc, number) => !acc.Any() ? number : Sum(acc, number), Magnitude ); } public object PartTwo(string input) { - // get the highest magnitude resulted from adding any two 'numbers' in the input: - var numbers = input.Split("\n").Select(ParseNumber).ToArray(); + // get the highest magnitude resulted from adding any two 'numbers' in the input: + var numbers = input.Split("\n").Select(ParseNumber).ToArray(); return ( from i in Enumerable.Range(0, numbers.Length) from j in Enumerable.Range(0, numbers.Length) @@ -330,7 +330,7 @@

Snailfish

// take left and right side of the pair var left = computeRecursive(); var right = computeRecursive(); - itoken++; // don't forget to eat the closing parenthesis + itoken++; // don't forget to eat the closing parenthesis return 3 * left + 2 * right; } } @@ -339,8 +339,8 @@

Snailfish

} - // just wrap A and B in a new 'number' and reduce: - Number Sum(Number numberA, Number numberB) => Reduce(Number.Pair(numberA, numberB)); + // just wrap A and B in a new 'number' and reduce: + Number Sum(Number numberA, Number numberB) => Reduce(Number.Pair(numberA, numberB)); Number Reduce(Number number) { while (Explode(number) || Split(number)) { @@ -353,14 +353,14 @@

Snailfish

// exploding means we need to find the first pair in the number // that is embedded in 4 other pairs and get rid of it: var depth = 0; - for (var i = 0; i < number.Count; i++) { + for (var i = 0; i < number.Count; i++) { if (number[i].kind == TokenKind.Open) { depth++; if (depth == 5) { - // we are deep enough, let's to the reduce part + // we are deep enough, let's to the reduce part // find the digit to the left (if any) and increase: - for (var j = i - 1; j >= 0; j--) { + for (var j = i - 1; j >= 0; j--) { if (number[j].kind == TokenKind.Digit) { number[j] = number[j] with { value = number[j].value + number[i + 1].value }; break; @@ -368,7 +368,7 @@

Snailfish

} // find the digit to the right (if any) and increase: - for (var j = i + 3; j < number.Count; j++) { + for (var j = i + 3; j < number.Count; j++) { if (number[j].kind == TokenKind.Digit) { number[j] = number[j] with { value = number[j].value + number[i + 2].value }; break; @@ -387,15 +387,15 @@

Snailfish

} } - // couldn't reduce: + // couldn't reduce: return false; } bool Split(Number number) { // spliting means we neeed to find a token with a high value and make a pair out of it: - for (var i = 0; i < number.Count; i++) { - if (number[i].value >= 10) { + for (var i = 0; i < number.Count; i++) { + if (number[i].value >= 10) { var v = number[i].value; number.RemoveRange(i, 1); @@ -405,32 +405,32 @@

Snailfish

return true; } } - // couldn't split: + // couldn't split: return false; } - // tokenize the input to a list of '[' ']' and digit tokens + // tokenize the input to a list of '[' ']' and digit tokens Number ParseNumber(string st) { var res = new Number(); - var n = ""; + var n = ""; foreach (var ch in st) { - if (ch >= '0' && ch <= '9') { + if (ch >= '0' && ch <= '9') { n += ch; } else { - if (n != "") { + if (n != "") { res.Add(new Token(TokenKind.Digit, int.Parse(n))); - n = ""; + n = ""; } - if (ch == '[') { + if (ch == '[') { res.Add(new Token(TokenKind.Open)); - } else if (ch == ']') { + } else if (ch == ']') { res.Add(new Token(TokenKind.Close)); } } } - if (n != "") { + if (n != "") { res.Add(new Token(TokenKind.Digit, int.Parse(n))); - n = ""; + n = ""; } return res; } @@ -445,8 +445,8 @@

Snailfish

} record Token(TokenKind kind, int value = 0); -class Number : List { - public static Number Digit(int value) => +class Number : List<Token> { + public static Number Digit(int value) => new Number(){ new Token(TokenKind.Digit, value) }; diff --git a/2021/19/index.html b/2021/19/index.html index c7b76b24..62dba4a9 100644 --- a/2021/19/index.html +++ b/2021/19/index.html @@ -285,12 +285,12 @@

Beacon Scanner

namespace AdventOfCode.Y2021.Day19; -[ProblemName("Beacon Scanner")] +[ProblemName("Beacon Scanner")] class Solution : Solver { - public object PartOne(string input) => + public object PartOne(string input) => LocateScanners(input) - .SelectMany(scanner => scanner.GetBeaconsInWorld()) + .SelectMany(scanner => scanner.GetBeaconsInWorld()) .Distinct() .Count(); @@ -307,10 +307,10 @@

Beacon Scanner

).Max(); } - HashSet LocateScanners(string input) { - var scanners = new HashSet(Parse(input)); - var locatedScanners = new HashSet(); - var q = new Queue(); + HashSet<Scanner> LocateScanners(string input) { + var scanners = new HashSet<Scanner>(Parse(input)); + var locatedScanners = new HashSet<Scanner>(); + var q = new Queue<Scanner>(); // when a scanner is located, it gets into the queue so that we can // explore its neighbours. @@ -342,7 +342,7 @@

Beacon Scanner

foreach (var (beaconInA, beaconInB) in PotentialMatchingBeacons(scannerA, scannerB)) { // now try to find the orientation for B: var rotatedB = scannerB; - for (var rotation = 0; rotation < 24; rotation++, rotatedB = rotatedB.Rotate()) { + for (var rotation = 0; rotation < 24; rotation++, rotatedB = rotatedB.Rotate()) { // Moving the rotated scanner so that beaconA and beaconB overlaps. Are there 12 matches? var beaconInRotatedB = rotatedB.Transform(beaconInB); @@ -352,7 +352,7 @@

Beacon Scanner

beaconInA.z - beaconInRotatedB.z )); - if (locatedB.GetBeaconsInWorld().Intersect(beaconsInA).Count() >= 12) { + if (locatedB.GetBeaconsInWorld().Intersect(beaconsInA).Count() >= 12) { return locatedB; } } @@ -362,7 +362,7 @@

Beacon Scanner

return null; } - IEnumerable<(Coord beaconInA, Coord beaconInB)> PotentialMatchingBeacons(Scanner scannerA, Scanner scannerB) { + IEnumerable<(Coord beaconInA, Coord beaconInB)> PotentialMatchingBeacons(Scanner scannerA, Scanner scannerB) { // If we had a matching beaconInA and beaconInB and moved the center // of the scanners to these then we would find at least 12 beacons // with the same coordinates. @@ -375,7 +375,7 @@

Beacon Scanner

// taking the absolute values of the x y and z coordinates of their beacons // and compare those. - IEnumerable absCoordinates(Scanner scanner) => + IEnumerable<int> absCoordinates(Scanner scanner) => from coord in scanner.GetBeaconsInWorld() from v in new[] { coord.x, coord.y, coord.z } select Math.Abs(v); @@ -384,9 +384,9 @@

Beacon Scanner

// have at least 3 * 12 common values (with multiplicity). // 🐦 We can also considerably speed up the search with the pigeonhole principle - // which says that it's enough to take all but 11 beacons from A and B. + // which says that it's enough to take all but 11 beacons from A and B. // If there is no match amongst those, there cannot be 12 matching pairs: - IEnumerable pick(IEnumerable ts) => ts.Take(ts.Count() - 11); + IEnumerable<T> pick<T>(IEnumerable<T> ts) => ts.Take(ts.Count() - 11); foreach (var beaconInA in pick(scannerA.GetBeaconsInWorld())) { var absA = absCoordinates( @@ -398,27 +398,27 @@

Beacon Scanner

scannerB.Translate(new Coord(-beaconInB.x, -beaconInB.y, -beaconInB.z)) ); - if (absB.Count(d => absA.Contains(d)) >= 3 * 12) { + if (absB.Count(d => absA.Contains(d)) >= 3 * 12) { yield return (beaconInA, beaconInB); } } } } - Scanner[] Parse(string input) => ( - from block in input.Split("\n\n") + Scanner[] Parse(string input) => ( + from block in input.Split("\n\n") let beacons = - from line in block.Split("\n").Skip(1) - let parts = line.Split(",").Select(int.Parse).ToArray() + from line in block.Split("\n").Skip(1) + let parts = line.Split(",").Select(int.Parse).ToArray() select new Coord(parts[0], parts[1], parts[2]) select new Scanner(new Coord(0, 0, 0), 0, beacons.ToList()) ).ToArray(); } record Coord(int x, int y, int z); -record Scanner(Coord center, int rotation, List beaconsInLocal) { - public Scanner Rotate() => new Scanner(center, rotation + 1, beaconsInLocal); - public Scanner Translate(Coord t) => new Scanner( +record Scanner(Coord center, int rotation, List<Coord> beaconsInLocal) { + public Scanner Rotate() => new Scanner(center, rotation + 1, beaconsInLocal); + public Scanner Translate(Coord t) => new Scanner( new Coord(center.x + t.x, center.y + t.y, center.z + t.z), rotation, beaconsInLocal); public Coord Transform(Coord coord) { @@ -447,7 +447,7 @@

Beacon Scanner

return new Coord(center.x + x, center.y + y, center.z + z); } - public IEnumerable GetBeaconsInWorld() { + public IEnumerable<Coord> GetBeaconsInWorld() { return beaconsInLocal.Select(Transform); } } diff --git a/2021/2/index.html b/2021/2/index.html index 288ee5d9..e813908b 100644 --- a/2021/2/index.html +++ b/2021/2/index.html @@ -285,20 +285,20 @@

Dive!

namespace AdventOfCode.Y2021.Day02; -[ProblemName("Dive!")] +[ProblemName("Dive!")] class Solution : Solver { public object PartOne(string input) { return Parse(input) .Aggregate( new State1(0, 0), - (state, step) => step.dir switch { - 'f' => state with { x = state.x + step.amount }, - 'u' => state with { y = state.y - step.amount }, - 'd' => state with { y = state.y + step.amount }, - _ => throw new Exception(), + (state, step) => step.dir switch { + 'f' => state with { x = state.x + step.amount }, + 'u' => state with { y = state.y - step.amount }, + 'd' => state with { y = state.y + step.amount }, + _ => throw new Exception(), }, - res => res.x * res.y + res => res.x * res.y ); } @@ -306,22 +306,22 @@

Dive!

return Parse(input) .Aggregate( new State2(0, 0, 0), - (state, step) => step.dir switch { - 'f' => state with { + (state, step) => step.dir switch { + 'f' => state with { x = state.x + step.amount, y = state.y + step.amount * state.aim }, - 'u' => state with { aim = state.aim - step.amount }, - 'd' => state with { aim = state.aim + step.amount }, - _ => throw new Exception(), + 'u' => state with { aim = state.aim - step.amount }, + 'd' => state with { aim = state.aim + step.amount }, + _ => throw new Exception(), }, - res => res.x * res.y + res => res.x * res.y ); } - IEnumerable Parse(string st) => + IEnumerable<Input> Parse(string st) => from - line in st.Split('\n') + line in st.Split('\n') let parts = line.Split() select new Input(parts[0][0], int.Parse(parts[1])); diff --git a/2021/20/index.html b/2021/20/index.html index 65c59039..e4da843e 100644 --- a/2021/20/index.html +++ b/2021/20/index.html @@ -285,45 +285,45 @@

Trench Map

namespace AdventOfCode.Y2021.Day20; -[ProblemName("Trench Map")] +[ProblemName("Trench Map")] class Solution : Solver { - public object PartOne(string input) => EnhanceN(input, 2).Count(x => x.Value == 1); - public object PartTwo(string input) => EnhanceN(input, 50).Count(x => x.Value == 1); + public object PartOne(string input) => EnhanceN(input, 2).Count(x => x.Value == 1); + public object PartTwo(string input) => EnhanceN(input, 50).Count(x => x.Value == 1); // return the N times enhanced image - Dictionary EnhanceN(string input, int n) { - var blocks = input.Split("\n\n"); + Dictionary<Point, int> EnhanceN(string input, int n) { + var blocks = input.Split("\n\n"); var (algo, image) = (blocks[0], GetImage(blocks[1])); - System.Diagnostics.Debug.Assert(algo[0] == '#'); // the image changes parity in each rounds + System.Diagnostics.Debug.Assert(algo[0] == '#'); // the image changes parity in each rounds - var (minX, minY, maxX, maxY) = (0, 0, image.Keys.MaxBy(p => p.x).x, image.Keys.MaxBy(p => p.y).y); + var (minX, minY, maxX, maxY) = (0, 0, image.Keys.MaxBy(p => p.x).x, image.Keys.MaxBy(p => p.y).y); - for (var i = 0; i < n; i++) { - var tmp = new Dictionary(); + for (var i = 0; i < n; i++) { + var tmp = new Dictionary<Point, int>(); - for (var y = minY - 1; y <= maxY + 1; y++) { - for (var x = minX - 1; x <= maxX + 1; x++) { + for (var y = minY - 1; y <= maxY + 1; y++) { + for (var x = minX - 1; x <= maxX + 1; x++) { var point = new Point(x, y); var index = 0; - // it's supposed that neighbours are enumarated in the right order + // it's supposed that neighbours are enumarated in the right order foreach (var neighbour in Neighbours(point)) { // the trick is in the i % 2 part, // for even values of i, the infinite part of the image is all zero - // for odd ones, it contains 1-s due to the way the 'algo' is set up. + // for odd ones, it contains 1-s due to the way the 'algo' is set up. index = index * 2 + image.GetValueOrDefault(neighbour, i % 2); } - tmp[point] = algo[index] == '#' ? 1 : 0; + tmp[point] = algo[index] == '#' ? 1 : 0; } } - // update bounds & image + // update bounds & image (minX, minY, maxX, maxY) = (minX - 1, minY - 1, maxX + 1, maxY + 1); image = tmp; } @@ -333,16 +333,16 @@

Trench Map

// store the points in a dictionary so that we can iterate over them and // to easily deal with points outside the area - Dictionary GetImage(string input) { - var map = input.Split("\n"); - return new Dictionary( + Dictionary<Point, int> GetImage(string input) { + var map = input.Split("\n"); + return new Dictionary<Point, int>( from y in Enumerable.Range(0, map.Length) from x in Enumerable.Range(0, map[0].Length) - select new KeyValuePair(new Point(x, y), map[y][x] == '#' ? 1 : 0) + select new KeyValuePair<Point, int>(new Point(x, y), map[y][x] == '#' ? 1 : 0) ); } - IEnumerable Neighbours(Point pos) => + IEnumerable<Point> Neighbours(Point pos) => from y in Enumerable.Range(-1, 3) from x in Enumerable.Range(-1, 3) select new Point(pos.x + x, pos.y + y); diff --git a/2021/21/index.html b/2021/21/index.html index b049709a..b213684e 100644 --- a/2021/21/index.html +++ b/2021/21/index.html @@ -285,12 +285,12 @@

Dirac Dice

namespace AdventOfCode.Y2021.Day21; -[ProblemName("Dirac Dice")] +[ProblemName("Dirac Dice")] class Solution : Solver { public object PartOne(string input) { // ⭐ we can convert 3 consecutive throws to a 3-throw with the new .Net 6 Chunk function: - var threeRoll = DeterministicThrows().Chunk(3).Select(x => x.Sum()); + var threeRoll = DeterministicThrows().Chunk(3).Select(x => x.Sum()); // take turns until the active player wins: var round = 0; @@ -298,7 +298,7 @@

Dirac Dice

foreach (var steps in threeRoll) { round++; active = active.Move(steps); - if (active.score >= 1000) { + if (active.score >= 1000) { break; } (active, other) = (other, active); @@ -311,11 +311,11 @@

Dirac Dice

// win counts tells us how many times the active and the other player wins // if they are starting from the given positions and scores. - // this function needs to be cached, because we don't have time till eternity. - var cache = new Dictionary<(Player, Player), (long, long)>(); + // this function needs to be cached, because we don't have time till eternity. + var cache = new Dictionary<(Player, Player), (long, long)>(); (long activeWins, long otherWins) winCounts((Player active, Player other) players) { - if (players.other.score >= 21) { + if (players.other.score >= 21) { return (0, 1); } @@ -339,11 +339,11 @@

Dirac Dice

return Math.Max(wins.activeWins, wins.otherWins); } - IEnumerable DeterministicThrows() => + IEnumerable<int> DeterministicThrows() => from i in Enumerable.Range(1, int.MaxValue) select (i - 1) % 100 + 1; - IEnumerable DiracThrows() => + IEnumerable<int> DiracThrows() => from i in new[] { 1, 2, 3 } from j in new[] { 1, 2, 3 } from k in new[] { 1, 2, 3 } @@ -351,8 +351,8 @@

Dirac Dice

(Player active, Player other) Parse(string input) { var players = ( - from line in input.Split("\n") - let parts = line.Split(": ") + from line in input.Split("\n") + let parts = line.Split(": ") select new Player(0, int.Parse(parts[1])) ).ToArray(); return (players[0], players[1]); diff --git a/2021/22/index.html b/2021/22/index.html index fa93ed85..e3ea87de 100644 --- a/2021/22/index.html +++ b/2021/22/index.html @@ -286,11 +286,11 @@

Reactor Reboot

namespace AdventOfCode.Y2021.Day22; -[ProblemName("Reactor Reboot")] +[ProblemName("Reactor Reboot")] class Solution : Solver { - public object PartOne(string input) => ActiveCubesInRange(input, 50); - public object PartTwo(string input) => ActiveCubesInRange(input, int.MaxValue); + public object PartOne(string input) => ActiveCubesInRange(input, 50); + public object PartTwo(string input) => ActiveCubesInRange(input, int.MaxValue); public long ActiveCubesInRange(string input, int range) { var cmds = Parse(input); @@ -301,7 +301,7 @@

Reactor Reboot

// we can compute the effect of the i-th cmd as well: long activeCubesAfterIcmd(int icmd, Region region) { - if (region.IsEmpty || icmd < 0) { + if (region.IsEmpty || icmd < 0) { return 0; // empty is empty } else { var intersection = region.Intersect(cmds[icmd].region); @@ -323,11 +323,11 @@

Reactor Reboot

} Cmd[] Parse(string input) { - var res = new List(); - foreach (var line in input.Split("\n")) { - var turnOff = line.StartsWith("off"); + var res = new List<Cmd>(); + foreach (var line in input.Split("\n")) { + var turnOff = line.StartsWith("off"); // get all the numbers with a regexp: - var m = Regex.Matches(line, "-?[0-9]+").Select(m => int.Parse(m.Value)).ToArray(); + var m = Regex.Matches(line, "-?[0-9]+").Select(m => int.Parse(m.Value)).ToArray(); res.Add(new Cmd(turnOff, new Region(new Segment(m[0], m[1]), new Segment(m[2], m[3]), new Segment(m[4], m[5])))); } return res.ToArray(); @@ -337,18 +337,18 @@

Reactor Reboot

record Cmd(bool turnOff, Region region); record Segment(int from, int to) { - public bool IsEmpty => from > to; - public long Length => IsEmpty ? 0 : to - from + 1; + public bool IsEmpty => from > to; + public long Length => IsEmpty ? 0 : to - from + 1; - public Segment Intersect(Segment that) => + public Segment Intersect(Segment that) => new Segment(Math.Max(this.from, that.from), Math.Min(this.to, that.to)); } record Region(Segment x, Segment y, Segment z) { - public bool IsEmpty => x.IsEmpty || y.IsEmpty || z.IsEmpty; - public long Volume => x.Length * y.Length * z.Length; + public bool IsEmpty => x.IsEmpty || y.IsEmpty || z.IsEmpty; + public long Volume => x.Length * y.Length * z.Length; - public Region Intersect(Region that) => + public Region Intersect(Region that) => new Region(this.x.Intersect(that.x), this.y.Intersect(that.y), this.z.Intersect(that.z)); } diff --git a/2021/23/index.html b/2021/23/index.html index 0e94c14b..b006864e 100644 --- a/2021/23/index.html +++ b/2021/23/index.html @@ -286,29 +286,29 @@

Amphipod

namespace AdventOfCode.Y2021.Day23; -[ProblemName("Amphipod")] +[ProblemName("Amphipod")] class Solution : Solver { - public object PartOne(string input) => Solve(input); - public object PartTwo(string input) => Solve(Upscale(input)); + public object PartOne(string input) => Solve(input); + public object PartTwo(string input) => Solve(Upscale(input)); string Upscale(string input) { - var lines = input.Split("\n").ToList(); - lines.Insert(3, " #D#C#B#A#"); - lines.Insert(4, " #D#B#A#C#"); - return string.Join("\n", lines); + var lines = input.Split("\n").ToList(); + lines.Insert(3, " #D#C#B#A#"); + lines.Insert(4, " #D#B#A#C#"); + return string.Join("\n", lines); } int Solve(string input) { var maze = Maze.Parse(input); - var q = new PriorityQueue(); - var cost = new Dictionary(); + var q = new PriorityQueue<Maze, int>(); + var cost = new Dictionary<Maze, int>(); q.Enqueue(maze, 0); cost.Add(maze, 0); - while (q.Count > 0) { + while (q.Count > 0) { maze = q.Dequeue(); if (maze.Finished()) { @@ -316,7 +316,7 @@

Amphipod

} foreach (var n in Neighbours(maze)) { - if (cost[maze] + n.cost < cost.GetValueOrDefault(n.maze, int.MaxValue)) { + if (cost[maze] + n.cost < cost.GetValueOrDefault(n.maze, int.MaxValue)) { cost[n.maze] = cost[maze] + n.cost; q.Enqueue(n.maze, cost[n.maze]); } @@ -327,33 +327,33 @@

Amphipod

} int stepCost(char actor) { - return actor == 'A' ? 1 : actor == 'B' ? 10 : actor == 'C' ? 100 : 1000; + return actor == 'A' ? 1 : actor == 'B' ? 10 : actor == 'C' ? 100 : 1000; } int getIcolDst(char ch) { return - ch == 'A' ? 3 : - ch == 'B' ? 5 : - ch == 'C' ? 7 : - ch == 'D' ? 9 : + ch == 'A' ? 3 : + ch == 'B' ? 5 : + ch == 'C' ? 7 : + ch == 'D' ? 9 : throw new Exception(); } (Maze maze, int cost) HallwayToRoom(Maze maze) { - for (var icol = 1; icol < 12; icol++) { + for (var icol = 1; icol < 12; icol++) { var ch = maze.ItemAt(new Point(1, icol)); - if (ch == '.') { + if (ch == '.') { continue; } var icolDst = getIcolDst(ch); - if (maze.CanMoveToDoor(icol, icolDst) && maze.CanEnterRoom(ch)) { + if (maze.CanMoveToDoor(icol, icolDst) && maze.CanEnterRoom(ch)) { var steps = Math.Abs(icolDst - icol); var pt = new Point(1, icolDst); - while (maze.ItemAt(pt.Below) == '.') { + while (maze.ItemAt(pt.Below) == '.') { pt = pt.Below; steps++; } @@ -365,7 +365,7 @@

Amphipod

return (maze, 0); } - IEnumerable<(Maze maze, int cost)> RoomToHallway(Maze maze) { + IEnumerable<(Maze maze, int cost)> RoomToHallway(Maze maze) { var hallwayColumns = new int[] { 1, 2, 4, 6, 8, 10, 11 }; foreach (var roomColumn in new[] { 3, 5, 7, 9 }) { @@ -376,20 +376,20 @@

Amphipod

var stepsV = 0; var ptSrc = new Point(1, roomColumn); - while (maze.ItemAt(ptSrc) == '.') { + while (maze.ItemAt(ptSrc) == '.') { ptSrc = ptSrc.Below; stepsV++; } var ch = maze.ItemAt(ptSrc); - if (ch == '#') { + if (ch == '#') { continue; } foreach (var dj in new[] { -1, 1 }) { var stepsH = 0; var ptDst = new Point(1, roomColumn); - while (maze.ItemAt(ptDst) == '.') { + while (maze.ItemAt(ptDst) == '.') { if (hallwayColumns.Contains(ptDst.icol)) { yield return (maze.Move(ptSrc, ptDst), (stepsV + stepsH) * stepCost(ch)); @@ -406,7 +406,7 @@

Amphipod

} } - IEnumerable<(Maze maze, int cost)> Neighbours(Maze maze) { + IEnumerable<(Maze maze, int cost)> Neighbours(Maze maze) { var hallwayToRoom = HallwayToRoom(maze); return hallwayToRoom.cost != 0 ? new[] { hallwayToRoom } : RoomToHallway(maze); } @@ -414,26 +414,26 @@

Amphipod

} record Point(int irow, int icol) { - public Point Below => new Point(irow + 1, icol); - public Point Above => new Point(irow - 1, icol); - public Point Left => new Point(irow, icol - 1); - public Point Right => new Point(irow, icol + 1); + public Point Below => new Point(irow + 1, icol); + public Point Above => new Point(irow - 1, icol); + public Point Left => new Point(irow, icol - 1); + public Point Right => new Point(irow, icol + 1); } record Maze { - const int columnMaskA = (1 << 11) | (1 << 15) | (1 << 19) | (1 << 23); - const int columnMaskB = (1 << 12) | (1 << 16) | (1 << 20) | (1 << 24); - const int columnMaskC = (1 << 13) | (1 << 17) | (1 << 21) | (1 << 25); - const int columnMaskD = (1 << 14) | (1 << 18) | (1 << 22) | (1 << 26); + const int columnMaskA = (1 << 11) | (1 << 15) | (1 << 19) | (1 << 23); + const int columnMaskB = (1 << 12) | (1 << 16) | (1 << 20) | (1 << 24); + const int columnMaskC = (1 << 13) | (1 << 17) | (1 << 21) | (1 << 25); + const int columnMaskD = (1 << 14) | (1 << 18) | (1 << 22) | (1 << 26); public static Maze Parse(string input) { var maze = new Maze(columnMaskA, columnMaskB, columnMaskC, columnMaskD); - var map = input.Split("\n"); + var map = input.Split("\n"); foreach (var irow in Enumerable.Range(0, map.Length)) { foreach (var icol in Enumerable.Range(0, map[0].Length)) { maze = maze.SetItem( - new Point(irow, icol), irow < map.Length && icol < map[irow].Length ? map[irow][icol] : '#'); + new Point(irow, icol), irow < map.Length && icol < map[irow].Length ? map[irow][icol] : '#'); } } return maze; @@ -448,59 +448,59 @@

Amphipod

this.d = d; } - int BitFromPoint(Point pt) => + int BitFromPoint(Point pt) => (pt.irow, pt.icol) switch { - (1, 1) => 1 << 0, - (1, 2) => 1 << 1, - (1, 3) => 1 << 2, - (1, 4) => 1 << 3, - (1, 5) => 1 << 4, - (1, 6) => 1 << 5, - (1, 7) => 1 << 6, - (1, 8) => 1 << 7, - (1, 9) => 1 << 8, - (1, 10) => 1 << 9, - (1, 11) => 1 << 10, - - (2, 3) => 1 << 11, - (2, 5) => 1 << 12, - (2, 7) => 1 << 13, - (2, 9) => 1 << 14, - - (3, 3) => 1 << 15, - (3, 5) => 1 << 16, - (3, 7) => 1 << 17, - (3, 9) => 1 << 18, - - (4, 3) => 1 << 19, - (4, 5) => 1 << 20, - (4, 7) => 1 << 21, - (4, 9) => 1 << 22, - - (5, 3) => 1 << 23, - (5, 5) => 1 << 24, - (5, 7) => 1 << 25, - (5, 9) => 1 << 26, - - _ => 1 << 31, + (1, 1) => 1 << 0, + (1, 2) => 1 << 1, + (1, 3) => 1 << 2, + (1, 4) => 1 << 3, + (1, 5) => 1 << 4, + (1, 6) => 1 << 5, + (1, 7) => 1 << 6, + (1, 8) => 1 << 7, + (1, 9) => 1 << 8, + (1, 10) => 1 << 9, + (1, 11) => 1 << 10, + + (2, 3) => 1 << 11, + (2, 5) => 1 << 12, + (2, 7) => 1 << 13, + (2, 9) => 1 << 14, + + (3, 3) => 1 << 15, + (3, 5) => 1 << 16, + (3, 7) => 1 << 17, + (3, 9) => 1 << 18, + + (4, 3) => 1 << 19, + (4, 5) => 1 << 20, + (4, 7) => 1 << 21, + (4, 9) => 1 << 22, + + (5, 3) => 1 << 23, + (5, 5) => 1 << 24, + (5, 7) => 1 << 25, + (5, 9) => 1 << 26, + + _ => 1 << 31, }; - public bool CanEnterRoom(char ch) => + public bool CanEnterRoom(char ch) => ch switch { - 'A' => (b & columnMaskA) == 0 && (c & columnMaskA) == 0 && (d & columnMaskA) == 0, - 'B' => (a & columnMaskB) == 0 && (c & columnMaskB) == 0 && (d & columnMaskB) == 0, - 'C' => (a & columnMaskC) == 0 && (b & columnMaskC) == 0 && (d & columnMaskC) == 0, - 'D' => (a & columnMaskD) == 0 && (b & columnMaskD) == 0 && (c & columnMaskD) == 0, - _ => throw new Exception() + 'A' => (b & columnMaskA) == 0 && (c & columnMaskA) == 0 && (d & columnMaskA) == 0, + 'B' => (a & columnMaskB) == 0 && (c & columnMaskB) == 0 && (d & columnMaskB) == 0, + 'C' => (a & columnMaskC) == 0 && (b & columnMaskC) == 0 && (d & columnMaskC) == 0, + 'D' => (a & columnMaskD) == 0 && (b & columnMaskD) == 0 && (c & columnMaskD) == 0, + _ => throw new Exception() }; public bool CanMoveToDoor(int icolFrom, int icolTo) { Point step(Point pt) { - return icolFrom < icolTo ? pt.Right : pt.Left; + return icolFrom < icolTo ? pt.Right : pt.Left; } var pt = step(new Point(1, icolFrom)); while (pt.icol != icolTo) { - if (this.ItemAt(pt) != '.') { + if (this.ItemAt(pt) != '.') { return false; } pt = step(pt); @@ -508,53 +508,53 @@

Amphipod

return true; } - public bool FinishedColumn(int icol) => + public bool FinishedColumn(int icol) => icol switch { - 3 => a == columnMaskA, - 5 => b == columnMaskB, - 7 => c == columnMaskC, - 9 => d == columnMaskD, - _ => throw new Exception() + 3 => a == columnMaskA, + 5 => b == columnMaskB, + 7 => c == columnMaskC, + 9 => d == columnMaskD, + _ => throw new Exception() }; - public bool Finished() => - FinishedColumn(3) && FinishedColumn(5) && FinishedColumn(7) && FinishedColumn(9); + public bool Finished() => + FinishedColumn(3) && FinishedColumn(5) && FinishedColumn(7) && FinishedColumn(9); public char ItemAt(Point pt) { var bit = BitFromPoint(pt); return - bit == 1 << 31 ? '#' : - (a & bit) != 0 ? 'A' : - (b & bit) != 0 ? 'B' : - (c & bit) != 0 ? 'C' : - (d & bit) != 0 ? 'D' : - '.'; + bit == 1 << 31 ? '#' : + (a & bit) != 0 ? 'A' : + (b & bit) != 0 ? 'B' : + (c & bit) != 0 ? 'C' : + (d & bit) != 0 ? 'D' : + '.'; } - public Maze Move(Point from, Point to) => - SetItem(to, ItemAt(from)).SetItem(from, '.'); + public Maze Move(Point from, Point to) => + SetItem(to, ItemAt(from)).SetItem(from, '.'); private Maze SetItem(Point pt, char ch) { - if (ch == '#') { + if (ch == '#') { return this; } var bit = BitFromPoint(pt); - if (bit == 1 << 31) { + if (bit == 1 << 31) { return this; } return ch switch { - '.' => new Maze( - a & ~bit, - b & ~bit, - c & ~bit, - d & ~bit + '.' => new Maze( + a & ~bit, + b & ~bit, + c & ~bit, + d & ~bit ), - 'A' => new Maze(a | bit, b & ~bit, c & ~bit, d & ~bit), - 'B' => new Maze(a & ~bit, b | bit, c & ~bit, d & ~bit), - 'C' => new Maze(a & ~bit, b & ~bit, c | bit, d & ~bit), - 'D' => new Maze(a & ~bit, b & ~bit, c & ~bit, d | bit), - _ => throw new Exception() + 'A' => new Maze(a | bit, b & ~bit, c & ~bit, d & ~bit), + 'B' => new Maze(a & ~bit, b | bit, c & ~bit, d & ~bit), + 'C' => new Maze(a & ~bit, b & ~bit, c | bit, d & ~bit), + 'D' => new Maze(a & ~bit, b & ~bit, c & ~bit, d | bit), + _ => throw new Exception() }; } } diff --git a/2021/24/index.html b/2021/24/index.html index 38add461..5602646c 100644 --- a/2021/24/index.html +++ b/2021/24/index.html @@ -285,11 +285,11 @@

Arithmetic Logic Unit

namespace AdventOfCode.Y2021.Day24; -[ProblemName("Arithmetic Logic Unit")] +[ProblemName("Arithmetic Logic Unit")] class Solution : Solver { - public object PartOne(string input) => GetSerials(input).max; - public object PartTwo(string input) => GetSerials(input).min; + public object PartOne(string input) => GetSerials(input).max; + public object PartTwo(string input) => GetSerials(input).min; (string min, string max) GetSerials(string input) { @@ -298,21 +298,21 @@

Arithmetic Logic Unit

// The input has 14 code blocks, each dealing with one digit. // The blocks define 7 pairs of `a`, `b` digits and a `shift` between them. // The input is valid if for each pair the condition `a + shift = b` holds. - var stmBlocks = input.Split("inp w\n")[1..]; + var stmBlocks = input.Split("inp w\n")[1..]; // Extracts the numeric argument of a statement: - var getArgFromLine = (int iblock, Index iline) => - int.Parse(stmBlocks[iblock].Split('\n')[iline].Split(' ')[^1]); + var getArgFromLine = (int iblock, Index iline) => + int.Parse(stmBlocks[iblock].Split('\n')[iline].Split(' ')[^1]); // A stack will contain the index of an `a` digit when we find its corresponding `b`. - var stack = new Stack(); + var stack = new Stack<int>(); // We will fill up the result when `b` is found. var max = Enumerable.Repeat(int.MinValue, 14).ToArray(); var min = Enumerable.Repeat(int.MaxValue, 14).ToArray(); - for (var j = 0; j < 14; j++) { - if (stmBlocks[j].Contains("div z 1")) { + for (var j = 0; j < 14; j++) { + if (stmBlocks[j].Contains("div z 1")) { // j points to an `a` digit. stack.Push(j); } else { @@ -330,10 +330,10 @@

Arithmetic Logic Unit

var b = a + shift; if (digits.Contains(b)) { - if (a > max[i]) { + if (a > max[i]) { (max[i], max[j]) = (a, b); } - if (a < min[i]) { + if (a < min[i]) { (min[i], min[j]) = (a, b); } } @@ -341,8 +341,8 @@

Arithmetic Logic Unit

} } - // That's all folks - return (string.Join("", min), string.Join("", max)); + // That's all folks + return (string.Join("", min), string.Join("", max)); } } diff --git a/2021/25/index.html b/2021/25/index.html index edc60c4f..f8241cfe 100644 --- a/2021/25/index.html +++ b/2021/25/index.html @@ -283,35 +283,35 @@

Sea Cucumber

namespace AdventOfCode.Y2021.Day25; -[ProblemName("Sea Cucumber")] +[ProblemName("Sea Cucumber")] class Solution : Solver { public object PartOne(string input) { - var map = input.Split('\n'); + var map = input.Split('\n'); var (ccol, crow) = (map[0].Length, map.Length); - int right(int icol) => (icol + 1) % ccol; - int left(int icol) => (icol - 1 + ccol) % ccol; - int up(int irow) => (irow - 1 + crow) % crow; - int down(int irow) => (irow + 1) % crow; + int right(int icol) => (icol + 1) % ccol; + int left(int icol) => (icol - 1 + ccol) % ccol; + int up(int irow) => (irow - 1 + crow) % crow; + int down(int irow) => (irow + 1) % crow; - bool movesRight(int irow, int icol) => - map[irow][icol] == '>' && map[irow][right(icol)] == '.'; - bool movesDown(int irow, int icol) => - map[irow][icol] == 'v' && map[down(irow)][icol] == '.'; + bool movesRight(int irow, int icol) => + map[irow][icol] == '>' && map[irow][right(icol)] == '.'; + bool movesDown(int irow, int icol) => + map[irow][icol] == 'v' && map[down(irow)][icol] == '.'; for(var steps = 1;; steps++) { var anyMoves = false; - var newMap = new List(); - for (var irow = 0; irow < crow; irow++) { - var st = ""; - for (var icol = 0; icol < ccol; icol++) { + var newMap = new List<string>(); + for (var irow = 0; irow < crow; irow++) { + var st = ""; + for (var icol = 0; icol < ccol; icol++) { anyMoves |= movesRight(irow, icol); st += - movesRight(irow, icol) ? '.' : - movesRight(irow, left(icol)) ? '>' : + movesRight(irow, icol) ? '.' : + movesRight(irow, left(icol)) ? '>' : map[irow][icol]; } @@ -321,13 +321,13 @@

Sea Cucumber

map = newMap.ToArray(); newMap.Clear(); - for (var irow = 0; irow < crow; irow++) { - var st = ""; - for (var icol = 0; icol < ccol; icol++) { + for (var irow = 0; irow < crow; irow++) { + var st = ""; + for (var icol = 0; icol < ccol; icol++) { anyMoves |= movesDown(irow, icol); st += - movesDown(irow, icol) ? '.' : - movesDown(up(irow), icol) ? 'v' : + movesDown(irow, icol) ? '.' : + movesDown(up(irow), icol) ? 'v' : map[irow][icol]; } newMap.Add(st); diff --git a/2021/3/index.html b/2021/3/index.html index 14b33ead..48615f82 100644 --- a/2021/3/index.html +++ b/2021/3/index.html @@ -284,46 +284,46 @@

Binary Diagnostic

namespace AdventOfCode.Y2021.Day03; -[ProblemName("Binary Diagnostic")] +[ProblemName("Binary Diagnostic")] class Solution : Solver { public object PartOne(string input) { - var diagnosticReport = input.Split("\n"); + var diagnosticReport = input.Split("\n"); return GammaRate(diagnosticReport) * EpsilonRate(diagnosticReport); } public object PartTwo(string input) { - var diagnosticReport = input.Split("\n"); + var diagnosticReport = input.Split("\n"); return OxygenGeneratorRating(diagnosticReport) * Co2ScruberRating(diagnosticReport); } - int GammaRate(string[] diagnosticReport) => Extract1(diagnosticReport, MostCommonBitAt); - int EpsilonRate(string[] diagnosticReport) => Extract1(diagnosticReport, LeastCommonBitAt); - int OxygenGeneratorRating(string[] diagnosticReport) => Extract2(diagnosticReport, MostCommonBitAt); - int Co2ScruberRating(string[] diagnosticReport) => Extract2(diagnosticReport, LeastCommonBitAt); + int GammaRate(string[] diagnosticReport) => Extract1(diagnosticReport, MostCommonBitAt); + int EpsilonRate(string[] diagnosticReport) => Extract1(diagnosticReport, LeastCommonBitAt); + int OxygenGeneratorRating(string[] diagnosticReport) => Extract2(diagnosticReport, MostCommonBitAt); + int Co2ScruberRating(string[] diagnosticReport) => Extract2(diagnosticReport, LeastCommonBitAt); - char MostCommonBitAt(string[] lines, int ibit) => - 2 * lines.Count(line => line[ibit] == '1') >= lines.Length ? '1' : '0'; + char MostCommonBitAt(string[] lines, int ibit) => + 2 * lines.Count(line => line[ibit] == '1') >= lines.Length ? '1' : '0'; - char LeastCommonBitAt(string[] lines, int ibit) => - MostCommonBitAt(lines, ibit) == '1' ? '0' : '1'; + char LeastCommonBitAt(string[] lines, int ibit) => + MostCommonBitAt(lines, ibit) == '1' ? '0' : '1'; - int Extract1(string[] lines, Func selectBitAt) { + int Extract1(string[] lines, Func<string[], int, char> selectBitAt) { var cbit = lines[0].Length; - var bits = ""; - for (var ibit = 0; ibit < cbit; ibit++) { + var bits = ""; + for (var ibit = 0; ibit < cbit; ibit++) { bits += selectBitAt(lines, ibit); } return Convert.ToInt32(bits, 2); } - int Extract2(string[] lines, Func selectBitAt) { + int Extract2(string[] lines, Func<string[], int, char> selectBitAt) { var cbit = lines[0].Length; - for (var ibit = 0; lines.Length > 1 && ibit < cbit; ibit++) { + for (var ibit = 0; lines.Length > 1 && ibit < cbit; ibit++) { var bit = selectBitAt(lines, ibit); - lines = lines.Where(line => line[ibit] == bit).ToArray(); + lines = lines.Where(line => line[ibit] == bit).ToArray(); } return Convert.ToInt32(lines[0], 2); diff --git a/2021/4/index.html b/2021/4/index.html index 6ba7cfaa..f5d2592b 100644 --- a/2021/4/index.html +++ b/2021/4/index.html @@ -285,25 +285,25 @@

Giant Squid

namespace AdventOfCode.Y2021.Day04; -[ProblemName("Giant Squid")] +[ProblemName("Giant Squid")] class Solution : Solver { - public object PartOne(string input) => BoardsInOrderOfCompletion(input).First().score; - public object PartTwo(string input) => BoardsInOrderOfCompletion(input).Last().score; + public object PartOne(string input) => BoardsInOrderOfCompletion(input).First().score; + public object PartTwo(string input) => BoardsInOrderOfCompletion(input).Last().score; - IEnumerable BoardsInOrderOfCompletion(string input) { + IEnumerable<BingoBoard> BoardsInOrderOfCompletion(string input) { - var blocks = input.Split("\n\n"); + var blocks = input.Split("\n\n"); // first block contains the numbers to be drawn, rest describe bingo boards: - var numbers = blocks[0].Split(","); + var numbers = blocks[0].Split(","); var boards = (from block in blocks.Skip(1) select new BingoBoard(block)).ToHashSet(); - // let's play the game + // let's play the game foreach (var number in numbers) { foreach (var board in boards.ToArray()) { board.AddNumber(number); - if (board.score > 0) { + if (board.score > 0) { yield return board; boards.Remove(board); } @@ -314,41 +314,41 @@

Giant Squid

record Cell(string number, bool marked = false); -// Let's be ho-ho-hoOOP this time. +// Let's be ho-ho-hoOOP this time. class BingoBoard { public int score { get; private set; } - private List cells; + private List<Cell> cells; - IEnumerable CellsInRow(int irow) => + IEnumerable<Cell> CellsInRow(int irow) => from icol in Enumerable.Range(0, 5) select cells[irow * 5 + icol]; - IEnumerable CellsInCol(int icol) => + IEnumerable<Cell> CellsInCol(int icol) => from irow in Enumerable.Range(0, 5) select cells[irow * 5 + icol]; public BingoBoard(string st) { - // split the input into words & read them numbers into cells + // split the input into words & read them numbers into cells cells = ( - from word in st.Split(" \n".ToArray(), StringSplitOptions.RemoveEmptyEntries) + from word in st.Split(" \n".ToArray(), StringSplitOptions.RemoveEmptyEntries) select new Cell(word) ).ToList(); } public void AddNumber(string number) { - var icell = cells.FindIndex(cell => cell.number == number); + var icell = cells.FindIndex(cell => cell.number == number); - if (icell >= 0) { + if (icell >= 0) { // mark the cell cells[icell] = cells[icell] with { marked = true }; // if the board is completed, compute score - for (var i = 0; i < 5; i++) { + for (var i = 0; i < 5; i++) { if ( - CellsInRow(i).All(cell => cell.marked) || - CellsInCol(i).All(cell => cell.marked) + CellsInRow(i).All(cell => cell.marked) || + CellsInCol(i).All(cell => cell.marked) ) { var unmarkedNumbers = diff --git a/2021/5/index.html b/2021/5/index.html index 98155cdf..4c6e6907 100644 --- a/2021/5/index.html +++ b/2021/5/index.html @@ -285,21 +285,21 @@

Hydrothermal Venture

namespace AdventOfCode.Y2021.Day05; -[ProblemName("Hydrothermal Venture")] +[ProblemName("Hydrothermal Venture")] class Solution : Solver { - public object PartOne(string input) => GetIntersections(ParseLines(input, skipDiagonals: true)).Count(); - public object PartTwo(string input) => GetIntersections(ParseLines(input, skipDiagonals: false)).Count(); + public object PartOne(string input) => GetIntersections(ParseLines(input, skipDiagonals: true)).Count(); + public object PartTwo(string input) => GetIntersections(ParseLines(input, skipDiagonals: false)).Count(); - IEnumerable GetIntersections(IEnumerable> lines) => + IEnumerable<Vec2> GetIntersections(IEnumerable<IEnumerable<Vec2>> lines) => // group all the points and return the intersections: - lines.SelectMany(pt => pt).GroupBy(pt => pt).Where(g => g.Count() > 1).Select(g => g.Key); + lines.SelectMany(pt => pt).GroupBy(pt => pt).Where(g => g.Count() > 1).Select(g => g.Key); - IEnumerable> ParseLines(string input, bool skipDiagonals) => - from line in input.Split("\n") + IEnumerable<IEnumerable<Vec2>> ParseLines(string input, bool skipDiagonals) => + from line in input.Split("\n") // parse out numbers first: let ns = ( - from st in line.Split(", ->".ToArray(), StringSplitOptions.RemoveEmptyEntries) + from st in line.Split(", ->".ToArray(), StringSplitOptions.RemoveEmptyEntries) select int.Parse(st) ).ToArray() diff --git a/2021/6/index.html b/2021/6/index.html index 9554d1e1..675f9951 100644 --- a/2021/6/index.html +++ b/2021/6/index.html @@ -283,27 +283,27 @@

Lanternfish

namespace AdventOfCode.Y2021.Day06; -[ProblemName("Lanternfish")] +[ProblemName("Lanternfish")] class Solution : Solver { - public object PartOne(string input) => FishCountAfterNDays(input, 80); - public object PartTwo(string input) => FishCountAfterNDays(input, 256); + public object PartOne(string input) => FishCountAfterNDays(input, 80); + public object PartTwo(string input) => FishCountAfterNDays(input, 256); long FishCountAfterNDays(string input, int days) { // group the fish by their timer, no need to deal with them one by one: var fishCountByInternalTimer = new long[9]; - foreach (var ch in input.Split(',')) { + foreach (var ch in input.Split(',')) { fishCountByInternalTimer[int.Parse(ch)]++; } // we will model a circular shift register, with an additional feedback: // 0123456 78 - // ┌──[.......]─<─(+)───[..]──┐ - // └──────>────────┴─────>────┘ + // ┌──[.......]─<─(+)───[..]──┐ + // └──────>────────┴─────>────┘ // reproduction newborn - for (var t = 0; t < days; t++) { + for (var t = 0; t < days; t++) { fishCountByInternalTimer[(t + 7) % 9] += fishCountByInternalTimer[t % 9]; } diff --git a/2021/7/index.html b/2021/7/index.html index 34ee1895..88049ab2 100644 --- a/2021/7/index.html +++ b/2021/7/index.html @@ -284,20 +284,20 @@

The Treachery of Whales

namespace AdventOfCode.Y2021.Day07; -[ProblemName("The Treachery of Whales")] +[ProblemName("The Treachery of Whales")] class Solution : Solver { - public object PartOne(string input) => - FuelMin(input, fuelConsumption: distance => distance); + public object PartOne(string input) => + FuelMin(input, fuelConsumption: distance => distance); - public object PartTwo(string input) => - FuelMin(input, fuelConsumption: distance => (1 + distance) * distance / 2); + public object PartTwo(string input) => + FuelMin(input, fuelConsumption: distance => (1 + distance) * distance / 2); - int FuelMin(string input, Func fuelConsumption) { - var positions = input.Split(",").Select(int.Parse).ToArray(); + int FuelMin(string input, Func<int, int> fuelConsumption) { + var positions = input.Split(",").Select(int.Parse).ToArray(); - var totalFuelToReachTarget = (int target) => - positions.Select(position => fuelConsumption(Math.Abs(target - position))).Sum(); + var totalFuelToReachTarget = (int target) => + positions.Select(position => fuelConsumption(Math.Abs(target - position))).Sum(); // Minimize the total fuel consumption checking each possible target position. // We have just about 1000 of these, so an O(n^2) algorithm will suffice. diff --git a/2021/8/index.html b/2021/8/index.html index 2751a2de..04a6fa36 100644 --- a/2021/8/index.html +++ b/2021/8/index.html @@ -284,7 +284,7 @@

Seven Segment Search

namespace AdventOfCode.Y2021.Day08; -[ProblemName("Seven Segment Search")] +[ProblemName("Seven Segment Search")] class Solution : Solver { /* @@ -301,12 +301,12 @@

Seven Segment Search

public object PartOne(string input) { // we can identify digits 1, 7, 4 and 8 by their active segments count: - var segmentCounts = new[] { "cd", "acf", "bcdf", "abcdefg" }.Select(x => x.Length).ToHashSet(); + var segmentCounts = new[] { "cd", "acf", "bcdf", "abcdefg" }.Select(x => x.Length).ToHashSet(); return ( - from line in input.Split("\n") - let parts = line.Split(" | ") - from segment in parts[1].Split(" ") + from line in input.Split("\n") + let parts = line.Split(" | ") + from segment in parts[1].Split(" ") where segmentCounts.Contains(segment.Length) select 1 ).Count(); @@ -314,22 +314,22 @@

Seven Segment Search

public object PartTwo(string input) { var res = 0; - foreach(var line in input.Split("\n")) { - var parts = line.Split(" | "); - var patterns = parts[0].Split(" ").Select(x => x.ToHashSet()).ToArray(); + foreach(var line in input.Split("\n")) { + var parts = line.Split(" | "); + var patterns = parts[0].Split(" ").Select(x => x.ToHashSet()).ToArray(); - // let's figure out what segments belong to each digit - var digits = new HashSet[10]; + // let's figure out what segments belong to each digit + var digits = new HashSet<char>[10]; // we can do these by length: - digits[1] = patterns.Single(pattern => pattern.Count() == "cf".Length); - digits[4] = patterns.Single(pattern => pattern.Count() == "bcdf".Length); + digits[1] = patterns.Single(pattern => pattern.Count() == "cf".Length); + digits[4] = patterns.Single(pattern => pattern.Count() == "bcdf".Length); // it turns out that the following tripplet uniquely identifies the rest: - var lookup = (int segmentCount, int commonWithOne, int commonWithFour) => - patterns.Single(pattern => - pattern.Count() == segmentCount && - pattern.Intersect(digits[1]).Count() == commonWithOne && + var lookup = (int segmentCount, int commonWithOne, int commonWithFour) => + patterns.Single(pattern => + pattern.Count() == segmentCount && + pattern.Intersect(digits[1]).Count() == commonWithOne && pattern.Intersect(digits[4]).Count() == commonWithFour ); @@ -342,11 +342,11 @@

Seven Segment Search

digits[8] = lookup(7, 2, 4); digits[9] = lookup(6, 2, 4); - var decode = (string v) => - Enumerable.Range(0, 10).Single(i => digits[i].SetEquals(v)); + var decode = (string v) => + Enumerable.Range(0, 10).Single(i => digits[i].SetEquals(v)); // Decode the number, Horner would like this. - res += parts[1].Split(" ").Aggregate(0, (n, digit) => n * 10 + decode(digit)); + res += parts[1].Split(" ").Aggregate(0, (n, digit) => n * 10 + decode(digit)); } return res; } diff --git a/2021/9/index.html b/2021/9/index.html index b93e94dd..606cf339 100644 --- a/2021/9/index.html +++ b/2021/9/index.html @@ -285,14 +285,14 @@

Smoke Basin

namespace AdventOfCode.Y2021.Day09; -[ProblemName("Smoke Basin")] +[ProblemName("Smoke Basin")] class Solution : Solver { public object PartOne(string input) { var map = GetMap(input); - // find the 'low points' and return a hash computed from their heights: - return GetLowPoints(map).Select(point => 1 + map[point]).Sum(); + // find the 'low points' and return a hash computed from their heights: + return GetLowPoints(map).Select(point => 1 + map[point]).Sum(); } public object PartTwo(string input) { @@ -300,24 +300,24 @@

Smoke Basin

// find the 3 biggest basins and return a hash computed from their size: return GetLowPoints(map) - .Select(p => BasinSize(map, p)) - .OrderByDescending(basinSize => basinSize) + .Select(p => BasinSize(map, p)) + .OrderByDescending(basinSize => basinSize) .Take(3) - .Aggregate(1, (m, basinSize) => m * basinSize); + .Aggregate(1, (m, basinSize) => m * basinSize); } // store the points in a dictionary so that we can iterate over them and // to easily deal with points outside the area using GetValueOrDefault - ImmutableDictionary GetMap(string input) { - var map = input.Split("\n"); + ImmutableDictionary<Point, int> GetMap(string input) { + var map = input.Split("\n"); return ( from y in Enumerable.Range(0, map.Length) from x in Enumerable.Range(0, map[0].Length) - select new KeyValuePair(new Point(x, y), map[y][x] - '0') + select new KeyValuePair<Point, int>(new Point(x, y), map[y][x] - '0') ).ToImmutableDictionary(); } - IEnumerable Neighbours(Point point) => + IEnumerable<Point> Neighbours(Point point) => new [] { point with {y = point.y + 1}, point with {y = point.y - 1}, @@ -325,16 +325,16 @@

Smoke Basin

point with {x = point.x - 1}, }; - public IEnumerable GetLowPoints(ImmutableDictionary map) => + public IEnumerable<Point> GetLowPoints(ImmutableDictionary<Point, int> map) => from point in map.Keys // point is low if each of its neighbours is higher: - where Neighbours(point).All(neighbour => map[point] < map.GetValueOrDefault(neighbour, 9)) + where Neighbours(point).All(neighbour => map[point] < map.GetValueOrDefault(neighbour, 9)) select point; - public int BasinSize(ImmutableDictionary map, Point point) { + public int BasinSize(ImmutableDictionary<Point, int> map, Point point) { // flood fill algorithm - var filled = new HashSet{point}; - var queue = new Queue(filled); + var filled = new HashSet<Point>{point}; + var queue = new Queue<Point>(filled); while (queue.Any()) { foreach (var neighbour in Neighbours(queue.Dequeue()).Except(filled)) { diff --git a/2022/1/index.html b/2022/1/index.html index fe1dc8ea..ada58a93 100644 --- a/2022/1/index.html +++ b/2022/1/index.html @@ -284,19 +284,19 @@

Calorie Counting

namespace AdventOfCode.Y2022.Day01; -[ProblemName("Calorie Counting")] +[ProblemName("Calorie Counting")] class Solution : Solver { - public object PartOne(string input) => + public object PartOne(string input) => GetCaloriesPerElf(input).First(); - public object PartTwo(string input) => + public object PartTwo(string input) => GetCaloriesPerElf(input).Take(3).Sum(); // Returns the calories carried by the elves in descending order. - private IEnumerable GetCaloriesPerElf(string input) => - from elf in input.Split("\n\n") - let calories = elf.Split('\n').Select(int.Parse).Sum() + private IEnumerable<int> GetCaloriesPerElf(string input) => + from elf in input.Split("\n\n") + let calories = elf.Split('\n').Select(int.Parse).Sum() orderby calories descending select calories; } diff --git a/2022/10/index.html b/2022/10/index.html index 36778ac0..51b6b048 100644 --- a/2022/10/index.html +++ b/2022/10/index.html @@ -285,38 +285,38 @@

Cathode-Ray Tube

namespace AdventOfCode.Y2022.Day10; -[ProblemName("Cathode-Ray Tube")] +[ProblemName("Cathode-Ray Tube")] class Solution : Solver { public object PartOne(string input) { var sample = new[] { 20, 60, 100, 140, 180, 220 }; return Signal(input) - .Where(signal => sample.Contains(signal.cycle)) - .Select(signal => signal.x * signal.cycle) + .Where(signal => sample.Contains(signal.cycle)) + .Select(signal => signal.x * signal.cycle) .Sum(); } - public object PartTwo(string input) => + public object PartTwo(string input) => Signal(input) - .Select(signal => { + .Select(signal => { var spriteMiddle = signal.x; var screenColumn = (signal.cycle - 1) % 40; - return Math.Abs(spriteMiddle - screenColumn) < 2 ? '#' : ' '; + return Math.Abs(spriteMiddle - screenColumn) < 2 ? '#' : ' '; }) .Chunk(40) - .Select(line => new string(line)) - .Aggregate("", (screen, line) => screen + line + "\n") + .Select(line => new string(line)) + .Aggregate("", (screen, line) => screen + line + "\n") .Ocr(); - IEnumerable<(int cycle, int x)> Signal(string input) { + IEnumerable<(int cycle, int x)> Signal(string input) { var (cycle, x) = (1, 1); - foreach (var line in input.Split("\n")) { - var parts = line.Split(" "); + foreach (var line in input.Split("\n")) { + var parts = line.Split(" "); switch (parts[0]) { - case "noop": + case "noop": yield return (cycle++, x); break; - case "addx": + case "addx": yield return (cycle++, x); yield return (cycle++, x); x += int.Parse(parts[1]); diff --git a/2022/11/index.html b/2022/11/index.html index 43549c75..f861ca06 100644 --- a/2022/11/index.html +++ b/2022/11/index.html @@ -286,45 +286,45 @@

Monkey in the Middle

namespace AdventOfCode.Y2022.Day11; -[ProblemName("Monkey in the Middle")] +[ProblemName("Monkey in the Middle")] class Solution : Solver { public object PartOne(string input) { var monkeys = ParseMonkeys(input); - Run(20, monkeys, w => w / 3); + Run(20, monkeys, w => w / 3); return GetMonkeyBusinessLevel(monkeys); } public object PartTwo(string input) { var monkeys = ParseMonkeys(input); - var mod = monkeys.Aggregate(1, (mod, monkey) => mod * monkey.mod); - Run(10_000, monkeys, w => w % mod); + var mod = monkeys.Aggregate(1, (mod, monkey) => mod * monkey.mod); + Run(10_000, monkeys, w => w % mod); return GetMonkeyBusinessLevel(monkeys); } - Monkey[] ParseMonkeys(string input) => - input.Split("\n\n").Select(ParseMonkey).ToArray(); + Monkey[] ParseMonkeys(string input) => + input.Split("\n\n").Select(ParseMonkey).ToArray(); Monkey ParseMonkey(string input) { var monkey = new Monkey(); - foreach (var line in input.Split("\n")) { + foreach (var line in input.Split("\n")) { var tryParse = LineParser(line); - if (tryParse(@"Monkey (\d+)", out var arg)) { + if (tryParse(@"Monkey (\d+)", out var arg)) { // pass - } else if (tryParse("Starting items: (.*)", out arg)) { - monkey.items = new Queue(arg.Split(", ").Select(long.Parse)); - } else if (tryParse(@"Operation: new = old \* old", out _)) { - monkey.operation = old => old * old; - } else if (tryParse(@"Operation: new = old \* (\d+)", out arg)) { - monkey.operation = old => old * int.Parse(arg); - } else if (tryParse(@"Operation: new = old \+ (\d+)", out arg)) { - monkey.operation = old => old + int.Parse(arg); - } else if (tryParse(@"Test: divisible by (\d+)", out arg)) { + } else if (tryParse("Starting items: (.*)", out arg)) { + monkey.items = new Queue<long>(arg.Split(", ").Select(long.Parse)); + } else if (tryParse(@"Operation: new = old \* old", out _)) { + monkey.operation = old => old * old; + } else if (tryParse(@"Operation: new = old \* (\d+)", out arg)) { + monkey.operation = old => old * int.Parse(arg); + } else if (tryParse(@"Operation: new = old \+ (\d+)", out arg)) { + monkey.operation = old => old + int.Parse(arg); + } else if (tryParse(@"Test: divisible by (\d+)", out arg)) { monkey.mod = int.Parse(arg); - } else if (tryParse(@"If true: throw to monkey (\d+)", out arg)) { + } else if (tryParse(@"If true: throw to monkey (\d+)", out arg)) { monkey.passToMonkeyIfDivides = int.Parse(arg); - } else if (tryParse(@"If false: throw to monkey (\d+)", out arg)) { + } else if (tryParse(@"If false: throw to monkey (\d+)", out arg)) { monkey.passToMonkeyOtherwise = int.Parse(arg); } else { throw new ArgumentException(line); @@ -333,14 +333,14 @@

Monkey in the Middle

return monkey; } - long GetMonkeyBusinessLevel(IEnumerable monkeys) => + long GetMonkeyBusinessLevel(IEnumerable<Monkey> monkeys) => monkeys - .OrderByDescending(monkey => monkey.inspectedItems) + .OrderByDescending(monkey => monkey.inspectedItems) .Take(2) - .Aggregate(1L, (res, monkey) => res * monkey.inspectedItems); + .Aggregate(1L, (res, monkey) => res * monkey.inspectedItems); - void Run(int rounds, Monkey[] monkeys, Func updateWorryLevel) { - for (var i = 0; i < rounds; i++) { + void Run(int rounds, Monkey[] monkeys, Func<long, long> updateWorryLevel) { + for (var i = 0; i < rounds; i++) { foreach (var monkey in monkeys) { while (monkey.items.Any()) { monkey.inspectedItems++; @@ -360,8 +360,8 @@

Monkey in the Middle

} class Monkey { - public Queue items; - public Func operation; + public Queue<long> items; + public Func<long, long> operation; public int inspectedItems; public int mod; public int passToMonkeyIfDivides, passToMonkeyOtherwise; @@ -375,7 +375,7 @@

Monkey in the Middle

arg = m.Groups[m.Groups.Count - 1].Value; return true; } else { - arg = ""; + arg = ""; return false; } } diff --git a/2022/12/index.html b/2022/12/index.html index 861e3aa0..23e9157b 100644 --- a/2022/12/index.html +++ b/2022/12/index.html @@ -287,49 +287,49 @@

Hill Climbing Algorithm

// // Standard breadth-first algorithm, starting from the goal node and walking backwards. -// I used a dictionary to represent valid coordinates, it's very handy when in need of +// I used a dictionary to represent valid coordinates, it's very handy when in need of // enumerating all coordinates or checking if we are stepping to valid location. // -[ProblemName("Hill Climbing Algorithm")] +[ProblemName("Hill Climbing Algorithm")] class Solution : Solver { // I feel like a cartographer today record struct Coord(int lat, int lon); - // we have two 'char' like things, let's introduce wrappers to keep them well separated in code + // we have two 'char' like things, let's introduce wrappers to keep them well separated in code record struct Symbol(char value); record struct Elevation(char value); // locations on the map will be represented by the following structure of points-of-interests. record struct Poi(Symbol symbol, Elevation elevation, int distanceFromGoal); - Symbol startSymbol = new Symbol('S'); - Symbol goalSymbol = new Symbol('E'); - Elevation lowestElevation = new Elevation('a'); - Elevation highestElevation = new Elevation('z'); + Symbol startSymbol = new Symbol('S'); + Symbol goalSymbol = new Symbol('E'); + Elevation lowestElevation = new Elevation('a'); + Elevation highestElevation = new Elevation('z'); - public object PartOne(string input) => + public object PartOne(string input) => GetPois(input) - .Single(poi => poi.symbol == startSymbol) + .Single(poi => poi.symbol == startSymbol) .distanceFromGoal; - public object PartTwo(string input) => + public object PartTwo(string input) => GetPois(input) - .Where(poi => poi.elevation == lowestElevation) - .Select(poi => poi.distanceFromGoal) + .Where(poi => poi.elevation == lowestElevation) + .Select(poi => poi.distanceFromGoal) .Min(); - IEnumerable GetPois(string input) { + IEnumerable<Poi> GetPois(string input) { var map = ParseMap(input); - var goal = map.Keys.Single(point => map[point] == goalSymbol); + var goal = map.Keys.Single(point => map[point] == goalSymbol); // starting from the goal symbol compute shortest paths for each point of // the map using a breadth-first search. - var poiByCoord = new Dictionary() { + var poiByCoord = new Dictionary<Coord, Poi>() { {goal, new Poi(goalSymbol, GetElevation(goalSymbol), 0)} }; - var q = new Queue(); + var q = new Queue<Coord>(); q.Enqueue(goal); while (q.Any()) { var thisCoord = q.Dequeue(); @@ -343,7 +343,7 @@

Hill Climbing Algorithm

var nextSymbol = map[nextCoord]; var nextElevation = GetElevation(nextSymbol); - if (thisPoi.elevation.value - nextElevation.value <= 1) { + if (thisPoi.elevation.value - nextElevation.value <= 1) { poiByCoord[nextCoord] = new Poi( symbol: nextSymbol, elevation: nextElevation, @@ -357,27 +357,27 @@

Hill Climbing Algorithm

return poiByCoord.Values; } - Elevation GetElevation(Symbol symbol) => + Elevation GetElevation(Symbol symbol) => symbol.value switch { - 'S' => lowestElevation, - 'E' => highestElevation, - _ => new Elevation(symbol.value) + 'S' => lowestElevation, + 'E' => highestElevation, + _ => new Elevation(symbol.value) }; // locations are parsed into a dictionary so that valid coordinates and // neighbours are easy to deal with - ImmutableDictionary ParseMap(string input) { - var lines = input.Split("\n"); + ImmutableDictionary<Coord, Symbol> ParseMap(string input) { + var lines = input.Split("\n"); return ( from y in Enumerable.Range(0, lines.Length) from x in Enumerable.Range(0, lines[0].Length) - select new KeyValuePair( + select new KeyValuePair<Coord, Symbol>( new Coord(x, y), new Symbol(lines[y][x]) ) ).ToImmutableDictionary(); } - IEnumerable Neighbours(Coord coord) => + IEnumerable<Coord> Neighbours(Coord coord) => new[] { coord with {lat = coord.lat + 1}, coord with {lat = coord.lat - 1}, diff --git a/2022/13/index.html b/2022/13/index.html index 496db687..a1bf7581 100644 --- a/2022/13/index.html +++ b/2022/13/index.html @@ -286,52 +286,52 @@

Distress Signal

namespace AdventOfCode.Y2022.Day13; -// NOTES: I don't use C# during the year, so I didn't know which Json parser to use +// NOTES: I don't use C# during the year, so I didn't know which Json parser to use // and first went with System.Text.Json, then found a solution on reddit which uses // System.Text.Json.Nodes and could improve my coding a bit. // -// For part2: I couldn't find a version of OrderBy() that would take a simple comparator -// function, and I didn't want to implement a full blown IComparer interface. Then -// realised that List has a Sort function which works with just a simple delegate. -// Unfortunately it's a void function so there is no way to chain the result further. +// For part2: I couldn't find a version of OrderBy() that would take a simple comparator +// function, and I didn't want to implement a full blown IComparer<T> interface. Then +// realised that List<T> has a Sort function which works with just a simple delegate. +// Unfortunately it's a void function so there is no way to chain the result further. // So much about using just one expression for Part2. // -// I didn't have a great idea to deal with the 1 based indexing, but I'm satisfied with +// I didn't have a great idea to deal with the 1 based indexing, but I'm satisfied with // how this looks in general. Well mostly. I managed to overgolf the compare function // at the end... // -[ProblemName("Distress Signal")] +[ProblemName("Distress Signal")] class Solution : Solver { - public object PartOne(string input) => + public object PartOne(string input) => GetPackets(input) .Chunk(2) - .Select((pair, index) => Compare(pair[0], pair[1]) < 0 ? index + 1 : 0) + .Select((pair, index) => Compare(pair[0], pair[1]) < 0 ? index + 1 : 0) .Sum(); public object PartTwo(string input) { - var divider = GetPackets("[[2]]\n[[6]]").ToList(); + var divider = GetPackets("[[2]]\n[[6]]").ToList(); var packets = GetPackets(input).Concat(divider).ToList(); packets.Sort(Compare); return (packets.IndexOf(divider[0]) + 1) * (packets.IndexOf(divider[1]) + 1); } - IEnumerable GetPackets(string input) => - from line in input.Split("\n") + IEnumerable<JsonNode> GetPackets(string input) => + from line in input.Split("\n") where !string.IsNullOrEmpty(line) select JsonNode.Parse(line); int Compare(JsonNode nodeA, JsonNode nodeB) { - if (nodeA is JsonValue && nodeB is JsonValue) { + if (nodeA is JsonValue && nodeB is JsonValue) { return (int)nodeA - (int)nodeB; } else { - // It's AoC time, let's exploit FirstOrDefault! + // It's AoC time, let's exploit FirstOrDefault! // 😈 if all items are equal, compare the length of the arrays var arrayA = nodeA as JsonArray ?? new JsonArray((int)nodeA); var arrayB = nodeB as JsonArray ?? new JsonArray((int)nodeB); return Enumerable.Zip(arrayA, arrayB) - .Select(p => Compare(p.First, p.Second)) - .FirstOrDefault(c => c != 0, arrayA.Count - arrayB.Count); + .Select(p => Compare(p.First, p.Second)) + .FirstOrDefault(c => c != 0, arrayA.Count - arrayB.Count); } } } diff --git a/2022/14/index.html b/2022/14/index.html index 7d1ff0c5..15dc34b0 100644 --- a/2022/14/index.html +++ b/2022/14/index.html @@ -286,38 +286,38 @@

Regolith Reservoir

namespace AdventOfCode.Y2022.Day14; -[ProblemName("Regolith Reservoir")] +[ProblemName("Regolith Reservoir")] class Solution : Solver { public object PartOne(string input) - => new Cave(input, hasFloor: false).FillWithSand(new Complex(500, 0)); + => new Cave(input, hasFloor: false).FillWithSand(new Complex(500, 0)); public object PartTwo(string input) - => new Cave(input, hasFloor: true).FillWithSand(new Complex(500, 0)); + => new Cave(input, hasFloor: true).FillWithSand(new Complex(500, 0)); } class Cave { bool hasFloor; - Dictionary map; + Dictionary<Complex, char> map; int maxImaginary; public Cave(string input, bool hasFloor) { this.hasFloor = hasFloor; - this.map = new Dictionary(); + this.map = new Dictionary<Complex, char>(); - foreach (var line in input.Split("\n")) { + foreach (var line in input.Split("\n")) { var steps = ( - from step in line.Split(" -> ") - let parts = step.Split(",") + from step in line.Split(" -> ") + let parts = step.Split(",") select new Complex(int.Parse(parts[0]), int.Parse(parts[1])) ).ToArray(); - for (var i = 1; i < steps.Length; i++) { + for (var i = 1; i < steps.Length; i++) { FillWithRocks(steps[i - 1], steps[i]); } } - this.maxImaginary = (int)this.map.Keys.Select(pos => pos.Imaginary).Max(); + this.maxImaginary = (int)this.map.Keys.Select(pos => pos.Imaginary).Max(); } // Adds a line of rocks to the cave @@ -329,7 +329,7 @@

Regolith Reservoir

var steps = 0; for (var pos = from; pos != to + dir; pos += dir) { - map[pos] = '#'; + map[pos] = '#'; steps ++; } return steps; @@ -347,14 +347,14 @@

Regolith Reservoir

} // flows out into the void - if (!hasFloor && location.Imaginary == maxImaginary + 1) { + if (!hasFloor && location.Imaginary == maxImaginary + 1) { break; } - map[location] = 'o'; + map[location] = 'o'; } - return map.Values.Count(x => x == 'o'); + return map.Values.Count(x => x == 'o'); } // Returns the final location of a falling unit of sand following the rules of cave physics @@ -363,7 +363,7 @@

Regolith Reservoir

var left = new Complex(-1, 1); var right = new Complex(1, 1); - while (sand.Imaginary < maxImaginary + 1) { + while (sand.Imaginary < maxImaginary + 1) { if (!map.ContainsKey(sand + down)) { sand += down; } else if (!map.ContainsKey(sand + left)) { diff --git a/2022/15/index.html b/2022/15/index.html index 3cdac597..173339f0 100644 --- a/2022/15/index.html +++ b/2022/15/index.html @@ -286,21 +286,21 @@

Beacon Exclusion Zone

namespace AdventOfCode.Y2022.Day15; -[ProblemName("Beacon Exclusion Zone")] +[ProblemName("Beacon Exclusion Zone")] class Solution : Solver { public object PartOne(string input) { var pairing = Parse(input).ToArray(); - var rects = pairing.Select(pair => pair.ToRect()).ToArray(); - var left = rects.Select(r => r.Left).Min(); - var right = rects.Select(r => r.Right).Max(); + var rects = pairing.Select(pair => pair.ToRect()).ToArray(); + var left = rects.Select(r => r.Left).Min(); + var right = rects.Select(r => r.Right).Max(); var y = 2000000; var res = 0; - for (var x = left; x <= right; x++) { + for (var x = left; x <= right; x++) { var pos = new Pos(x, y); - if (pairing.Any(pair => pair.beacon != pos && pair.InRange(pos))) { + if (pairing.Any(pair => pair.beacon != pos && pair.InRange(pos))) { res++; } } @@ -315,9 +315,9 @@

Beacon Exclusion Zone

// Parse the 4 numbers with regex from each line and return the list of pairings - IEnumerable Parse(string input) { - foreach (var line in input.Split("\n")) { - var numbers = Regex.Matches(line, @"-?\d+").Select(m => int.Parse(m.Value)).ToArray(); + IEnumerable<Pair> Parse(string input) { + foreach (var line in input.Split("\n")) { + var numbers = Regex.Matches(line, @"-?\d+").Select(m => int.Parse(m.Value)).ToArray(); yield return new Pair( sensor: new Pos(numbers[0], numbers[1]), beacon: new Pos(numbers[2], numbers[3]) @@ -327,21 +327,21 @@

Beacon Exclusion Zone

// Do a quadtree style recursive check for uncovered areas with early exit // when there is proof that the rectangle is fully covered / uncovered - IEnumerable GetUncoveredAreas(Pair[] pairing, Rect rect) { - // empty rectangle -> doesn't have uncovered areas 👍 + IEnumerable<Rect> GetUncoveredAreas(Pair[] pairing, Rect rect) { + // empty rectangle -> doesn't have uncovered areas 👍 if (rect.Width == 0 || rect.Height == 0) { yield break; } - // if all 4 corners of the rectangle are in range of one of the sensors -> it's covered 👍 + // if all 4 corners of the rectangle are in range of one of the sensors -> it's covered 👍 foreach (var pair in pairing) { - if (rect.Corners.All(corner => pair.InRange(corner))) { + if (rect.Corners.All(corner => pair.InRange(corner))) { yield break; } } - // if the rectangle is 1x1 -> we just proved that it's uncovered 👍 - if (rect.Width == 1 && rect.Height == 1) { + // if the rectangle is 1x1 -> we just proved that it's uncovered 👍 + if (rect.Width == 1 && rect.Height == 1) { yield return rect; yield break; } @@ -358,11 +358,11 @@

Beacon Exclusion Zone

record struct Pos(int X, int Y); - // I don't have a better name for a sensor-bacon pair + // I don't have a better name for a sensor-bacon pair record struct Pair(Pos sensor, Pos beacon) { public int Radius = Manhattan(sensor, beacon); - public bool InRange(Pos pos) => Manhattan(pos, sensor) <= Radius; + public bool InRange(Pos pos) => Manhattan(pos, sensor) <= Radius; // The smallest rectangle that covers the whole range of the pairing: // ............................ @@ -376,20 +376,20 @@

Beacon Exclusion Zone

// ..........===###===......... // ..........====#====......... // ............................ - public Rect ToRect() => + public Rect ToRect() => new Rect(sensor.X - Radius, sensor.Y - Radius, 2 * Radius + 1, 2 * Radius + 1); - static int Manhattan(Pos p1, Pos p2) => + static int Manhattan(Pos p1, Pos p2) => Math.Abs(p1.X - p2.X) + Math.Abs(p1.Y - p2.Y); } record struct Rect(int X, int Y, int Width, int Height) { - public int Left => X; - public int Right => X + Width - 1; - public int Top => Y; - public int Bottom => Y + Height - 1; + public int Left => X; + public int Right => X + Width - 1; + public int Top => Y; + public int Bottom => Y + Height - 1; - public IEnumerable Corners { + public IEnumerable<Pos> Corners { get { yield return new Pos(Left, Top); yield return new Pos(Right, Top); @@ -399,7 +399,7 @@

Beacon Exclusion Zone

} // Creates 4 smaller rectangles, might return empty ones with width or height == 0 - public IEnumerable Split() { + public IEnumerable<Rect> Split() { var w0 = Width / 2; var w1 = Width - w0; var h0 = Height / 2; diff --git a/2022/16/index.html b/2022/16/index.html index ecd7abe8..9efdf46f 100644 --- a/2022/16/index.html +++ b/2022/16/index.html @@ -286,7 +286,7 @@

Proboscidea Volcanium

namespace AdventOfCode.Y2022.Day16; -[ProblemName("Proboscidea Volcanium")] +[ProblemName("Proboscidea Volcanium")] class Solution : Solver { record Map(int[,] distances, Valve[] valves); @@ -301,14 +301,14 @@

Proboscidea Volcanium

int Solve(string input, bool humanOnly, int time) { var map = Parse(input); - var start = map.valves.Single(x => x.name == "AA"); - var valvesToOpen = map.valves.Where(valve => valve.flowRate > 0).ToArray(); + var start = map.valves.Single(x => x.name == "AA"); + var valvesToOpen = map.valves.Where(valve => valve.flowRate > 0).ToArray(); - var cache = new Dictionary(); + var cache = new Dictionary<string, int>(); if (humanOnly) { return MaxFlow(cache, map, start, valvesToOpen.ToHashSet(), time); } else { - return Pairings(valvesToOpen).Select(pairing => + return Pairings(valvesToOpen).Select(pairing => MaxFlow(cache, map, start, pairing.human, time) + MaxFlow(cache, map, start, pairing.elephant, time) ).Max(); @@ -316,17 +316,17 @@

Proboscidea Volcanium

} // Divide the valves between human and elephant in all possible ways - IEnumerable<(HashSet human, HashSet elephant)> Pairings(Valve[] valves) { - var maxMask = 1 << (valves.Length - 1); + IEnumerable<(HashSet<Valve> human, HashSet<Valve> elephant)> Pairings(Valve[] valves) { + var maxMask = 1 << (valves.Length - 1); - for (var mask = 0; mask < maxMask; mask++) { - var elephant = new HashSet(); - var human = new HashSet(); + for (var mask = 0; mask < maxMask; mask++) { + var elephant = new HashSet<Valve>(); + var human = new HashSet<Valve>(); elephant.Add(valves[0]); - for (var ivalve = 1; ivalve < valves.Length; ivalve++) { - if ((mask & (1 << ivalve)) == 0) { + for (var ivalve = 1; ivalve < valves.Length; ivalve++) { + if ((mask & (1 << ivalve)) == 0) { human.Add(valves[ivalve]); } else { elephant.Add(valves[ivalve]); @@ -337,16 +337,16 @@

Proboscidea Volcanium

} int MaxFlow( - Dictionary cache, + Dictionary<string, int> cache, Map map, Valve currentValve, - HashSet valves, + HashSet<Valve> valves, int remainingTime ) { string key = - remainingTime + "-" + - currentValve.id + "-" + - string.Join("-", valves.OrderBy(x => x.id).Select(x => x.id)); + remainingTime + "-" + + currentValve.id + "-" + + string.Join("-", valves.OrderBy(x => x.id).Select(x => x.id)); if (!cache.ContainsKey(key)) { // current valve gives us this much flow: @@ -357,7 +357,7 @@

Proboscidea Volcanium

foreach (var valve in valves.ToArray()) { var distance = map.distances[currentValve.id, valve.id]; - if (remainingTime >= distance + 1) { + if (remainingTime >= distance + 1) { valves.Remove(valve); remainingTime -= distance + 1; @@ -377,16 +377,16 @@

Proboscidea Volcanium

Map Parse(string input) { // Valve BB has flow rate=0; tunnels lead to valve CC // Valve CC has flow rate=10; tunnels lead to valves DD, EE - var valveList = new List(); - foreach (var line in input.Split("\n")) { - var name = Regex.Match(line, "Valve (.*) has").Groups[1].Value; - var flow = int.Parse(Regex.Match(line, @"\d+").Groups[0].Value); - var tunnels = Regex.Match(line, "to valves? (.*)").Groups[1].Value.Split(", "); + var valveList = new List<Valve>(); + foreach (var line in input.Split("\n")) { + var name = Regex.Match(line, "Valve (.*) has").Groups[1].Value; + var flow = int.Parse(Regex.Match(line, @"\d+").Groups[0].Value); + var tunnels = Regex.Match(line, "to valves? (.*)").Groups[1].Value.Split(", "); valveList.Add(new Valve(0, name, flow, tunnels)); } var valves = valveList - .OrderByDescending(valve => valve.flowRate) - .Select((v, i) => v with { id = i }) + .OrderByDescending(valve => valve.flowRate) + .Select((v, i) => v with { id = i }) .ToArray(); return new Map(ComputeDistances(valves), valves); @@ -400,20 +400,20 @@

Proboscidea Volcanium

// This is an O(n^3) algorithm, but we are dealing with a low n. var n = valves.Length; - // Just "big enough" so that infinity + infinity still fits in an int. + // Just "big enough" so that infinity + infinity still fits in an int. var infinity = int.MaxValue / 2; var dist = new int[valves.Length, valves.Length]; - for (var i = 0; i < n; i++) { - for (var j = 0; j < n; j++) { + for (var i = 0; i < n; i++) { + for (var j = 0; j < n; j++) { var neighbours = valves[i].tunnels.Contains(valves[j].name); dist[i, j] = neighbours ? 1 : infinity; } } - for (var k = 0; k < n; k++) { - for (var i = 0; i < n; i++) { - for (var j = 0; j < n; j++) { + for (var k = 0; k < n; k++) { + for (var i = 0; i < n; i++) { + for (var j = 0; j < n; j++) { dist[i, j] = Math.Min(dist[i,j], dist[i, k] + dist[k, j]); } } diff --git a/2022/17/index.html b/2022/17/index.html index d2c60f00..1f7502c9 100644 --- a/2022/17/index.html +++ b/2022/17/index.html @@ -285,7 +285,7 @@

Pyroclastic Flow

namespace AdventOfCode.Y2022.Day17; -[ProblemName("Pyroclastic Flow")] +[ProblemName("Pyroclastic Flow")] class Solution : Solver { public object PartOne(string input) { @@ -299,10 +299,10 @@

Pyroclastic Flow

class Tunnel { int linesToStore; - List lines = new List(); + List<char[]> lines = new List<char[]>(); long linesNotStored; - public long Height => lines.Count + linesNotStored; + public long Height => lines.Count + linesNotStored; string[][] rocks; string jets; @@ -314,11 +314,11 @@

Pyroclastic Flow

public Tunnel(string jets, int linesToStore) { this.linesToStore = linesToStore; rocks = new string[][]{ - new []{"####"}, - new []{" # ", "###", " # "}, - new []{" #", " #", "###"}, - new []{"#", "#", "#", "#"}, - new []{"##", "##"} + new []{"####"}, + new []{" # ", "###", " # "}, + new []{" #", " #", "###"}, + new []{"#", "#", "#", "#"}, + new []{"##", "##"} }; this.irock = new ModCounter(0, rocks.Length); @@ -335,9 +335,9 @@

Pyroclastic Flow

// Then we just add the remaining rocks. - var seen = new Dictionary(); - while (rocksToAdd > 0) { - var hash = string.Join("", lines.SelectMany(ch => ch)); + var seen = new Dictionary<string, (long rocksToAdd, long height)>(); + while (rocksToAdd > 0) { + var hash = string.Join("", lines.SelectMany(ch => ch)); if (seen.TryGetValue(hash, out var cache)) { // we have seen this pattern, advance forwad as much as possible var heightOfPeriod = this.Height - cache.height; @@ -352,7 +352,7 @@

Pyroclastic Flow

} } - while (rocksToAdd > 0) { + while (rocksToAdd > 0) { this.AddRock(); rocksToAdd--; } @@ -364,17 +364,17 @@

Pyroclastic Flow

var rock = rocks[(int)irock++]; // make room of 3 lines + the height of the rock - for (var i = 0; i < rock.Length + 3; i++) { - lines.Insert(0, "| |".ToArray()); + for (var i = 0; i < rock.Length + 3; i++) { + lines.Insert(0, "| |".ToArray()); } // simulate falling var pos = new Pos(0, 3); while (true) { var jet = jets[(int)ijet++]; - if (jet == '>' && !Hit(rock, pos.Right)) { + if (jet == '>' && !Hit(rock, pos.Right)) { pos = pos.Right; - } else if (jet == '<' && !Hit(rock, pos.Left)) { + } else if (jet == '<' && !Hit(rock, pos.Left)) { pos = pos.Left; } if (Hit(rock, pos.Below)) { @@ -388,57 +388,57 @@

Pyroclastic Flow

} // tells if a rock can be placed in the given location or hits something - bool Hit(string[] rock, Pos pos) => - Area(rock).Any(pt => - Get(rock, pt) == '#' && - Get(lines, pt + pos) != ' ' + bool Hit(string[] rock, Pos pos) => + Area(rock).Any(pt => + Get(rock, pt) == '#' && + Get(lines, pt + pos) != ' ' ); void Draw(string[] rock, Pos pos) { // draws a rock pattern into the cave at the given x,y coordinates, foreach (var pt in Area(rock)) { - if (Get(rock, pt) == '#') { - Set(lines, pt + pos, '#'); + if (Get(rock, pt) == '#') { + Set(lines, pt + pos, '#'); } } // remove empty lines from the top - while (!lines[0].Contains('#')) { + while (!lines[0].Contains('#')) { lines.RemoveAt(0); } // keep the tail - while (lines.Count > linesToStore) { + while (lines.Count > linesToStore) { lines.RemoveAt(lines.Count - 1); linesNotStored ++; } } } - static IEnumerable Area(string[] mat) => + static IEnumerable<Pos> Area(string[] mat) => from irow in Enumerable.Range(0, mat.Length) from icol in Enumerable.Range(0, mat[0].Length) select new Pos(irow, icol); - static char Get(IEnumerable> mat, Pos pos) { - return (mat.ElementAtOrDefault(pos.irow) ?? "#########").ElementAt(pos.icol); + static char Get(IEnumerable<IEnumerable<char>> mat, Pos pos) { + return (mat.ElementAtOrDefault(pos.irow) ?? "#########").ElementAt(pos.icol); } - static char Set(IList mat, Pos pos, char ch) { + static char Set(IList<char[]> mat, Pos pos, char ch) { return mat[pos.irow][pos.icol] = ch; } record struct Pos(int irow, int icol) { - public Pos Left => new Pos(irow, icol - 1); - public Pos Right => new Pos(irow, icol + 1); - public Pos Below => new Pos(irow + 1, icol); - public static Pos operator +(Pos posA, Pos posB) => + public Pos Left => new Pos(irow, icol - 1); + public Pos Right => new Pos(irow, icol + 1); + public Pos Below => new Pos(irow + 1, icol); + public static Pos operator +(Pos posA, Pos posB) => new Pos(posA.irow + posB.irow, posA.icol + posB.icol); } record struct ModCounter(int index, int mod) { - public static explicit operator int(ModCounter c) => c.index; - public static ModCounter operator ++(ModCounter c) => + public static explicit operator int(ModCounter c) => c.index; + public static ModCounter operator ++(ModCounter c) => c with { index = c.index == c.mod - 1 ? 0 : c.index + 1 }; } } diff --git a/2022/18/index.html b/2022/18/index.html index 82f494dc..0769a9ca 100644 --- a/2022/18/index.html +++ b/2022/18/index.html @@ -284,7 +284,7 @@

Boiling Boulders

namespace AdventOfCode.Y2022.Day18; -[ProblemName("Boiling Boulders")] +[ProblemName("Boiling Boulders")] class Solution : Solver { record class Point(int x, int y, int z); @@ -292,29 +292,29 @@

Boiling Boulders

public object PartOne(string input) { var lavaLocations = GetLavaLocations(input).ToHashSet(); - return lavaLocations.SelectMany(Neighbours).Count(p => !lavaLocations.Contains(p)); + return lavaLocations.SelectMany(Neighbours).Count(p => !lavaLocations.Contains(p)); } public object PartTwo(string input) { var lavaLocations = GetLavaLocations(input).ToHashSet(); var bounds = GetBounds(lavaLocations); var waterLocations = FillWithWater(bounds.min, bounds, lavaLocations); - return lavaLocations.SelectMany(Neighbours).Count(p => waterLocations.Contains(p)); + return lavaLocations.SelectMany(Neighbours).Count(p => waterLocations.Contains(p)); } // fills a region with water starting from the given point and avoiding lavalLocations // standard flood fill algorithm - HashSet FillWithWater(Point from, Bounds bounds, HashSet lavaLocations) { - var result = new HashSet(); - var q = new Queue(); + HashSet<Point> FillWithWater(Point from, Bounds bounds, HashSet<Point> lavaLocations) { + var result = new HashSet<Point>(); + var q = new Queue<Point>(); result.Add(from); q.Enqueue(from); while (q.Any()) { var water = q.Dequeue(); foreach (var neighbour in Neighbours(water)) { - if (!result.Contains(neighbour) && - Within(bounds, neighbour) && + if (!result.Contains(neighbour) && + Within(bounds, neighbour) && !lavaLocations.Contains(neighbour) ) { result.Add(neighbour); @@ -326,31 +326,31 @@

Boiling Boulders

return result; } - IEnumerable GetLavaLocations(string input) => - from line in input.Split("\n") - let coords = line.Split(",").Select(int.Parse).ToArray() + IEnumerable<Point> GetLavaLocations(string input) => + from line in input.Split("\n") + let coords = line.Split(",").Select(int.Parse).ToArray() select new Point(coords[0], coords[1], coords[2]); // returns the enclosing box of a point set, the min and max values are padded by one - Bounds GetBounds(IEnumerable points) { - var minX = points.Select(p => p.x).Min() - 1; - var maxX = points.Select(p => p.x).Max() + 1; + Bounds GetBounds(IEnumerable<Point> points) { + var minX = points.Select(p => p.x).Min() - 1; + var maxX = points.Select(p => p.x).Max() + 1; - var minY = points.Select(p => p.y).Min() - 1; - var maxY = points.Select(p => p.y).Max() + 1; + var minY = points.Select(p => p.y).Min() - 1; + var maxY = points.Select(p => p.y).Max() + 1; - var minZ = points.Select(p => p.z).Min() - 1; - var maxZ = points.Select(p => p.z).Max() + 1; + var minZ = points.Select(p => p.z).Min() - 1; + var maxZ = points.Select(p => p.z).Max() + 1; return new Bounds(new Point(minX, minY, minZ), new Point(maxX, maxY, maxZ)); } - bool Within(Bounds bounds, Point point) => - bounds.min.x <= point.x && point.x <= bounds.max.x && - bounds.min.y <= point.y && point.y <= bounds.max.y && - bounds.min.z <= point.z && point.z <= bounds.max.z; + bool Within(Bounds bounds, Point point) => + bounds.min.x <= point.x && point.x <= bounds.max.x && + bounds.min.y <= point.y && point.y <= bounds.max.y && + bounds.min.z <= point.z && point.z <= bounds.max.z; - IEnumerable Neighbours(Point point) => + IEnumerable<Point> Neighbours(Point point) => new[]{ point with { x = point.x - 1 }, point with { x = point.x + 1 }, diff --git a/2022/19/index.html b/2022/19/index.html index 945ba239..01060521 100644 --- a/2022/19/index.html +++ b/2022/19/index.html @@ -286,12 +286,12 @@

Not Enough Minerals

namespace AdventOfCode.Y2022.Day19; -[ProblemName("Not Enough Minerals")] +[ProblemName("Not Enough Minerals")] class Solution : Solver { public object PartOne(string input) { var res = 0; - foreach (var blueprint in Parse(input).Where(bp => bp.id < 100)) { + foreach (var blueprint in Parse(input).Where(bp => bp.id < 100)) { var m = MaxGeodes(blueprint, 24); res += blueprint.id * m; } @@ -300,7 +300,7 @@

Not Enough Minerals

public object PartTwo(string input) { var res = 1; - foreach (var blueprint in Parse(input).Where(bp => bp.id <= 3)) { + foreach (var blueprint in Parse(input).Where(bp => bp.id <= 3)) { var m = MaxGeodes(blueprint, 32); res *= m; } @@ -309,8 +309,8 @@

Not Enough Minerals

// Priority queue based maximum search with LOTS OF PRUNING private int MaxGeodes(Blueprint blueprint, int timeLimit) { - var q = new PriorityQueue(); - var seen = new HashSet(); + var q = new PriorityQueue<State, int>(); + var seen = new HashSet<State>(); enqueue(new State( remainingTime: timeLimit, @@ -320,12 +320,12 @@

Not Enough Minerals

)); var max = 0; - while (q.Count > 0) { + while (q.Count > 0) { var state = q.Dequeue(); // Queue is ordered by potentialGeodeCount, there is // no point in investigating the remaining items. - if (potentialGeodeCount(state) < max) { + if (potentialGeodeCount(state) < max) { break; } @@ -338,7 +338,7 @@

Not Enough Minerals

} else { // What robots can be created from the available materials? var buildableRobots = blueprint.robots - .Where(robot => state.available >= robot.cost) + .Where(robot => state.available >= robot.cost) .ToArray(); // 1) build one of them right away @@ -353,15 +353,15 @@

Not Enough Minerals

} } - // 2) or wait until next round for more robot types. Don't postpone + // 2) or wait until next round for more robot types. Don't postpone // building of robots which are already available. This is a very - // very important prunning step. It's about 25 times faster if we + // very important prunning step. It's about 25 times faster if we // do it this way. enqueue( state with { remainingTime = state.remainingTime - 1, available = state.available + state.producing, - dontBuild = buildableRobots.Select(robot => robot.id).Sum(), + dontBuild = buildableRobots.Select(robot => robot.id).Sum(), } ); } @@ -373,7 +373,7 @@

Not Enough Minerals

// ------- // Upper limit for the maximum geodes we reach when starting from this state. - // Let's be optimistic and suppose that in each step we will be able to build + // Let's be optimistic and suppose that in each step we will be able to build // a new geode robot... int potentialGeodeCount(State state) { // sum of [state.producing.geode .. state.producing.geode + state.remainingTime - 1] @@ -385,14 +385,14 @@

Not Enough Minerals

bool worthBuilding(State state, Robot robot) { // We can explicitly ignore building some robots. // Robot ids are powers of 2 used as flags in the dontBuild integer. - if ((state.dontBuild & robot.id) != 0) { + if ((state.dontBuild & robot.id) != 0) { return false; } // Our factory can build just a single robot in a round. This gives as // a prunning condition. Producing more material in a round that we can // spend on building a new robot is worthless. - return state.producing + robot.producing <= blueprint.maxCost; + return state.producing + robot.producing <= blueprint.maxCost; } // Just add an item to the search queue, use -potentialGeodeCount as priority @@ -401,9 +401,9 @@

Not Enough Minerals

} } - IEnumerable Parse(string input) { - foreach (var line in input.Split("\n")) { - var numbers = Regex.Matches(line, @"(\d+)").Select(x => int.Parse(x.Value)).ToArray(); + IEnumerable<Blueprint> Parse(string input) { + foreach (var line in input.Split("\n")) { + var numbers = Regex.Matches(line, @"(\d+)").Select(x => int.Parse(x.Value)).ToArray(); yield return new Blueprint( id: numbers[0], new Robot(id: 1, producing: Ore, cost: numbers[1] * Ore), @@ -442,20 +442,20 @@

Not Enough Minerals

); } - public static bool operator <=(Material a, Material b) { + public static bool operator <=(Material a, Material b) { return - a.ore <= b.ore && - a.clay <= b.clay && - a.obsidian <= b.obsidian && - a.geode <= b.geode; + a.ore <= b.ore && + a.clay <= b.clay && + a.obsidian <= b.obsidian && + a.geode <= b.geode; } - public static bool operator >=(Material a, Material b) { + public static bool operator >=(Material a, Material b) { return - a.ore >= b.ore && - a.clay >= b.clay && - a.obsidian >= b.obsidian && - a.geode >= b.geode; + a.ore >= b.ore && + a.clay >= b.clay && + a.obsidian >= b.obsidian && + a.geode >= b.geode; } } @@ -463,9 +463,9 @@

Not Enough Minerals

record State(int remainingTime, Material available, Material producing, int dontBuild); record Blueprint(int id, params Robot[] robots) { public Material maxCost = new Material( - ore: robots.Select(robot => robot.cost.ore).Max(), - clay: robots.Select(robot => robot.cost.clay).Max(), - obsidian: robots.Select(robot => robot.cost.obsidian).Max(), + ore: robots.Select(robot => robot.cost.ore).Max(), + clay: robots.Select(robot => robot.cost.clay).Max(), + obsidian: robots.Select(robot => robot.cost.obsidian).Max(), geode: int.MaxValue ); } diff --git a/2022/2/index.html b/2022/2/index.html index fb79be8b..85c33b63 100644 --- a/2022/2/index.html +++ b/2022/2/index.html @@ -284,7 +284,7 @@

Rock Paper Scissors

namespace AdventOfCode.Y2022.Day02; -[ProblemName("Rock Paper Scissors")] +[ProblemName("Rock Paper Scissors")] class Solution : Solver { // There are many obscure ways of solving this challenge. You can use @@ -303,41 +303,41 @@

Rock Paper Scissors

Scissors = 3, } - public object PartOne(string input) => Total(input, Elf, Human1); + public object PartOne(string input) => Total(input, Elf, Human1); - public object PartTwo(string input) => Total(input, Elf, Human2); + public object PartTwo(string input) => Total(input, Elf, Human2); - Sign Elf(string line) => - line[0] == 'A' ? Sign.Rock : - line[0] == 'B' ? Sign.Paper : - line[0] == 'C' ? Sign.Scissors : + Sign Elf(string line) => + line[0] == 'A' ? Sign.Rock : + line[0] == 'B' ? Sign.Paper : + line[0] == 'C' ? Sign.Scissors : throw new ArgumentException(line); - Sign Human1(string line) => - line[2] == 'X' ? Sign.Rock : - line[2] == 'Y' ? Sign.Paper : - line[2] == 'Z' ? Sign.Scissors : + Sign Human1(string line) => + line[2] == 'X' ? Sign.Rock : + line[2] == 'Y' ? Sign.Paper : + line[2] == 'Z' ? Sign.Scissors : throw new ArgumentException(line); - Sign Human2(string line) => - line[2] == 'X' ? Next(Next(Elf(line))): // elf wins - line[2] == 'Y' ? Elf(line) : // draw - line[2] == 'Z' ? Next(Elf(line)) : // you win + Sign Human2(string line) => + line[2] == 'X' ? Next(Next(Elf(line))): // elf wins + line[2] == 'Y' ? Elf(line) : // draw + line[2] == 'Z' ? Next(Elf(line)) : // you win throw new ArgumentException(line); - int Total(string input, Func elf, Func human) => + int Total(string input, Func<string, Sign> elf, Func<string, Sign> human) => input - .Split("\n") - .Select(line => Score(elf(line), human(line))) + .Split("\n") + .Select(line => Score(elf(line), human(line))) .Sum(); - int Score(Sign elfSign, Sign humanSign) => + int Score(Sign elfSign, Sign humanSign) => humanSign == Next(elfSign) ? 6 + (int)humanSign : // human wins humanSign == elfSign ? 3 + (int)humanSign : // draw humanSign == Next(Next(elfSign)) ? 0 + (int)humanSign : // elf wins throw new ArgumentException(); - Sign Next(Sign sign) => + Sign Next(Sign sign) => sign == Sign.Rock ? Sign.Paper : sign == Sign.Paper ? Sign.Scissors : sign == Sign.Scissors ? Sign.Rock : diff --git a/2022/20/index.html b/2022/20/index.html index 530f3637..5f055044 100644 --- a/2022/20/index.html +++ b/2022/20/index.html @@ -284,36 +284,36 @@

Grove Positioning System

namespace AdventOfCode.Y2022.Day20; -[ProblemName("Grove Positioning System")] +[ProblemName("Grove Positioning System")] class Solution : Solver { record Data(int idx, long num); - public object PartOne(string input) => + public object PartOne(string input) => GetGrooveCoordinates(Mix(Parse(input, 1))); public object PartTwo(string input) { var data = Parse(input, 811589153L); - for (var i = 0; i < 10; i++) { + for (var i = 0; i < 10; i++) { data = Mix(data); } return GetGrooveCoordinates(data); } - List Parse(string input, long m) => + List<Data> Parse(string input, long m) => input - .Split("\n") - .Select((line, idx) => new Data(idx, long.Parse(line) * m)) + .Split("\n") + .Select((line, idx) => new Data(idx, long.Parse(line) * m)) .ToList(); - List Mix(List numsWithIdx) { + List<Data> Mix(List<Data> numsWithIdx) { var mod = numsWithIdx.Count - 1; - for (var idx = 0; idx < numsWithIdx.Count; idx++) { - var srcIdx = numsWithIdx.FindIndex(x => x.idx == idx); + for (var idx = 0; idx < numsWithIdx.Count; idx++) { + var srcIdx = numsWithIdx.FindIndex(x => x.idx == idx); var num = numsWithIdx[srcIdx]; var dstIdx = (srcIdx + num.num) % mod; - if (dstIdx < 0) { + if (dstIdx < 0) { dstIdx += mod; } @@ -323,8 +323,8 @@

Grove Positioning System

return numsWithIdx; } - long GetGrooveCoordinates(List numsWithIdx) { - var idx = numsWithIdx.FindIndex(x => x.num == 0); + long GetGrooveCoordinates(List<Data> numsWithIdx) { + var idx = numsWithIdx.FindIndex(x => x.num == 0); return ( numsWithIdx[(idx + 1000) % numsWithIdx.Count].num + numsWithIdx[(idx + 2000) % numsWithIdx.Count].num + diff --git a/2022/21/index.html b/2022/21/index.html index b25f0646..24e6a46c 100644 --- a/2022/21/index.html +++ b/2022/21/index.html @@ -284,15 +284,15 @@

Monkey Math

namespace AdventOfCode.Y2022.Day21; -[ProblemName("Monkey Math")] +[ProblemName("Monkey Math")] class Solution : Solver { public object PartOne(string input) { - return Parse(input, "root", false).Simplify(); + return Parse(input, "root", false).Simplify(); } public object PartTwo(string input) { - var expr = Parse(input, "root", true) as Eq; + var expr = Parse(input, "root", true) as Eq; while (!(expr.left is Var)) { expr = Solve(expr); @@ -300,37 +300,37 @@

Monkey Math

return expr.right; } - // One step in rearranging the equation to = form. + // One step in rearranging the equation to <variable> = <constant> form. // It is supposed that there is only one variable occurrence in the whole // expression tree. - Eq Solve(Eq eq) => + Eq Solve(Eq eq) => eq.left switch { - Op(Const l, "+", Expr r) => new Eq(r, new Op(eq.right, "-", l).Simplify()), - Op(Const l, "*", Expr r) => new Eq(r, new Op(eq.right, "/", l).Simplify()), - Op(Expr l, "+", Expr r) => new Eq(l, new Op(eq.right, "-", r).Simplify()), - Op(Expr l, "-", Expr r) => new Eq(l, new Op(eq.right, "+", r).Simplify()), - Op(Expr l, "*", Expr r) => new Eq(l, new Op(eq.right, "/", r).Simplify()), - Op(Expr l, "/", Expr r) => new Eq(l, new Op(eq.right, "*", r).Simplify()), - Const => new Eq(eq.right, eq.left), - _ => eq + Op(Const l, "+", Expr r) => new Eq(r, new Op(eq.right, "-", l).Simplify()), + Op(Const l, "*", Expr r) => new Eq(r, new Op(eq.right, "/", l).Simplify()), + Op(Expr l, "+", Expr r) => new Eq(l, new Op(eq.right, "-", r).Simplify()), + Op(Expr l, "-", Expr r) => new Eq(l, new Op(eq.right, "+", r).Simplify()), + Op(Expr l, "*", Expr r) => new Eq(l, new Op(eq.right, "/", r).Simplify()), + Op(Expr l, "/", Expr r) => new Eq(l, new Op(eq.right, "*", r).Simplify()), + Const => new Eq(eq.right, eq.left), + _ => eq }; // parses the input including the special rules for part2 // and returns the expression with the specified name Expr Parse(string input, string name, bool part2) { - var context = new Dictionary(); - foreach (var line in input.Split("\n")) { - var parts = line.Split(" "); - context[parts[0].TrimEnd(':')] = parts.Skip(1).ToArray(); + var context = new Dictionary<string, string[]>(); + foreach (var line in input.Split("\n")) { + var parts = line.Split(" "); + context[parts[0].TrimEnd(':')] = parts.Skip(1).ToArray(); } Expr buildExpr(string name) { var parts = context[name]; if (part2) { - if (name == "humn") { - return new Var("humn"); - } else if (name == "root") { + if (name == "humn") { + return new Var("humn"); + } else if (name == "root") { return new Eq(buildExpr(parts[0]), buildExpr(parts[2])); } } @@ -350,29 +350,29 @@

Monkey Math

} record Const(long Value) : Expr { - public override string ToString() => Value.ToString(); - public Expr Simplify() => this; + public override string ToString() => Value.ToString(); + public Expr Simplify() => this; } record Var(string name) : Expr { - public override string ToString() => name; - public Expr Simplify() => this; + public override string ToString() => name; + public Expr Simplify() => this; } record Eq(Expr left, Expr right) : Expr { - public override string ToString() => $"{left} == {right}"; - public Expr Simplify() => new Eq(left.Simplify(), right.Simplify()); + public override string ToString() => $"{left} == {right}"; + public Expr Simplify() => new Eq(left.Simplify(), right.Simplify()); } record Op(Expr left, string op, Expr right) : Expr { - public override string ToString() => $"({left}) {op} ({right})"; + public override string ToString() => $"({left}) {op} ({right})"; public Expr Simplify() { return (left.Simplify(), op, right.Simplify()) switch { - (Const l, "+", Const r) => new Const(l.Value + r.Value), - (Const l, "-", Const r) => new Const(l.Value - r.Value), - (Const l, "*", Const r) => new Const(l.Value * r.Value), - (Const l, "/", Const r) => new Const(l.Value / r.Value), - (Expr l, _, Expr r) => new Op(l, op, r), + (Const l, "+", Const r) => new Const(l.Value + r.Value), + (Const l, "-", Const r) => new Const(l.Value - r.Value), + (Const l, "*", Const r) => new Const(l.Value * r.Value), + (Const l, "/", Const r) => new Const(l.Value / r.Value), + (Expr l, _, Expr r) => new Op(l, op, r), }; } } diff --git a/2022/22/index.html b/2022/22/index.html index c4129f6e..f80cd799 100644 --- a/2022/22/index.html +++ b/2022/22/index.html @@ -285,7 +285,7 @@

Monkey Map

namespace AdventOfCode.Y2022.Day22; -[ProblemName("Monkey Map")] +[ProblemName("Monkey Map")] class Solution : Solver { /* The cube is unfolded like this. Each letter identifies an 50x50 square @@ -295,42 +295,42 @@

Monkey Map

DE F A topology map tells us how cube sides are connected. For example in - case of part 1 the line "A -> B0 C0 B0 E0" means that if we go to the + case of part 1 the line "A -> B0 C0 B0 E0" means that if we go to the right from A we get to B, C is down, moving to the left we find B again, and moving up from A we get to E. The order of directions is always right, down, left and up. The number next to the letter tells us how many 90 degrees we need to rotate the destination square to point upwards. In case of part 1 we - don't need to rotate so the number is always zero. In part 2 there is - "A -> B0 C0 D2 F1" which means that if we are about to move up from A we + don't need to rotate so the number is always zero. In part 2 there is + "A -> B0 C0 D2 F1" which means that if we are about to move up from A we get to F, but F is rotated to the right once, likewise D2 means that D is on the left of A and it is up side down. This mapping was generated from a paper model. */ - public object PartOne(string input) => Solve( + public object PartOne(string input) => Solve( input, - """" - A -> B0 C0 B0 E0 - B -> A0 B0 A0 B0 - C -> C0 E0 C0 A0 - D -> E0 F0 E0 F0 - E -> D0 A0 D0 C0 - F -> F0 D0 F0 D0 - """" + """" + A -> B0 C0 B0 E0 + B -> A0 B0 A0 B0 + C -> C0 E0 C0 A0 + D -> E0 F0 E0 F0 + E -> D0 A0 D0 C0 + F -> F0 D0 F0 D0 + """" ); - public object PartTwo(string input) => Solve( + public object PartTwo(string input) => Solve( input, - """ - A -> B0 C0 D2 F1 - B -> E2 C1 A0 F0 - C -> B3 E0 D3 A0 - D -> E0 F0 A2 C1 - E -> B2 F1 D0 C0 - F -> E3 B0 A3 D0 - """ + """ + A -> B0 C0 D2 F1 + B -> E2 C1 A0 F0 + C -> B3 E0 D3 A0 + D -> E0 F0 A2 C1 + E -> B2 F1 D0 C0 + F -> E3 B0 A3 D0 + """ ); const int blockSize = 50; @@ -341,7 +341,7 @@

Monkey Map

int Solve(string input, string topology) { var (map, cmds) = Parse(input); - var state = new State("A", new Coord(0, 0), right); + var state = new State("A", new Coord(0, 0), right); foreach (var cmd in cmds) { switch (cmd) { @@ -352,10 +352,10 @@

Monkey Map

state = state with { dir = (state.dir + 1) % 4 }; break; case Forward(var n): - for (var i = 0; i < n; i++) { + for (var i = 0; i < n; i++) { var stateNext = Step(topology, state); var global = ToGlobal(stateNext); - if (map[global.irow][global.icol] == '.') { + if (map[global.irow][global.icol] == '.') { state = stateNext; } else { break; @@ -370,44 +370,44 @@

Monkey Map

state.dir; } - Coord ToGlobal(State state) => + Coord ToGlobal(State state) => state.block switch { - "A" => state.coord + new Coord(0, blockSize), - "B" => state.coord + new Coord(0, 2 * blockSize), - "C" => state.coord + new Coord(blockSize, blockSize), - "D" => state.coord + new Coord(2 * blockSize, 0), - "E" => state.coord + new Coord(2 * blockSize, blockSize), - "F" => state.coord + new Coord(3 * blockSize, 0), - _ => throw new Exception() + "A" => state.coord + new Coord(0, blockSize), + "B" => state.coord + new Coord(0, 2 * blockSize), + "C" => state.coord + new Coord(blockSize, blockSize), + "D" => state.coord + new Coord(2 * blockSize, 0), + "E" => state.coord + new Coord(2 * blockSize, blockSize), + "F" => state.coord + new Coord(3 * blockSize, 0), + _ => throw new Exception() }; State Step(string topology, State state) { - bool wrapsAround(Coord coord) => - coord.icol < 0 || coord.icol >= blockSize || - coord.irow < 0 || coord.irow >= blockSize; + bool wrapsAround(Coord coord) => + coord.icol < 0 || coord.icol >= blockSize || + coord.irow < 0 || coord.irow >= blockSize; var (srcBlock, coord, dir) = state; var dstBlock = srcBlock; // take one step, if there is no wrap around we are all right coord = dir switch { - left => coord with { icol = coord.icol - 1 }, - down => coord with { irow = coord.irow + 1 }, - right => coord with { icol = coord.icol + 1 }, - up => coord with { irow = coord.irow - 1 }, - _ => throw new Exception() + left => coord with { icol = coord.icol - 1 }, + down => coord with { irow = coord.irow + 1 }, + right => coord with { icol = coord.icol + 1 }, + up => coord with { irow = coord.irow - 1 }, + _ => throw new Exception() }; if (wrapsAround(coord)) { // check the topology, select the dstBlock and rotate coord and dir // as much as needed this is easier to follow through an example - // if srcBlock: "C", dir: 2 + // if srcBlock: "C", dir: 2 - var line = topology.Split('\n').Single(x => x.StartsWith(srcBlock)); - // line: C -> B3 E0 D3 A0 + var line = topology.Split('\n').Single(x => x.StartsWith(srcBlock)); + // line: C -> B3 E0 D3 A0 - var mapping = line.Split(" -> ")[1].Split(" "); + var mapping = line.Split(" -> ")[1].Split(" "); // mapping: B3 E0 D3 A0 var neighbour = mapping[dir]; @@ -425,7 +425,7 @@

Monkey Map

icol = (coord.icol + blockSize) % blockSize, }; - for (var i = 0; i < rotate; i++) { + for (var i = 0; i < rotate; i++) { coord = coord with { irow = coord.icol, icol = blockSize - coord.irow - 1 @@ -438,16 +438,16 @@

Monkey Map

} (string[] map, Cmd[] path) Parse(string input) { - var blocks = input.Split("\n\n"); + var blocks = input.Split("\n\n"); - var map = blocks[0].Split("\n"); + var map = blocks[0].Split("\n"); var commands = Regex - .Matches(blocks[1], @"(\d+)|L|R") - .Select(m => + .Matches(blocks[1], @"(\d+)|L|R") + .Select<Match, Cmd>(m => m.Value switch { - "L" => new Left(), - "R" => new Right(), - string n => new Forward(int.Parse(n)), + "L" => new Left(), + "R" => new Right(), + string n => new Forward(int.Parse(n)), }) .ToArray(); @@ -457,10 +457,10 @@

Monkey Map

record State(string block, Coord coord, int dir); record Coord(int irow, int icol) { - public static Coord operator +(Coord a, Coord b) => + public static Coord operator +(Coord a, Coord b) => new Coord(a.irow + b.irow, a.icol + b.icol); - public static Coord operator -(Coord a, Coord b) => + public static Coord operator -(Coord a, Coord b) => new Coord(a.irow - b.irow, a.icol - b.icol); } diff --git a/2022/23/index.html b/2022/23/index.html index d5e9a27f..76bb10bd 100644 --- a/2022/23/index.html +++ b/2022/23/index.html @@ -286,28 +286,28 @@

Unstable Diffusion

namespace AdventOfCode.Y2022.Day23; -[ProblemName("Unstable Diffusion")] +[ProblemName("Unstable Diffusion")] class Solution : Solver { // I used complex numbers for a change. The map is represented with a hashset of positions. public object PartOne(string input) - => Simulate(Parse(input)).Select(Area).ElementAt(9); + => Simulate(Parse(input)).Select(Area).ElementAt(9); public object PartTwo(string input) - => Simulate(Parse(input)).Count(); + => Simulate(Parse(input)).Count(); - IEnumerable> Simulate(HashSet elves) { - var lookAround = new Queue(new []{ N, S, W, E }); + IEnumerable<HashSet<Complex>> Simulate(HashSet<Complex> elves) { + var lookAround = new Queue<Complex>(new []{ N, S, W, E }); for (var fixpoint = false; !fixpoint; lookAround.Enqueue(lookAround.Dequeue())) { // 1) collect proposals; for each position (key) compute the list of the elves // who want to step there - var proposals = new Dictionary>(); + var proposals = new Dictionary<Complex, List<Complex>>(); foreach (var elf in elves) { - var lonely = Directions.All(dir => !elves.Contains(elf + dir)); + var lonely = Directions.All(dir => !elves.Contains(elf + dir)); if (lonely) { continue; } @@ -315,11 +315,11 @@

Unstable Diffusion

foreach (var dir in lookAround) { // elf proposes a postion if nobody stands in that direction - var proposes = ExtendDir(dir).All(d => !elves.Contains(elf + d)); + var proposes = ExtendDir(dir).All(d => !elves.Contains(elf + d)); if (proposes) { var pos = elf + dir; if (!proposals.ContainsKey(pos)) { - proposals[pos] = new List(); + proposals[pos] = new List<Complex>(); } proposals[pos].Add(elf); break; @@ -342,23 +342,23 @@

Unstable Diffusion

} } - double Area(HashSet elves) { + double Area(HashSet<Complex> elves) { // smallest enclosing rectangle - var width = elves.Select(p => p.Real).Max() - - elves.Select(p => p.Real).Min() + 1; + var width = elves.Select(p => p.Real).Max() - + elves.Select(p => p.Real).Min() + 1; - var height = elves.Select(p => p.Imaginary).Max() - - elves.Select(p => p.Imaginary).Min() + 1; + var height = elves.Select(p => p.Imaginary).Max() - + elves.Select(p => p.Imaginary).Min() + 1; return width * height - elves.Count; } - HashSet Parse(string input) { - var lines = input.Split("\n"); + HashSet<Complex> Parse(string input) { + var lines = input.Split("\n"); return ( from irow in Enumerable.Range(0, lines.Length) from icol in Enumerable.Range(0, lines[0].Length) - where lines[irow][icol] == '#' + where lines[irow][icol] == '#' select new Complex(icol, irow) ).ToHashSet(); } @@ -377,7 +377,7 @@

Unstable Diffusion

static Complex[] Directions = new[] { NW, N, NE, E, SE, S, SW, W }; // Extends an ordinal position with its intercardinal neighbours - Complex[] ExtendDir(Complex dir) => + Complex[] ExtendDir(Complex dir) => dir == N ? new[] { NW, N, NE } : dir == E ? new[] { NE, E, SE } : dir == S ? new[] { SW, S, SE } : diff --git a/2022/24/index.html b/2022/24/index.html index 0ae503b3..2319c21b 100644 --- a/2022/24/index.html +++ b/2022/24/index.html @@ -284,11 +284,11 @@

Blizzard Basin

namespace AdventOfCode.Y2022.Day24; -[ProblemName("Blizzard Basin")] +[ProblemName("Blizzard Basin")] class Solution : Solver { // We do a standard A* algorithm, the only trick is that - // the 'map' always changes as blizzards move, so our position + // the 'map' always changes as blizzards move, so our position // is now a space time coordinate. // I used an efficent Maps class that can be queried with these. @@ -310,7 +310,7 @@

Blizzard Basin

// Standard A* algorithm Pos WalkTo(Pos start, Pos goal, Maps maps) { - var q = new PriorityQueue(); + var q = new PriorityQueue<Pos, int>(); int f(Pos pos) { // estimate the remaining step count with Manhattan distance @@ -321,11 +321,11 @@

Blizzard Basin

} q.Enqueue(start, f(start)); - HashSet seen = new HashSet(); + HashSet<Pos> seen = new HashSet<Pos>(); - while (q.Count > 0) { + while (q.Count > 0) { var pos = q.Dequeue(); - if (pos.irow == goal.irow && pos.icol == goal.icol) { + if (pos.irow == goal.irow && pos.icol == goal.icol) { return pos; } @@ -341,7 +341,7 @@

Blizzard Basin

} // Increase time, look for free neighbours - IEnumerable NextPositions(Pos pos, Maps maps) { + IEnumerable<Pos> NextPositions(Pos pos, Maps maps) { pos = pos with {time = pos.time + 1}; foreach (var nextPos in new Pos[]{ pos, @@ -350,7 +350,7 @@

Blizzard Basin

pos with {icol=pos.icol -1}, pos with {icol=pos.icol +1}, }) { - if (maps.Get(nextPos) == '.') { + if (maps.Get(nextPos) == '.') { yield return nextPos; } } @@ -370,27 +370,27 @@

Blizzard Basin

public readonly int ccol; public Maps(string input) { - map = input.Split("\n"); + map = input.Split("\n"); this.crow = map.Length; this.ccol = map[0].Length; } public char Get(Pos pos) { - if (pos.irow == 0 && pos.icol == 1) { - return '.'; + if (pos.irow == 0 && pos.icol == 1) { + return '.'; } - if (pos.irow == crow - 1 && pos.icol == ccol - 2) { - return '.'; + if (pos.irow == crow - 1 && pos.icol == ccol - 2) { + return '.'; } - if (pos.irow <= 0 || pos.irow >= crow - 1 || - pos.icol <= 0 || pos.icol >= ccol - 1 + if (pos.irow <= 0 || pos.irow >= crow - 1 || + pos.icol <= 0 || pos.icol >= ccol - 1 ) { - return '#'; + return '#'; } // blizzards have a horizontal and a vertical loop - // it's easy to check the original postions with going back in time + // it's easy to check the original postions with going back in time // using modular arithmetic var hmod = ccol - 2; var vmod = crow - 2; @@ -401,11 +401,11 @@

Blizzard Basin

var icolS = (pos.irow - 1 + vmod + (pos.time % vmod)) % vmod + 1; return - map[pos.irow][icolW] == '>' ? '>': - map[pos.irow][icolE] == '<' ? '<': - map[icolN][pos.icol] == 'v' ? 'v': - map[icolS][pos.icol] == '^' ? '^': - '.'; + map[pos.irow][icolW] == '>' ? '>': + map[pos.irow][icolE] == '<' ? '<': + map[icolN][pos.icol] == 'v' ? 'v': + map[icolS][pos.icol] == '^' ? '^': + '.'; } } } diff --git a/2022/25/index.html b/2022/25/index.html index e4e8e63b..23a1693c 100644 --- a/2022/25/index.html +++ b/2022/25/index.html @@ -284,29 +284,29 @@

Full of Hot Air

namespace AdventOfCode.Y2022.Day25; -[ProblemName("Full of Hot Air")] +[ProblemName("Full of Hot Air")] class Solution : Solver { - public object PartOne(string input) => + public object PartOne(string input) => LongToSnafu( input - .Split("\n") + .Split("\n") .Select(SnafuToLong) .Sum() ); // This is just string to number conversion in base 5 - // with the two special digits that's worth -2 and -1. + // with the two special digits that's worth -2 and -1. long SnafuToLong(string snafu) { long res = 0L; foreach (var digit in snafu) { res = res * 5; switch (digit) { - case '=': res += -2; break; - case '-': res += -1; break; - case '0': res += 0; break; - case '1': res += 1; break; - case '2': res += 2; break; + case '=': res += -2; break; + case '-': res += -1; break; + case '0': res += 0; break; + case '1': res += 1; break; + case '2': res += 2; break; } } return res; @@ -317,16 +317,16 @@

Full of Hot Air

// need to increment the higher decimal place so that we have // something to subtract 2 and 1 from. string LongToSnafu(long d) { - var res = ""; - while (d > 0) { + var res = ""; + while (d > 0) { switch (d % 5) { - case 0: res = '0' + res; break; - case 1: res = '1' + res; break; - case 2: res = '2' + res; break; + case 0: res = '0' + res; break; + case 1: res = '1' + res; break; + case 2: res = '2' + res; break; // add 5 and emit -2 because 3 = 5 -2 - case 3: d+=5; res = '=' + res; break; + case 3: d+=5; res = '=' + res; break; // add 5 and emit -1 because 4 = 5 -1 - case 4: d+=5; res = '-' + res; break; + case 4: d+=5; res = '-' + res; break; } d /= 5; } diff --git a/2022/3/index.html b/2022/3/index.html index bde6824d..49703eba 100644 --- a/2022/3/index.html +++ b/2022/3/index.html @@ -285,34 +285,34 @@

Rucksack Reorganization

namespace AdventOfCode.Y2022.Day03; -[ProblemName("Rucksack Reorganization")] +[ProblemName("Rucksack Reorganization")] class Solution : Solver { - public object PartOne(string input) => - // A line can be divided into two 'compartments' of equal length. We + public object PartOne(string input) => + // A line can be divided into two 'compartments' of equal length. We // need to find the common item (letter) in them, and convert it to a - // number called 'priority'. Do this for each line and sum the + // number called 'priority'. Do this for each line and sum the // priorities. - // We use 'chunk' to split a line in half. - input.Split("\n") - .Select(line => line.Chunk(line.Length/2)) // 🥩 + // We use 'chunk' to split a line in half. + input.Split("\n") + .Select(line => line.Chunk(line.Length/2)) // 🥩 .Select(GetCommonItemPriority) .Sum(); - public object PartTwo(string input) => + public object PartTwo(string input) => // Here we need to find the common item in three consecutive lines, // convert it to priority as before, and sum it up along the whole // input. // This is again conveniently done using the chunk function. - input.Split("\n") + input.Split("\n") .Chunk(3) .Select(GetCommonItemPriority) .Sum(); - private int GetCommonItemPriority(IEnumerable> texts) => ( + private int GetCommonItemPriority(IEnumerable<IEnumerable<char>> texts) => ( from ch in texts.First() - where texts.All(text => text.Contains(ch)) - select ch < 'a' ? ch - 'A' + 27 : ch - 'a' + 1 + where texts.All(text => text.Contains(ch)) + select ch < 'a' ? ch - 'A' + 27 : ch - 'a' + 1 ).First(); } diff --git a/2022/4/index.html b/2022/4/index.html index b57f3a24..5aff6ebe 100644 --- a/2022/4/index.html +++ b/2022/4/index.html @@ -284,22 +284,22 @@

Camp Cleanup

namespace AdventOfCode.Y2022.Day04; -[ProblemName("Camp Cleanup")] +[ProblemName("Camp Cleanup")] class Solution : Solver { // Each line of the input represents two ranges - job done by two elves. // We need to find those lines where the elves did some work twice. - // Part 1 and 2 differs in how we define 'duplicated work'. + // Part 1 and 2 differs in how we define 'duplicated work'. record struct Range(int from, int to); - public object PartOne(string input) => DuplicatedWorkCount(input, Contains); - public object PartTwo(string input) => DuplicatedWorkCount(input, Overlaps); + public object PartOne(string input) => DuplicatedWorkCount(input, Contains); + public object PartTwo(string input) => DuplicatedWorkCount(input, Overlaps); // True if r1 contains r2 [ { } ] - bool Contains(Range r1, Range r2) => r1.from <= r2.from && r2.to <= r1.to; + bool Contains(Range r1, Range r2) => r1.from <= r2.from && r2.to <= r1.to; // True if r1 overlaps r2 { [ } ], the other direction is not checked. - bool Overlaps(Range r1, Range r2) => r1.to >= r2.from && r1.from <= r2.to; + bool Overlaps(Range r1, Range r2) => r1.to >= r2.from && r1.from <= r2.to; // DuplicatedWorkCount parses each input line into ranges and applies // rangeCheck on them to find duplicated work. RangeCheck doesnt have to be @@ -307,18 +307,18 @@

Camp Cleanup

// it twice with the arguments swapped. private int DuplicatedWorkCount( string input, - Func rangeCheck + Func<Range, Range, bool> rangeCheck ) { - // E.g. '36-41,35-40' becomes [Range(36, 41), Range(35, 40)] - var parseRanges = (string line) => - from range in line.Split(',') - let fromTo = range.Split('-').Select(int.Parse) + // E.g. '36-41,35-40' becomes [Range(36, 41), Range(35, 40)] + var parseRanges = (string line) => + from range in line.Split(',') + let fromTo = range.Split('-').Select(int.Parse) select new Range(fromTo.First(), fromTo.Last()); return input - .Split("\n") + .Split("\n") .Select(parseRanges) - .Count(ranges => + .Count(ranges => rangeCheck(ranges.First(), ranges.Last()) || rangeCheck(ranges.Last(), ranges.First()) ); diff --git a/2022/5/index.html b/2022/5/index.html index 9a3ee733..8f3691fd 100644 --- a/2022/5/index.html +++ b/2022/5/index.html @@ -286,36 +286,36 @@

Supply Stacks

namespace AdventOfCode.Y2022.Day05; -[ProblemName("Supply Stacks")] +[ProblemName("Supply Stacks")] class Solution : Solver { - // The input is parsed into some stacks of 'crates', and move operations + // The input is parsed into some stacks of 'crates', and move operations // that is to be applied on them. There is a crane which takes some number // of crates from one stack and puts them on the top of an other stack. // Part one and two differs in how this crane works, which is implemented - // by the two 'crateMover' functions. - record struct Move(int count, Stack source, Stack target); + // by the two 'crateMover' functions. + record struct Move(int count, Stack<char> source, Stack<char> target); - public object PartOne(string input) => MoveCrates(input, CrateMover9000); - public object PartTwo(string input) => MoveCrates(input, CrateMover9001); + public object PartOne(string input) => MoveCrates(input, CrateMover9000); + public object PartTwo(string input) => MoveCrates(input, CrateMover9001); void CrateMover9000(Move move) { - for (var i = 0; i < move.count; i++) { + for (var i = 0; i < move.count; i++) { move.target.Push(move.source.Pop()); } } void CrateMover9001(Move move) { // same as CrateMover9000 but keeps element order - var helper = new Stack(); + var helper = new Stack<char>(); CrateMover9000(move with {target=helper}); CrateMover9000(move with {source=helper}); } - string MoveCrates(string input, Action crateMover) { - var parts = input.Split("\n\n"); + string MoveCrates(string input, Action<Move> crateMover) { + var parts = input.Split("\n\n"); - var stackDefs = parts[0].Split("\n"); + var stackDefs = parts[0].Split("\n"); // [D] // [N] [C] // [Z] [M] [P] @@ -325,25 +325,25 @@

Supply Stacks

var stacks = stackDefs .Last() .Chunk(4) - .Select(_ => new Stack()) + .Select(_ => new Stack<char>()) .ToArray(); // Each input line is processed in 4 character long chunks in bottom up // order. Push the next element into the next stack (note how the chunk - // and the stack is paired up using the zip function). ' ' means no more + // and the stack is paired up using the zip function). ' ' means no more // elements to add, just go to the next chunk. foreach (var line in stackDefs.Reverse().Skip(1)) { foreach (var (stack, item) in stacks.Zip(line.Chunk(4))) { - if (item[1] != ' ') { + if (item[1] != ' ') { stack.Push(item[1]); } } } // now parse the move operations and crateMover on them: - foreach (var line in parts[1].Split("\n")) { - // e.g. "move 6 from 4 to 3" - var m = Regex.Match(line, @"move (.*) from (.*) to (.*)"); + foreach (var line in parts[1].Split("\n")) { + // e.g. "move 6 from 4 to 3" + var m = Regex.Match(line, @"move (.*) from (.*) to (.*)"); var count = int.Parse(m.Groups[1].Value); var from = int.Parse(m.Groups[2].Value) - 1; var to = int.Parse(m.Groups[3].Value) - 1; @@ -355,7 +355,7 @@

Supply Stacks

} // collect the top of each stack: - return string.Join("", stacks.Select(stack => stack.Pop())); + return string.Join("", stacks.Select(stack => stack.Pop())); } } diff --git a/2022/6/index.html b/2022/6/index.html index 0fc1fdc8..63f45eb5 100644 --- a/2022/6/index.html +++ b/2022/6/index.html @@ -284,17 +284,17 @@

Tuning Trouble

namespace AdventOfCode.Y2022.Day06; -[ProblemName("Tuning Trouble")] +[ProblemName("Tuning Trouble")] class Solution : Solver { - public object PartOne(string input) => StartOfBlock(input, 4); - public object PartTwo(string input) => StartOfBlock(input, 14); + public object PartOne(string input) => StartOfBlock(input, 4); + public object PartTwo(string input) => StartOfBlock(input, 14); // Slides a window of length l over the input and finds the first position // where each character is different. Returns the right end of the window. - int StartOfBlock(string input, int l) => + int StartOfBlock(string input, int l) => Enumerable.Range(l, input.Length) - .First(i => input.Substring(i - l, l).ToHashSet().Count == l); + .First(i => input.Substring(i - l, l).ToHashSet().Count == l); }

Please ☆ my repo if you like it!

diff --git a/2022/7/index.html b/2022/7/index.html index f80310f3..1ef95c39 100644 --- a/2022/7/index.html +++ b/2022/7/index.html @@ -285,29 +285,29 @@

No Space Left On Device

namespace AdventOfCode.Y2022.Day07; -[ProblemName("No Space Left On Device")] +[ProblemName("No Space Left On Device")] class Solution : Solver { public object PartOne(string input) { - return GetDirectorySizes(input).Where(size => size < 100000).Sum(); + return GetDirectorySizes(input).Where(size => size < 100000).Sum(); } public object PartTwo(string input) { var directorySizes = GetDirectorySizes(input); var freeSpace = 70000000 - directorySizes.Max(); - return directorySizes.Where(size => size + freeSpace >= 30000000).Min(); + return directorySizes.Where(size => size + freeSpace >= 30000000).Min(); } - private List GetDirectorySizes(string input) { - var path = new Stack(); - var sizes = new Dictionary(); - foreach (var line in input.Split("\n")) { - if (line == "$ cd ..") { + private List<int> GetDirectorySizes(string input) { + var path = new Stack<string>(); + var sizes = new Dictionary<string, int>(); + foreach (var line in input.Split("\n")) { + if (line == "$ cd ..") { path.Pop(); - } else if (line.StartsWith("$ cd")) { - path.Push(string.Join("", path)+line.Split(" ")[2]); - } else if (Regex.Match(line, @"\d+").Success) { - var size = int.Parse(line.Split(" ")[0]); + } else if (line.StartsWith("$ cd")) { + path.Push(string.Join("", path)+line.Split(" ")[2]); + } else if (Regex.Match(line, @"\d+").Success) { + var size = int.Parse(line.Split(" ")[0]); foreach (var dir in path) { sizes[dir] = sizes.GetValueOrDefault(dir) + size; } diff --git a/2022/8/index.html b/2022/8/index.html index fe557e0a..44aa221e 100644 --- a/2022/8/index.html +++ b/2022/8/index.html @@ -284,7 +284,7 @@

Treetop Tree House

namespace AdventOfCode.Y2022.Day08; -[ProblemName("Treetop Tree House")] +[ProblemName("Treetop Tree House")] class Solution : Solver { static Direction Left = new Direction(0, -1); @@ -295,7 +295,7 @@

Treetop Tree House

public object PartOne(string input) { var forest = Parse(input); - return forest.Trees().Count(tree => + return forest.Trees().Count(tree => forest.IsTallest(tree, Left) || forest.IsTallest(tree, Right) || forest.IsTallest(tree, Up) || forest.IsTallest(tree, Down) ); @@ -304,14 +304,14 @@

Treetop Tree House

public object PartTwo(string input) { var forest = Parse(input); - return forest.Trees().Select(tree => + return forest.Trees().Select(tree => forest.ViewDistance(tree, Left) * forest.ViewDistance(tree, Right) * forest.ViewDistance(tree, Up) * forest.ViewDistance(tree, Down) ).Max(); } Forest Parse(string input) { - var items = input.Split("\n"); + var items = input.Split("\n"); var (ccol, crow) = (items[0].Length, items.Length); return new Forest(items, crow, ccol); } @@ -321,24 +321,24 @@

Treetop Tree House

record Tree(int height, int irow, int icol); record Forest(string[] items, int crow, int ccol) { - public IEnumerable Trees() => + public IEnumerable<Tree> Trees() => from irow in Enumerable.Range(0, crow) from icol in Enumerable.Range(0, ccol) select new Tree(items[irow][icol], irow, icol); - public int ViewDistance(Tree tree, Direction dir) => + public int ViewDistance(Tree tree, Direction dir) => IsTallest(tree, dir) ? TreesInDirection(tree, dir).Count() : SmallerTrees(tree, dir).Count() + 1; - public bool IsTallest(Tree tree, Direction dir) => - TreesInDirection(tree, dir).All(treeT => treeT.height < tree.height); + public bool IsTallest(Tree tree, Direction dir) => + TreesInDirection(tree, dir).All(treeT => treeT.height < tree.height); - IEnumerable SmallerTrees(Tree tree, Direction dir) => - TreesInDirection(tree, dir).TakeWhile(treeT => treeT.height < tree.height); + IEnumerable<Tree> SmallerTrees(Tree tree, Direction dir) => + TreesInDirection(tree, dir).TakeWhile(treeT => treeT.height < tree.height); - IEnumerable TreesInDirection(Tree tree, Direction dir) { + IEnumerable<Tree> TreesInDirection(Tree tree, Direction dir) { var (first, irow, icol) = (true, tree.irow, tree.icol); - while (irow >= 0 && irow < crow && icol >= 0 && icol < ccol) { + while (irow >= 0 && irow < crow && icol >= 0 && icol < ccol) { if (!first) { yield return new Tree(height: items[irow][icol], irow: irow, icol: icol); } diff --git a/2022/9/index.html b/2022/9/index.html index 2713196a..0433f3c9 100644 --- a/2022/9/index.html +++ b/2022/9/index.html @@ -285,25 +285,25 @@

Rope Bridge

namespace AdventOfCode.Y2022.Day09; -[ProblemName("Rope Bridge")] +[ProblemName("Rope Bridge")] class Solution : Solver { - public object PartOne(string input) => Tails(input, 2).ToHashSet().Count; - public object PartTwo(string input) => Tails(input, 10).ToHashSet().Count; + public object PartOne(string input) => Tails(input, 2).ToHashSet().Count; + public object PartTwo(string input) => Tails(input, 10).ToHashSet().Count; // simulates a rope with the given length as its head moves // according to the input and returns the position of its // tail knot in each step. - private IEnumerable Tails(string input, int ropeLength) { + private IEnumerable<Knot> Tails(string input, int ropeLength) { var rope = Enumerable.Repeat(new Knot(0, 0), ropeLength).ToArray(); yield return rope.Last(); - foreach (var line in input.Split("\n")) { - var parts = line.Split(' '); + foreach (var line in input.Split("\n")) { + var parts = line.Split(' '); var dir = parts[0]; var dist = int.Parse(parts[1]); - for (var i = 0; i < dist; i++) { + for (var i = 0; i < dist; i++) { MoveHead(rope, dir); yield return rope.Last(); } @@ -316,20 +316,20 @@

Rope Bridge

// of the rope void MoveHead(Knot[] rope, string dir) { rope[0] = dir switch { - "U" => rope[0] with { irow = rope[0].irow - 1 }, - "D" => rope[0] with { irow = rope[0].irow + 1 }, - "L" => rope[0] with { icol = rope[0].icol - 1 }, - "R" => rope[0] with { icol = rope[0].icol + 1 }, - _ => throw new ArgumentException(dir) + "U" => rope[0] with { irow = rope[0].irow - 1 }, + "D" => rope[0] with { irow = rope[0].irow + 1 }, + "L" => rope[0] with { icol = rope[0].icol - 1 }, + "R" => rope[0] with { icol = rope[0].icol + 1 }, + _ => throw new ArgumentException(dir) }; // knots move when become disconnected from the previous // sibling in the rope: - for (var i = 1; i < rope.Length; i++) { + for (var i = 1; i < rope.Length; i++) { var drow = rope[i - 1].irow - rope[i].irow; var dcol = rope[i - 1].icol - rope[i].icol; - if (Math.Abs(drow) > 1 || Math.Abs(dcol) > 1) { + if (Math.Abs(drow) > 1 || Math.Abs(dcol) > 1) { rope[i] = new Knot( rope[i].irow + Math.Sign(drow), rope[i].icol + Math.Sign(dcol) diff --git a/2023/1/index.html b/2023/1/index.html index ed6f6ee7..2fcd66ec 100644 --- a/2023/1/index.html +++ b/2023/1/index.html @@ -289,33 +289,33 @@

Trebuchet?!

using System.Linq; using System.Text.RegularExpressions; -[ProblemName("Trebuchet?!")] +[ProblemName("Trebuchet?!")] class Solution : Solver { - public object PartOne(string input) => - Solve(input, @"\d"); + public object PartOne(string input) => + Solve(input, @"\d"); - public object PartTwo(string input) => - Solve(input, @"\d|one|two|three|four|five|six|seven|eight|nine"); + public object PartTwo(string input) => + Solve(input, @"\d|one|two|three|four|five|six|seven|eight|nine"); - int Solve(string input, string rx) => ( - from line in input.Split("\n") + int Solve(string input, string rx) => ( + from line in input.Split("\n") let first = Regex.Match(line, rx) let last = Regex.Match(line, rx, RegexOptions.RightToLeft) select ParseMatch(first.Value) * 10 + ParseMatch(last.Value) ).Sum(); - int ParseMatch(string st) => st switch { - "one" => 1, - "two" => 2, - "three" => 3, - "four" => 4, - "five" => 5, - "six" => 6, - "seven" => 7, - "eight" => 8, - "nine" => 9, - var d => int.Parse(d) + int ParseMatch(string st) => st switch { + "one" => 1, + "two" => 2, + "three" => 3, + "four" => 4, + "five" => 5, + "six" => 6, + "seven" => 7, + "eight" => 8, + "nine" => 9, + var d => int.Parse(d) }; } diff --git a/2023/10/index.html b/2023/10/index.html index c93dbe3b..b7b025df 100644 --- a/2023/10/index.html +++ b/2023/10/index.html @@ -288,9 +288,9 @@

Pipe Maze

using System.Collections.Generic; using System.Linq; using System.Numerics; -using Map = System.Collections.Generic.Dictionary; +using Map = System.Collections.Generic.Dictionary<System.Numerics.Complex, char>; -[ProblemName("Pipe Maze")] +[ProblemName("Pipe Maze")] class Solution : Solver { static readonly Complex Up = -Complex.ImaginaryOne; static readonly Complex Down = Complex.ImaginaryOne; @@ -298,15 +298,15 @@

Pipe Maze

static readonly Complex Right = Complex.One; static readonly Complex[] Dirs = [Up, Right, Down, Left]; - static readonly Dictionary Exits = new Dictionary{ - {'7', [Left, Down] }, - {'F', [Right, Down]}, - {'L', [Up, Right]}, - {'J', [Up, Left]}, - {'|', [Up, Down]}, - {'-', [Left, Right]}, - {'S', [Up, Down, Left, Right]}, - {'.', []}, + static readonly Dictionary<char, Complex[]> Exits = new Dictionary<char, Complex[]>{ + {'7', [Left, Down] }, + {'F', [Right, Down]}, + {'L', [Up, Right]}, + {'J', [Up, Left]}, + {'|', [Up, Down]}, + {'-', [Left, Right]}, + {'S', [Up, Down, Left, Right]}, + {'.', []}, }; public object PartOne(string input) { @@ -318,34 +318,34 @@

Pipe Maze

public object PartTwo(string input) { var map = ParseMap(input); var loop = LoopPositions(map); - return map.Keys.Count(position => Inside(position, map, loop)); + return map.Keys.Count(position => Inside(position, map, loop)); } - // Returns the positions that make up the loop containing 'S' - HashSet LoopPositions(Map map) { - var position = map.Keys.Single(k => map[k] == 'S'); - var positions = new HashSet(); + // Returns the positions that make up the loop containing 'S' + HashSet<Complex> LoopPositions(Map map) { + var position = map.Keys.Single(k => map[k] == 'S'); + var positions = new HashSet<Complex>(); // pick a direction connected to a neighbour - var dir = Dirs.First(dir => Exits[map[position + dir]].Contains(-dir)); + var dir = Dirs.First(dir => Exits[map[position + dir]].Contains(-dir)); for (; ; ) { positions.Add(position); position += dir; - if (map[position] == 'S') { + if (map[position] == 'S') { break; } - dir = Exits[map[position]].Single(exit => exit != -dir); + dir = Exits[map[position]].Single(exit => exit != -dir); } return positions; } // Check if position is inside the loop using ray casting algorithm - bool Inside(Complex position, Map map, HashSet loop) { + bool Inside(Complex position, Map map, HashSet<Complex> loop) { // Imagine a small elf starting from the top half of a cell and moving // to the left jumping over the pipes it encounters. It needs to jump - // over only 'vertically' oriented pipes leading upwards, since it runs - // in the top of the row. Each jump flips the "inside" variable. + // over only 'vertically' oriented pipes leading upwards, since it runs + // in the top of the row. Each jump flips the "inside" variable. if (loop.Contains(position)) { return false; @@ -354,7 +354,7 @@

Pipe Maze

var inside = false; position += Left; while (map.ContainsKey(position)) { - if (loop.Contains(position) && Exits[map[position]].Contains(Up)) { + if (loop.Contains(position) && Exits[map[position]].Contains(Up)) { inside = !inside; } position += Left; @@ -363,13 +363,13 @@

Pipe Maze

} Map ParseMap(string input) { - var rows = input.Split("\n"); + var rows = input.Split("\n"); return ( from irow in Enumerable.Range(0, rows.Length) from icol in Enumerable.Range(0, rows[0].Length) let pos = new Complex(icol, irow) let cell = rows[irow][icol] - select new KeyValuePair(pos, cell) + select new KeyValuePair<Complex, char>(pos, cell) ).ToDictionary(); } } diff --git a/2023/11/index.html b/2023/11/index.html index 54b64f78..22520224 100644 --- a/2023/11/index.html +++ b/2023/11/index.html @@ -290,19 +290,19 @@

Cosmic Expansion

record Position(int irow, int icol); -[ProblemName("Cosmic Expansion")] +[ProblemName("Cosmic Expansion")] class Solution : Solver { - public object PartOne(string input) => Solve(input, 1); - public object PartTwo(string input) => Solve(input, 999999); + public object PartOne(string input) => Solve(input, 1); + public object PartTwo(string input) => Solve(input, 999999); long Solve(string input, int expansion) { - var map = input.Split("\n"); + var map = input.Split("\n"); - Func isRowEmpty = EmptyRows(map).ToHashSet().Contains; - Func isColEmpty = EmptyCols(map).ToHashSet().Contains; + Func<int, bool> isRowEmpty = EmptyRows(map).ToHashSet().Contains; + Func<int, bool> isColEmpty = EmptyCols(map).ToHashSet().Contains; - var galaxies = FindAll(map, '#'); + var galaxies = FindAll(map, '#'); return ( from g1 in galaxies from g2 in galaxies @@ -312,23 +312,23 @@

Cosmic Expansion

).Sum() / 2; } - long Distance(int i1, int i2, int expansion, Func isEmpty) { + long Distance(int i1, int i2, int expansion, Func<int, bool> isEmpty) { var a = Math.Min(i1, i2); var d = Math.Abs(i1 - i2); return d + expansion * Enumerable.Range(a, d).Count(isEmpty); } - IEnumerable EmptyRows(string[] map) => + IEnumerable<int> EmptyRows(string[] map) => from irow in Enumerable.Range(0, map.Length) - where map[irow].All(ch => ch == '.') + where map[irow].All(ch => ch == '.') select irow; - IEnumerable EmptyCols(string[] map) => + IEnumerable<int> EmptyCols(string[] map) => from icol in Enumerable.Range(0, map[0].Length) - where map.All(row => row[icol] == '.') + where map.All(row => row[icol] == '.') select icol; - IEnumerable FindAll(string[] map, char ch) => + IEnumerable<Position> FindAll(string[] map, char ch) => from irow in Enumerable.Range(0, map.Length) from icol in Enumerable.Range(0, map[0].Length) where map[irow][icol] == ch diff --git a/2023/12/index.html b/2023/12/index.html index 90c10d8b..7bff4b07 100644 --- a/2023/12/index.html +++ b/2023/12/index.html @@ -288,74 +288,74 @@

Hot Springs

using System; using System.Collections.Immutable; using System.Linq; -using Cache = System.Collections.Generic.Dictionary< - (string, System.Collections.Immutable.ImmutableStack), long>; +using Cache = System.Collections.Generic.Dictionary< + (string, System.Collections.Immutable.ImmutableStack<int>), long>; -[ProblemName("Hot Springs")] +[ProblemName("Hot Springs")] class Solution : Solver { - public object PartOne(string input) => Solve(input, 1); - public object PartTwo(string input) => Solve(input, 5); + public object PartOne(string input) => Solve(input, 1); + public object PartTwo(string input) => Solve(input, 5); // After unfolding the input we process it line by line computing the possible // combinations for each. We use memoized recursion to speed up PartTwo. // // The computation is recursive by nature, and goes over the pattern and numbers - // in tandem branching on '?' symbols and consuming as much of dead springs - // as dictated by the next number when a '#' is found. The symbol that follows - // a dead range needs special treatment: it cannot be a '#', and if it was a '?' - // we should consider it as a '.' according to the problem statement. + // in tandem branching on '?' symbols and consuming as much of dead springs + // as dictated by the next number when a '#' is found. The symbol that follows + // a dead range needs special treatment: it cannot be a '#', and if it was a '?' + // we should consider it as a '.' according to the problem statement. // // I like to use immutable datastructures when dealing with problems that - // involves backtracking, it's not immediately obvious from the solution below + // involves backtracking, it's not immediately obvious from the solution below // but using a mutable stack or list would cause a lot of headache. - long Solve(string input, int repeat) => ( - from line in input.Split("\n") - let parts = line.Split(" ") - let pattern = Unfold(parts[0], '?', repeat) - let numString = Unfold(parts[1], ',', repeat) - let nums = numString.Split(',').Select(int.Parse) + long Solve(string input, int repeat) => ( + from line in input.Split("\n") + let parts = line.Split(" ") + let pattern = Unfold(parts[0], '?', repeat) + let numString = Unfold(parts[1], ',', repeat) + let nums = numString.Split(',').Select(int.Parse) select Compute(pattern, ImmutableStack.CreateRange(nums.Reverse()), new Cache()) ).Sum(); - string Unfold(string st, char join, int unfold) => + string Unfold(string st, char join, int unfold) => string.Join(join, Enumerable.Repeat(st, unfold)); - long Compute(string pattern, ImmutableStack nums, Cache cache) { + long Compute(string pattern, ImmutableStack<int> nums, Cache cache) { if (!cache.ContainsKey((pattern, nums))) { cache[(pattern, nums)] = Dispatch(pattern, nums, cache); } return cache[(pattern, nums)]; } - long Dispatch(string pattern, ImmutableStack nums, Cache cache) { + long Dispatch(string pattern, ImmutableStack<int> nums, Cache cache) { return pattern.FirstOrDefault() switch { - '.' => ProcessDot(pattern, nums, cache), - '?' => ProcessQuestion(pattern, nums, cache), - '#' => ProcessHash(pattern, nums, cache), - _ => ProcessEnd(pattern, nums, cache), + '.' => ProcessDot(pattern, nums, cache), + '?' => ProcessQuestion(pattern, nums, cache), + '#' => ProcessHash(pattern, nums, cache), + _ => ProcessEnd(pattern, nums, cache), }; } - long ProcessEnd(string _, ImmutableStack nums, Cache __) { - // no numbers left at the end of pattern -> good + long ProcessEnd(string _, ImmutableStack<int> nums, Cache __) { + // no numbers left at the end of pattern -> good return nums.Any() ? 0 : 1; } - long ProcessDot(string pattern, ImmutableStack nums, Cache cache) { + long ProcessDot(string pattern, ImmutableStack<int> nums, Cache cache) { // consume one spring and recurse return Compute(pattern[1..], nums, cache); } - long ProcessQuestion(string pattern, ImmutableStack nums, Cache cache) { + long ProcessQuestion(string pattern, ImmutableStack<int> nums, Cache cache) { // recurse both ways - return Compute("." + pattern[1..], nums, cache) + - Compute("#" + pattern[1..], nums, cache); + return Compute("." + pattern[1..], nums, cache) + + Compute("#" + pattern[1..], nums, cache); } - long ProcessHash(string pattern, ImmutableStack nums, Cache cache) { + long ProcessHash(string pattern, ImmutableStack<int> nums, Cache cache) { // take the first number and consume that many dead springs, recurse if (!nums.Any()) { @@ -365,14 +365,14 @@

Hot Springs

var n = nums.Peek(); nums = nums.Pop(); - var potentiallyDead = pattern.TakeWhile(s => s == '#' || s == '?').Count(); + var potentiallyDead = pattern.TakeWhile(s => s == '#' || s == '?').Count(); - if (potentiallyDead < n) { + if (potentiallyDead < n) { return 0; // not enough dead springs } else if (pattern.Length == n) { - return Compute("", nums, cache); - } else if (pattern[n] == '#') { - return 0; // dead spring follows the range -> not good + return Compute("", nums, cache); + } else if (pattern[n] == '#') { + return 0; // dead spring follows the range -> not good } else { return Compute(pattern[(n + 1)..], nums, cache); } diff --git a/2023/13/index.html b/2023/13/index.html index 990f3980..3140db8b 100644 --- a/2023/13/index.html +++ b/2023/13/index.html @@ -288,26 +288,26 @@

Point of Incidence

using System.Collections.Generic; using System.Linq; using System.Numerics; -using Map = System.Collections.Generic.Dictionary; +using Map = System.Collections.Generic.Dictionary<System.Numerics.Complex, char>; -[ProblemName("Point of Incidence")] +[ProblemName("Point of Incidence")] class Solution : Solver { Complex Right = 1; Complex Down = Complex.ImaginaryOne; - Complex Ortho(Complex dir) => dir == Right ? Down : Right; + Complex Ortho(Complex dir) => dir == Right ? Down : Right; - public object PartOne(string input) => Solve(input, 0); - public object PartTwo(string input) => Solve(input, 1); + public object PartOne(string input) => Solve(input, 0); + public object PartTwo(string input) => Solve(input, 1); - double Solve(string input, int allowedSmudges) => ( - from block in input.Split("\n\n") + double Solve(string input, int allowedSmudges) => ( + from block in input.Split("\n\n") let map = ParseMap(block) select GetScore(map, allowedSmudges) ).Sum(); // place a mirror along the edges of the map, find the one with the allowed smudges - double GetScore(Map map, int allowedSmudges) => ( + double GetScore(Map map, int allowedSmudges) => ( from dir in new Complex[] { Right, Down } from mirror in Positions(map, dir, dir) where FindSmudges(map, mirror, dir) == allowedSmudges @@ -315,28 +315,28 @@

Point of Incidence

).First(); // cast a ray from each postion along the mirror and count the smudges - int FindSmudges(Map map, Complex mirror, Complex rayDir) => ( + int FindSmudges(Map map, Complex mirror, Complex rayDir) => ( from ray0 in Positions(map, mirror, Ortho(rayDir)) let rayA = Positions(map, ray0, rayDir) let rayB = Positions(map, ray0 - rayDir, -rayDir) - select Enumerable.Zip(rayA, rayB).Count(p => map[p.First] != map[p.Second]) + select Enumerable.Zip(rayA, rayB).Count(p => map[p.First] != map[p.Second]) ).Sum(); - // allowed positions of the map from 'start' going in 'dir' - IEnumerable Positions(Map map, Complex start, Complex dir) { + // allowed positions of the map from 'start' going in 'dir' + IEnumerable<Complex> Positions(Map map, Complex start, Complex dir) { for (var pos = start; map.ContainsKey(pos); pos += dir) { yield return pos; } } Map ParseMap(string input) { - var rows = input.Split("\n"); + var rows = input.Split("\n"); return ( from irow in Enumerable.Range(0, rows.Length) from icol in Enumerable.Range(0, rows[0].Length) let pos = new Complex(icol, irow) let cell = rows[irow][icol] - select new KeyValuePair(pos, cell) + select new KeyValuePair<Complex, char>(pos, cell) ).ToDictionary(); } } diff --git a/2023/14/index.html b/2023/14/index.html index 46eeaf65..2bd53ed1 100644 --- a/2023/14/index.html +++ b/2023/14/index.html @@ -290,33 +290,33 @@

Parabolic Reflector Dish

using System.Linq; using Map = char[][]; -[ProblemName("Parabolic Reflector Dish")] +[ProblemName("Parabolic Reflector Dish")] class Solution : Solver { - public object PartOne(string input) => + public object PartOne(string input) => Measure(Tilt(Parse(input))); - public object PartTwo(string input) => + public object PartTwo(string input) => Measure(Iterate(Parse(input), Cycle, 1_000_000_000)); - Map Parse(string input) => ( - from l in input.Split('\n') select l.ToCharArray() + Map Parse(string input) => ( + from l in input.Split('\n') select l.ToCharArray() ).ToArray(); - int Crow(char[][] map) => map.Length; - int Ccol(char[][] map) => map[0].Length; + int Crow(char[][] map) => map.Length; + int Ccol(char[][] map) => map[0].Length; - Map Iterate(Map map, Func cycle, int count) { + Map Iterate(Map map, Func<Map, Map> cycle, int count) { // The usual trick: keep iterating until we find a loop, make a shortcut // and read the result from the accumulated history. - var history = new List(); - while (count > 0) { + var history = new List<string>(); + while (count > 0) { map = cycle(map); count--; - var mapString = string.Join("\n", map.Select(l=> new string(l))); + var mapString = string.Join("\n", map.Select(l=> new string(l))); var idx = history.IndexOf(mapString); - if (idx < 0) { + if (idx < 0) { history.Add(mapString); } else { var loopLength = history.Count - idx; @@ -328,22 +328,22 @@

Parabolic Reflector Dish

} Map Cycle(Map map) { - for (var i = 0; i < 4; i++) { + for (var i = 0; i < 4; i++) { map = Rotate(Tilt(map)); } return map; } - // Tilt the map to the North, so that the 'O' tiles roll to the top. + // Tilt the map to the North, so that the 'O' tiles roll to the top. Map Tilt(Map map) { - for (var icol = 0; icol < Ccol(map); icol++) { - var irowT = 0; // tells where to roll up the next 'O' tile - for (var irowS = 0; irowS < Crow(map); irowS++) { - if (map[irowS][icol] == '#') { + for (var icol = 0; icol < Ccol(map); icol++) { + var irowT = 0; // tells where to roll up the next 'O' tile + for (var irowS = 0; irowS < Crow(map); irowS++) { + if (map[irowS][icol] == '#') { irowT = irowS + 1; - } else if (map[irowS][icol] == 'O') { - map[irowS][icol] = '.'; - map[irowT][icol] = 'O'; + } else if (map[irowS][icol] == 'O') { + map[irowS][icol] = '.'; + map[irowT][icol] = 'O'; irowT++; } } @@ -354,19 +354,19 @@

Parabolic Reflector Dish

// Ugly coordinate magic, turns the map 90º clockwise Map Rotate(Map src) { var dst = new char[Crow(src)][]; - for (var irow = 0; irow < Ccol(src); irow++) { + for (var irow = 0; irow < Ccol(src); irow++) { dst[irow] = new char[Ccol(src)]; - for (var icol = 0; icol < Crow(src); icol++) { + for (var icol = 0; icol < Crow(src); icol++) { dst[irow][icol] = src[Crow(src) - icol - 1][irow]; } } return dst; } - // returns the cummulated distances of 'O' tiles from the bottom of the map - int Measure(Map map) => - map.Select((row, irow) => - (Crow(map) - irow) * row.Count(ch => ch == 'O') + // returns the cummulated distances of 'O' tiles from the bottom of the map + int Measure(Map map) => + map.Select((row, irow) => + (Crow(map) - irow) * row.Count(ch => ch == 'O') ).Sum(); }

Please ☆ my repo if you like it!

diff --git a/2023/15/index.html b/2023/15/index.html index 97945180..32d6f0bf 100644 --- a/2023/15/index.html +++ b/2023/15/index.html @@ -291,49 +291,49 @@

Lens Library

using System.Collections.Generic; using System.Linq; -using Boxes = System.Collections.Generic.List[]; +using Boxes = System.Collections.Generic.List<Lens>[]; record Lens(string label, int focalLength); record Step(string label, int? focalLength); -[ProblemName("Lens Library")] +[ProblemName("Lens Library")] class Solution : Solver { - public object PartOne(string input) => input.Split(',').Select(Hash).Sum(); + public object PartOne(string input) => input.Split(',').Select(Hash).Sum(); - // "funcionally imperative of imperatively functional", only for 🎄 - public object PartTwo(string input) => + // "funcionally imperative of imperatively functional", only for 🎄 + public object PartTwo(string input) => ParseSteps(input).Aggregate(MakeBoxes(256), UpdateBoxes, GetFocusingPower); Boxes UpdateBoxes(Boxes boxes, Step step) { var box = boxes[Hash(step.label)]; - var ilens = box.FindIndex(lens => lens.label == step.label); + var ilens = box.FindIndex(lens => lens.label == step.label); - if (!step.focalLength.HasValue && ilens >= 0) { + if (!step.focalLength.HasValue && ilens >= 0) { box.RemoveAt(ilens); - } else if (step.focalLength.HasValue && ilens >= 0) { + } else if (step.focalLength.HasValue && ilens >= 0) { box[ilens] = new Lens(step.label, step.focalLength.Value); - } else if (step.focalLength.HasValue && ilens < 0) { + } else if (step.focalLength.HasValue && ilens < 0) { box.Add(new Lens(step.label, step.focalLength.Value)); } return boxes; } - IEnumerable ParseSteps(string input) => - from item in input.Split(',') - let parts = item.Split('-', '=') - select new Step(parts[0], parts[1] == "" ? null : int.Parse(parts[1])); + IEnumerable<Step> ParseSteps(string input) => + from item in input.Split(',') + let parts = item.Split('-', '=') + select new Step(parts[0], parts[1] == "" ? null : int.Parse(parts[1])); - Boxes MakeBoxes(int count) => - Enumerable.Range(0, count).Select(_ => new List()).ToArray(); + Boxes MakeBoxes(int count) => + Enumerable.Range(0, count).Select(_ => new List<Lens>()).ToArray(); - int GetFocusingPower(Boxes boxes) => ( + int GetFocusingPower(Boxes boxes) => ( from ibox in Enumerable.Range(0, boxes.Length) from ilens in Enumerable.Range(0, boxes[ibox].Count) select (ibox + 1) * (ilens + 1) * boxes[ibox][ilens].focalLength ).Sum(); - int Hash(string st) => st.Aggregate(0, (ch, a) => (ch + a) * 17 % 256); + int Hash(string st) => st.Aggregate(0, (ch, a) => (ch + a) * 17 % 256); }

Please ☆ my repo if you like it!

diff --git a/2023/16/index.html b/2023/16/index.html index 94a94ea4..673a8139 100644 --- a/2023/16/index.html +++ b/2023/16/index.html @@ -291,10 +291,10 @@

The Floor Will Be Lava

using System.Collections.Generic; using System.Linq; using System.Numerics; -using Map = System.Collections.Generic.Dictionary; +using Map = System.Collections.Generic.Dictionary<System.Numerics.Complex, char>; using Beam = (System.Numerics.Complex pos, System.Numerics.Complex dir); -[ProblemName("The Floor Will Be Lava")] +[ProblemName("The Floor Will Be Lava")] class Solution : Solver { static readonly Complex Up = -Complex.ImaginaryOne; @@ -302,7 +302,7 @@

The Floor Will Be Lava

static readonly Complex Left = -Complex.One; static readonly Complex Right = Complex.One; - public object PartOne(string input) => + public object PartOne(string input) => EnergizedCells(ParseMap(input), (Complex.Zero, Right)); public object PartTwo(string input) { @@ -314,26 +314,26 @@

The Floor Will Be Lava

int EnergizedCells(Map map, Beam beam) { // this is essentially just a flood fill algorithm. - var q = new Queue([beam]); - var seen = new HashSet(); + var q = new Queue<Beam>([beam]); + var seen = new HashSet<Beam>(); while (q.TryDequeue(out beam)) { seen.Add(beam); foreach (var dir in Exits(map[beam.pos], beam.dir)) { var pos = beam.pos + dir; - if (map.ContainsKey(pos) && !seen.Contains((pos, dir))) { + if (map.ContainsKey(pos) && !seen.Contains((pos, dir))) { q.Enqueue((pos, dir)); } } } - return seen.Select(beam => beam.pos).Distinct().Count(); + return seen.Select(beam => beam.pos).Distinct().Count(); } // go around the edges (top, right, bottom, left order) of the map // and return the inward pointing directions - IEnumerable StartBeams(Map map) { - var br = map.Keys.MaxBy(pos => pos.Imaginary + pos.Real); + IEnumerable<Beam> StartBeams(Map map) { + var br = map.Keys.MaxBy(pos => pos.Imaginary + pos.Real); return [ ..from pos in map.Keys where pos.Real == 0 select (pos, Down), ..from pos in map.Keys where pos.Real == br.Real select (pos, Left), @@ -344,24 +344,24 @@

The Floor Will Be Lava

// using a dictionary helps with bounds check (simply containskey): Map ParseMap(string input) { - var lines = input.Split('\n'); + var lines = input.Split('\n'); return ( from irow in Enumerable.Range(0, lines.Length) from icol in Enumerable.Range(0, lines[0].Length) let cell = lines[irow][icol] let pos = new Complex(icol, irow) - select new KeyValuePair(pos, cell) + select new KeyValuePair<Complex, char>(pos, cell) ).ToDictionary(); } - // the 'exit' direction(s) of the given cell when entered by a beam moving in 'dir' + // the 'exit' direction(s) of the given cell when entered by a beam moving in 'dir' // we have some special cases for mirrors and spliters, the rest keeps the direction - Complex[] Exits(char cell, Complex dir) => cell switch { - '-' when dir == Up || dir == Down => [Left, Right], - '|' when dir == Left || dir == Right => [Up, Down], - '/' => [-new Complex(dir.Imaginary, dir.Real)], - '\\' => [new Complex(dir.Imaginary, dir.Real)], - _ => [dir] + Complex[] Exits(char cell, Complex dir) => cell switch { + '-' when dir == Up || dir == Down => [Left, Right], + '|' when dir == Left || dir == Right => [Up, Down], + '/' => [-new Complex(dir.Imaginary, dir.Real)], + '\\' => [new Complex(dir.Imaginary, dir.Real)], + _ => [dir] }; }

Please ☆ my repo if you like it!

diff --git a/2023/17/index.html b/2023/17/index.html index a5360cfc..b11ea154 100644 --- a/2023/17/index.html +++ b/2023/17/index.html @@ -291,34 +291,34 @@

Clumsy Crucible

using System.Collections.Generic; using System.Linq; using System.Numerics; -using Map = System.Collections.Generic.Dictionary; +using Map = System.Collections.Generic.Dictionary<System.Numerics.Complex, int>; record Crucible(Complex pos, Complex dir, int straight); -[ProblemName("Clumsy Crucible")] +[ProblemName("Clumsy Crucible")] class Solution : Solver { - public object PartOne(string input) => Heatloss(input, 0, 3); - public object PartTwo(string input) => Heatloss(input, 4, 10); + public object PartOne(string input) => Heatloss(input, 0, 3); + public object PartTwo(string input) => Heatloss(input, 4, 10); // Graph search using a priority queue. We can simply store the heatloss in // the priority. int Heatloss(string input, int minStraight, int maxStraight) { var map = ParseMap(input); - var goal = map.Keys.MaxBy(pos => pos.Imaginary + pos.Real); - var q = new PriorityQueue(); + var goal = map.Keys.MaxBy(pos => pos.Imaginary + pos.Real); + var q = new PriorityQueue<Crucible, int>(); // initial direction: right or down q.Enqueue(new Crucible(pos: 0, dir: 1, straight: 0), 0); q.Enqueue(new Crucible(pos: 0, dir: Complex.ImaginaryOne, straight: 0), 0); - var seen = new HashSet(); + var seen = new HashSet<Crucible>(); while (q.TryDequeue(out var crucible, out var heatloss)) { - if (crucible.pos == goal && crucible.straight >= minStraight) { + if (crucible.pos == goal && crucible.straight >= minStraight) { return heatloss; } foreach (var next in Moves(crucible, minStraight, maxStraight)) { - if (map.ContainsKey(next.pos) && !seen.Contains(next)) { + if (map.ContainsKey(next.pos) && !seen.Contains(next)) { seen.Add(next); q.Enqueue(next, heatloss + map[next.pos]); } @@ -328,15 +328,15 @@

Clumsy Crucible

} // returns possible next states based on the rules - IEnumerable Moves(Crucible c, int minStraight, int maxStraight) { - if (c.straight < maxStraight) { + IEnumerable<Crucible> Moves(Crucible c, int minStraight, int maxStraight) { + if (c.straight < maxStraight) { yield return c with { pos = c.pos + c.dir, straight = c.straight + 1 }; } - if (c.straight >= minStraight) { + if (c.straight >= minStraight) { var dir = c.dir * Complex.ImaginaryOne; yield return new Crucible(c.pos + dir, dir, 1); yield return new Crucible(c.pos - dir, -dir, 1); @@ -345,13 +345,13 @@

Clumsy Crucible

// using a dictionary helps with bounds check (simply containskey): Map ParseMap(string input) { - var lines = input.Split('\n'); + var lines = input.Split('\n'); return ( from irow in Enumerable.Range(0, lines.Length) from icol in Enumerable.Range(0, lines[0].Length) let cell = int.Parse(lines[irow].Substring(icol, 1)) let pos = new Complex(icol, irow) - select new KeyValuePair(pos, cell) + select new KeyValuePair<Complex, int>(pos, cell) ).ToDictionary(); } } diff --git a/2023/18/index.html b/2023/18/index.html index c2483d71..a6b11080 100644 --- a/2023/18/index.html +++ b/2023/18/index.html @@ -300,40 +300,40 @@

Lavaduct Lagoon

using System.Linq; using System.Numerics; -[ProblemName("Lavaduct Lagoon")] +[ProblemName("Lavaduct Lagoon")] class Solution : Solver { - public object PartOne(string input) => Area(Steps1(input)); - public object PartTwo(string input) => Area(Steps2(input)); + public object PartOne(string input) => Area(Steps1(input)); + public object PartTwo(string input) => Area(Steps2(input)); - IEnumerable Steps1(string input) => - from line in input.Split('\n') - let parts = line.Split(' ') + IEnumerable<Complex> Steps1(string input) => + from line in input.Split('\n') + let parts = line.Split(' ') let dir = parts[0] switch { - "R" => Complex.One, - "U" => -Complex.ImaginaryOne, - "L" => -Complex.One, - "D" => Complex.ImaginaryOne, - _ => throw new Exception() + "R" => Complex.One, + "U" => -Complex.ImaginaryOne, + "L" => -Complex.One, + "D" => Complex.ImaginaryOne, + _ => throw new Exception() } let dist = int.Parse(parts[1]) select dir * dist; - IEnumerable Steps2(string input) => - from line in input.Split('\n') - let hex = line.Split(' ')[2] + IEnumerable<Complex> Steps2(string input) => + from line in input.Split('\n') + let hex = line.Split(' ')[2] let dir = hex[7] switch { - '0' => Complex.One, - '1' => -Complex.ImaginaryOne, - '2' => -Complex.One, - '3' => Complex.ImaginaryOne, - _ => throw new Exception() + '0' => Complex.One, + '1' => -Complex.ImaginaryOne, + '2' => -Complex.One, + '3' => Complex.ImaginaryOne, + _ => throw new Exception() } let dist = Convert.ToInt32(hex[2..7], 16) select dir * dist; - // We are using a combination of the shoelace formula with Pick's theorem - double Area(IEnumerable steps) { + // We are using a combination of the shoelace formula with Pick's theorem + double Area(IEnumerable<Complex> steps) { var vertices = Vertices(steps).ToList(); // Shoelace formula https://en.wikipedia.org/wiki/Shoelace_formula @@ -345,15 +345,15 @@

Lavaduct Lagoon

select p1.Real * p2.Imaginary - p1.Imaginary * p2.Real; var area = Math.Abs(shoelaces.Sum()) / 2; - // Pick's theorem https://en.wikipedia.org/wiki/Pick%27s_theorem - var boundary = steps.Select(x => x.Magnitude).Sum(); + // Pick's theorem https://en.wikipedia.org/wiki/Pick%27s_theorem + var boundary = steps.Select(x => x.Magnitude).Sum(); var interior = area - boundary / 2 + 1; // Integer area return boundary + interior; } - IEnumerable Vertices(IEnumerable steps) { + IEnumerable<Complex> Vertices(IEnumerable<Complex> steps) { var pos = Complex.Zero; foreach (var step in steps) { pos += step; diff --git a/2023/19/index.html b/2023/19/index.html index dab45c30..ba1980ae 100644 --- a/2023/19/index.html +++ b/2023/19/index.html @@ -304,65 +304,65 @@

Aplenty

using System.Linq; using System.Text.RegularExpressions; using System.Numerics; -using Rules = System.Collections.Generic.Dictionary; -using Cube = System.Collections.Immutable.ImmutableArray; +using Rules = System.Collections.Generic.Dictionary<string, string>; +using Cube = System.Collections.Immutable.ImmutableArray<Range>; record Range(int begin, int end); record Cond(int dim, char op, int num, string state); -[ProblemName("Aplenty")] +[ProblemName("Aplenty")] class Solution : Solver { // Part 1 can be understood in the context of Part 2. Part 2 asks to compute // the accepted volume of a four dimensional hypercube. It has some elaborate // way to slice up the cube parallel to its edges to smaller and smaller pieces // and decide if the final sub-sub cubes are accepted or not. Our Part 2 - // algorithm follows these rules and returns the 'accepted'volume we are + // algorithm follows these rules and returns the 'accepted'volume we are // looking for. // We can use this algorithm to solve Part 1 starting from unit sized cubes // and checking if they are fully accepted or not. public object PartOne(string input) { - var parts = input.Split("\n\n"); + var parts = input.Split("\n\n"); var rules = ParseRules(parts[0]); return ( from cube in ParseUnitCube(parts[1]) where AcceptedVolume(rules, cube) == 1 - select cube.Select(r => r.begin).Sum() + select cube.Select(r => r.begin).Sum() ).Sum(); } public object PartTwo(string input) { - var parts = input.Split("\n\n"); + var parts = input.Split("\n\n"); var rules = ParseRules(parts[0]); var cube = Enumerable.Repeat(new Range(1, 4000), 4).ToImmutableArray(); return AcceptedVolume(rules, cube); } BigInteger AcceptedVolume(Rules rules, Cube cube) { - var q = new Queue<(Cube cube, string state)>(); - q.Enqueue((cube, "in")); + var q = new Queue<(Cube cube, string state)>(); + q.Enqueue((cube, "in")); BigInteger res = 0; while (q.Any()) { (cube, var state) = q.Dequeue(); - if (cube.Any(coord => coord.end < coord.begin)) { + if (cube.Any(coord => coord.end < coord.begin)) { continue; // cube is empty - } else if (state == "R") { + } else if (state == "R") { continue; // cube is rejected - } else if (state == "A") { + } else if (state == "A") { res += Volume(cube); // cube is accepted } else { - foreach (var stm in rules[state].Split(",")) { + foreach (var stm in rules[state].Split(",")) { Cond cond = TryParseCond(stm); if (cond == null) { q.Enqueue((cube, stm)); - } else if (cond.op == '<') { + } else if (cond.op == '<') { var (cube1, cube2) = CutCube(cube, cond.dim, cond.num - 1); q.Enqueue((cube1, cond.state)); cube = cube2; - } else if (cond?.op == '>') { + } else if (cond?.op == '>') { var (cube1, cube2) = CutCube(cube, cond.dim, cond.num); cube = cube1; q.Enqueue((cube2, cond.state)); @@ -373,8 +373,8 @@

Aplenty

return res; } - BigInteger Volume(Cube cube) => - cube.Aggregate(BigInteger.One, (m, r) => m * (r.end - r.begin + 1)); + BigInteger Volume(Cube cube) => + cube.Aggregate(BigInteger.One, (m, r) => m * (r.end - r.begin + 1)); // Cuts a cube along the specified dimension, other dimensions are unaffected. (Cube lo, Cube hi) CutCube(Cube cube, int dim, int num) { @@ -385,25 +385,25 @@

Aplenty

); } - Cond TryParseCond(string st) => - st.Split('<', '>', ':') switch { - ["x", var num, var state] => new Cond(0, st[1], int.Parse(num), state), - ["m", var num, var state] => new Cond(1, st[1], int.Parse(num), state), - ["a", var num, var state] => new Cond(2, st[1], int.Parse(num), state), - ["s", var num, var state] => new Cond(3, st[1], int.Parse(num), state), - _ => null + Cond TryParseCond(string st) => + st.Split('<', '>', ':') switch { + ["x", var num, var state] => new Cond(0, st[1], int.Parse(num), state), + ["m", var num, var state] => new Cond(1, st[1], int.Parse(num), state), + ["a", var num, var state] => new Cond(2, st[1], int.Parse(num), state), + ["s", var num, var state] => new Cond(3, st[1], int.Parse(num), state), + _ => null }; - Rules ParseRules(string input) => ( - from line in input.Split('\n') - let parts = line.Split('{', '}') - select new KeyValuePair(parts[0], parts[1]) + Rules ParseRules(string input) => ( + from line in input.Split('\n') + let parts = line.Split('{', '}') + select new KeyValuePair<string, string>(parts[0], parts[1]) ).ToDictionary(); - IEnumerable ParseUnitCube(string input) => - from line in input.Split('\n') - let nums = Regex.Matches(line, @"\d+").Select(m => int.Parse(m.Value)) - select nums.Select(n => new Range(n, n)).ToImmutableArray(); + IEnumerable<Cube> ParseUnitCube(string input) => + from line in input.Split('\n') + let nums = Regex.Matches(line, @"\d+").Select(m => int.Parse(m.Value)) + select nums.Select(n => new Range(n, n)).ToImmutableArray(); }

Please ☆ my repo if you like it!

diff --git a/2023/2/index.html b/2023/2/index.html index 9ef83648..7aaa1ffe 100644 --- a/2023/2/index.html +++ b/2023/2/index.html @@ -287,34 +287,34 @@

Cube Conundrum

record Game(int id, int red, int green, int blue); -[ProblemName("Cube Conundrum")] +[ProblemName("Cube Conundrum")] class Solution : Solver { - public object PartOne(string input) => ( - from line in input.Split("\n") + public object PartOne(string input) => ( + from line in input.Split("\n") let game = ParseGame(line) - where game.red <= 12 && game.green <= 13 && game.blue <= 14 + where game.red <= 12 && game.green <= 13 && game.blue <= 14 select game.id ).Sum(); - public object PartTwo(string input) => ( - from line in input.Split("\n") + public object PartTwo(string input) => ( + from line in input.Split("\n") let game = ParseGame(line) select game.red * game.green * game.blue ).Sum(); // no need to keep track of the individual rounds in a game, just return // the maximum of the red, green, blue boxes - Game ParseGame(string line) => + Game ParseGame(string line) => new Game( - ParseInts(line, @"Game (\d+)").First(), - ParseInts(line, @"(\d+) red").Max(), - ParseInts(line, @"(\d+) green").Max(), - ParseInts(line, @"(\d+) blue").Max() + ParseInts(line, @"Game (\d+)").First(), + ParseInts(line, @"(\d+) red").Max(), + ParseInts(line, @"(\d+) green").Max(), + ParseInts(line, @"(\d+) blue").Max() ); // extracts integers from a string identified by a single regex group. - IEnumerable ParseInts(string st, string rx) => + IEnumerable<int> ParseInts(string st, string rx) => from m in Regex.Matches(st, rx) select int.Parse(m.Groups[1].Value); } diff --git a/2023/20/index.html b/2023/20/index.html index c4ec01a5..3bada7c6 100644 --- a/2023/20/index.html +++ b/2023/20/index.html @@ -301,9 +301,9 @@

Pulse Propagation

using System.Text.RegularExpressions; using Signal = (string sender, string receiver, bool value); -record Gate(string[] inputs, Func> handle); +record Gate(string[] inputs, Func<Signal, IEnumerable<Signal>> handle); -[ProblemName("Pulse Propagation")] +[ProblemName("Pulse Propagation")] class Solution : Solver { public object PartOne(string input) { @@ -313,7 +313,7 @@

Pulse Propagation

from signal in Trigger(gates) select signal.value ).ToArray(); - return values.Count(v => v) * values.Count(v => !v); + return values.Count(v => v) * values.Count(v => !v); } public object PartTwo(string input) { @@ -322,16 +322,16 @@

Pulse Propagation

// The nand gate is connected into rx. I checked that the substructures // work in a loop, that has prime length. Just need to multiply them all. var gates = ParseGates(input); - var nand = gates["rx"].inputs.Single(); + var nand = gates["rx"].inputs.Single(); var branches = gates[nand].inputs; - return branches.Aggregate(1L, (m, branch) => m * LoopLength(input, branch)); + return branches.Aggregate(1L, (m, branch) => m * LoopLength(input, branch)); } int LoopLength(string input, string output) { var gates = ParseGates(input); for (var i = 1; ; i++) { var signals = Trigger(gates); - if (signals.Any(s => s.sender == output && s.value)) { + if (signals.Any(s => s.sender == output && s.value)) { return i; } } @@ -339,9 +339,9 @@

Pulse Propagation

// emits a button press, executes until things settle down and returns // all signals for investigation. - IEnumerable Trigger(Dictionary gates) { - var q = new Queue(); - q.Enqueue(new Signal("button", "broadcaster", false)); + IEnumerable<Signal> Trigger(Dictionary<string, Gate> gates) { + var q = new Queue<Signal>(); + q.Enqueue(new Signal("button", "broadcaster", false)); while (q.TryDequeue(out var signal)) { yield return signal; @@ -353,46 +353,46 @@

Pulse Propagation

} } - Dictionary ParseGates(string input) { - input += "\nrx ->"; // an extra rule for rx with no output + Dictionary<string, Gate> ParseGates(string input) { + input += "\nrx ->"; // an extra rule for rx with no output var descriptions = - from line in input.Split('\n') - let words = Regex.Matches(line, "\\w+").Select(m => m.Value).ToArray() + from line in input.Split('\n') + let words = Regex.Matches(line, "\\w+").Select(m => m.Value).ToArray() select (kind: line[0], name: words.First(), outputs: words[1..]); - var inputs = (string name) => ( + var inputs = (string name) => ( from d in descriptions where d.outputs.Contains(name) select d.name ).ToArray(); return descriptions.ToDictionary( - d => d.name, - d => d.kind switch { - '&' => NandGate(d.name, inputs(d.name), d.outputs), - '%' => FlipFlop(d.name, inputs(d.name), d.outputs), - _ => Repeater(d.name, inputs(d.name), d.outputs) + d => d.name, + d => d.kind switch { + '&' => NandGate(d.name, inputs(d.name), d.outputs), + '%' => FlipFlop(d.name, inputs(d.name), d.outputs), + _ => Repeater(d.name, inputs(d.name), d.outputs) } ); } Gate NandGate(string name, string[] inputs, string[] outputs) { // initially assign low value for each input: - var state = inputs.ToDictionary(input => input, _ => false); + var state = inputs.ToDictionary(input => input, _ => false); - return new Gate(inputs, (Signal signal) => { + return new Gate(inputs, (Signal signal) => { state[signal.sender] = signal.value; - var value = !state.Values.All(b => b); - return outputs.Select(o => new Signal(name, o, value)); + var value = !state.Values.All(b => b); + return outputs.Select(o => new Signal(name, o, value)); }); } Gate FlipFlop(string name, string[] inputs, string[] outputs) { var state = false; - return new Gate(inputs, (Signal signal) => { + return new Gate(inputs, (Signal signal) => { if (!signal.value) { state = !state; - return outputs.Select(o => new Signal(name, o, state)); + return outputs.Select(o => new Signal(name, o, state)); } else { return []; } @@ -400,7 +400,7 @@

Pulse Propagation

} Gate Repeater(string name, string[] inputs, string[] outputs) { - return new Gate(inputs, (Signal s) => + return new Gate(inputs, (Signal s) => from o in outputs select new Signal(name, o, s.value) ); } diff --git a/2023/21/index.html b/2023/21/index.html index 24a7a4db..c07f3359 100644 --- a/2023/21/index.html +++ b/2023/21/index.html @@ -319,10 +319,10 @@

Step Counter

using System.Linq; using System.Numerics; -[ProblemName("Step Counter")] +[ProblemName("Step Counter")] class Solution : Solver { - public object PartOne(string input) => Steps(ParseMap(input)).ElementAt(64); + public object PartOne(string input) => Steps(ParseMap(input)).ElementAt(64); public object PartTwo(string input) { // Exploiting some nice properties of the input it reduces to quadratic // interpolation over 3 points: k * 131 + 65 for k = 0, 1, 2 @@ -342,18 +342,18 @@

Step Counter

} // walks around and returns the number of available positions at each step - IEnumerable Steps(HashSet map) { - var positions = new HashSet { new Complex(65, 65) }; + IEnumerable<long> Steps(HashSet<Complex> map) { + var positions = new HashSet<Complex> { new Complex(65, 65) }; while(true) { yield return positions.Count; positions = Step(map, positions); } } - HashSet Step(HashSet map, HashSet positions) { + HashSet<Complex> Step(HashSet<Complex> map, HashSet<Complex> positions) { Complex[] dirs = [1, -1, Complex.ImaginaryOne, -Complex.ImaginaryOne]; - var res = new HashSet(); + var res = new HashSet<Complex>(); foreach (var pos in positions) { foreach (var dir in dirs) { var posT = pos + dir; @@ -368,14 +368,14 @@

Step Counter

} // the double % takes care of negative numbers - double Mod(double n, int m) => ((n % m) + m) % m; + double Mod(double n, int m) => ((n % m) + m) % m; - HashSet ParseMap(string input) { - var lines = input.Split("\n"); + HashSet<Complex> ParseMap(string input) { + var lines = input.Split("\n"); return ( from irow in Enumerable.Range(0, lines.Length) from icol in Enumerable.Range(0, lines[0].Length) - where lines[irow][icol] != '#' + where lines[irow][icol] != '#' select new Complex(icol, irow) ).ToHashSet(); } diff --git a/2023/22/index.html b/2023/22/index.html index 8ec75c37..435f14b7 100644 --- a/2023/22/index.html +++ b/2023/22/index.html @@ -298,31 +298,31 @@

Sand Slabs

record Range(int begin, int end); record Block(Range x, Range y, Range z) { - public int Top => z.end; - public int Bottom => z.begin; + public int Top => z.end; + public int Bottom => z.begin; } record Supports( - Dictionary> blocksAbove, - Dictionary> blocksBelow + Dictionary<Block, HashSet<Block>> blocksAbove, + Dictionary<Block, HashSet<Block>> blocksBelow ); -[ProblemName("Sand Slabs")] +[ProblemName("Sand Slabs")] class Solution : Solver { - public object PartOne(string input) => Kaboom(input).Count(x => x == 0); - public object PartTwo(string input) => Kaboom(input).Sum(); + public object PartOne(string input) => Kaboom(input).Count(x => x == 0); + public object PartTwo(string input) => Kaboom(input).Sum(); // desintegrates the blocks one by one and returns how many blocks would // start falling because of that. - IEnumerable Kaboom(string input) { + IEnumerable<int> Kaboom(string input) { var blocks = Fall(ParseBlocks(input)); var supports = GetSupports(blocks); foreach (var desintegratedBlock in blocks) { - var q = new Queue(); + var q = new Queue<Block>(); q.Enqueue(desintegratedBlock); - var falling = new HashSet(); + var falling = new HashSet<Block>(); while (q.TryDequeue(out var block)) { falling.Add(block); @@ -335,19 +335,19 @@

Sand Slabs

q.Enqueue(blockT); } } - yield return falling.Count - 1; // -1: desintegratedBlock doesn't count + yield return falling.Count - 1; // -1: desintegratedBlock doesn't count } } - // applies 'gravity' to the blocks. + // applies 'gravity' to the blocks. Block[] Fall(Block[] blocks) { // sort them in Z first so that we can work in bottom to top order - blocks = blocks.OrderBy(block => block.Bottom).ToArray(); + blocks = blocks.OrderBy(block => block.Bottom).ToArray(); - for (var i = 0; i < blocks.Length; i++) { + for (var i = 0; i < blocks.Length; i++) { var newBottom = 1; - for (var j = 0; j < i; j++) { + for (var j = 0; j < i; j++) { if (IntersectsXY(blocks[i], blocks[j])) { newBottom = Math.Max(newBottom, blocks[j].Top + 1); } @@ -362,12 +362,12 @@

Sand Slabs

// calculate upper and lower neighbours for each block Supports GetSupports(Block[] blocks) { - var blocksAbove = blocks.ToDictionary(b => b, _ => new HashSet()); - var blocksBelow = blocks.ToDictionary(b => b, _ => new HashSet()); - for (var i = 0; i < blocks.Length; i++) { - for (var j = i + 1; j < blocks.Length; j++) { + var blocksAbove = blocks.ToDictionary(b => b, _ => new HashSet<Block>()); + var blocksBelow = blocks.ToDictionary(b => b, _ => new HashSet<Block>()); + for (var i = 0; i < blocks.Length; i++) { + for (var j = i + 1; j < blocks.Length; j++) { var zNeighbours = blocks[j].Bottom == 1 + blocks[i].Top; - if (zNeighbours && IntersectsXY(blocks[i], blocks[j])) { + if (zNeighbours && IntersectsXY(blocks[i], blocks[j])) { blocksBelow[blocks[j]].Add(blocks[i]); blocksAbove[blocks[i]].Add(blocks[j]); } @@ -376,15 +376,15 @@

Sand Slabs

return new Supports(blocksAbove, blocksBelow); } - bool IntersectsXY(Block blockA, Block blockB) => - Intersects(blockA.x, blockB.x) && Intersects(blockA.y, blockB.y); + bool IntersectsXY(Block blockA, Block blockB) => + Intersects(blockA.x, blockB.x) && Intersects(blockA.y, blockB.y); // see https://stackoverflow.com/a/3269471 - bool Intersects(Range r1, Range r2) => r1.begin <= r2.end && r2.begin <= r1.end; + bool Intersects(Range r1, Range r2) => r1.begin <= r2.end && r2.begin <= r1.end; - Block[] ParseBlocks(string input) => ( - from line in input.Split('\n') - let numbers = line.Split(',','~').Select(int.Parse).ToArray() + Block[] ParseBlocks(string input) => ( + from line in input.Split('\n') + let numbers = line.Split(',','~').Select(int.Parse).ToArray() select new Block( x: new Range(numbers[0], numbers[3]), y: new Range(numbers[1], numbers[4]), diff --git a/2023/23/index.html b/2023/23/index.html index f44fb879..e453bebe 100644 --- a/2023/23/index.html +++ b/2023/23/index.html @@ -301,17 +301,17 @@

A Long Walk

using System.Collections.Generic; using System.Numerics; using System.Linq; -using Map = System.Collections.Generic.Dictionary; +using Map = System.Collections.Generic.Dictionary<System.Numerics.Complex, char>; using Node = long; record Edge(Node start, Node end, int distance); -[ProblemName("A Long Walk")] +[ProblemName("A Long Walk")] class Solution : Solver { - // Instead of dealing with the 'map' tiles directly, we convert it to a graph. + // Instead of dealing with the 'map' tiles directly, we convert it to a graph. // Nodes: the entry tile, the exit and the crossroad tiles. // Edges: two nodes are connected if there is a direct path between them that - // doesn't contain crossroads. + // doesn't contain crossroads. // This reduces a problem to ~30 nodes and 120 edges for the Part 2 case // which can be solved using a dynamic programming approach. @@ -321,38 +321,38 @@

A Long Walk

static readonly Complex Right = 1; static readonly Complex[] Dirs = [Up, Down, Left, Right]; - Dictionary exits = new() { - ['<'] = [Left], - ['>'] = [Right], - ['^'] = [Up], - ['v'] = [Down], - ['.'] = Dirs, - ['#'] = [] + Dictionary<char, Complex[]> exits = new() { + ['<'] = [Left], + ['>'] = [Right], + ['^'] = [Up], + ['v'] = [Down], + ['.'] = Dirs, + ['#'] = [] }; - public object PartOne(string input) => Solve(input); - public object PartTwo(string input) => Solve(RemoveSlopes(input)); + public object PartOne(string input) => Solve(input); + public object PartTwo(string input) => Solve(RemoveSlopes(input)); - string RemoveSlopes(string st) => - string.Join("", st.Select(ch => ">v<^".Contains(ch) ? '.' : ch)); + string RemoveSlopes(string st) => + string.Join("", st.Select(ch => ">v<^".Contains(ch) ? '.' : ch)); int Solve(string input) { var (nodes, edges) = MakeGraph(input); var (start, goal) = (nodes.First(), nodes.Last()); - // Dynamic programming using a cache, 'visited' is a bitset of 'nodes'. - var cache = new Dictionary<(Node, long), int>(); + // Dynamic programming using a cache, 'visited' is a bitset of 'nodes'. + var cache = new Dictionary<(Node, long), int>(); int LongestPath(Node node, long visited) { if (node == goal) { return 0; - } else if ((visited & node) != 0) { - return int.MinValue; // small enough to represent '-infinity' + } else if ((visited & node) != 0) { + return int.MinValue; // small enough to represent '-infinity' } var key = (node, visited); if (!cache.ContainsKey(key)) { cache[key] = edges - .Where(e => e.start == node) - .Select(e => e.distance + LongestPath(e.end, visited | node)) + .Where(e => e.start == node) + .Select(e => e.distance + LongestPath(e.end, visited | node)) .Max(); } return cache[key]; @@ -363,16 +363,16 @@

A Long Walk

(Node[], Edge[]) MakeGraph(string input) { var map = ParseMap(input); - // row-major order: 'entry' node comes first and 'exit' is last + // row-major order: 'entry' node comes first and 'exit' is last var nodePos = ( from pos in map.Keys orderby pos.Imaginary, pos.Real - where IsFree(map, pos) && !IsRoad(map, pos) + where IsFree(map, pos) && !IsRoad(map, pos) select pos ).ToArray(); var nodes = ( - from i in Enumerable.Range(0, nodePos.Length) select 1L << i + from i in Enumerable.Range(0, nodePos.Length) select 1L << i ).ToArray(); var edges = ( @@ -380,7 +380,7 @@

A Long Walk

from j in Enumerable.Range(0, nodePos.Length) where i != j let distance = Distance(map, nodePos[i], nodePos[j]) - where distance > 0 + where distance > 0 select new Edge(nodes[i], nodes[j], distance) ).ToArray(); @@ -389,17 +389,17 @@

A Long Walk

// Length of the road between two crossroads; -1 if not neighbours int Distance(Map map, Complex crossroadA, Complex crossroadB) { - var q = new Queue<(Complex, int)>(); + var q = new Queue<(Complex, int)>(); q.Enqueue((crossroadA, 0)); - var visited = new HashSet { crossroadA }; + var visited = new HashSet<Complex> { crossroadA }; while (q.Any()) { var (pos, dist) = q.Dequeue(); foreach (var dir in exits[map[pos]]) { var posT = pos + dir; if (posT == crossroadB) { return dist + 1; - } else if (IsRoad(map, posT) && !visited.Contains(posT)) { + } else if (IsRoad(map, posT) && !visited.Contains(posT)) { visited.Add(posT); q.Enqueue((posT, dist + 1)); } @@ -408,19 +408,19 @@

A Long Walk

return -1; } - bool IsFree(Map map, Complex p) => - map.ContainsKey(p) && map[p] != '#'; + bool IsFree(Map map, Complex p) => + map.ContainsKey(p) && map[p] != '#'; - bool IsRoad(Map map, Complex p) => - IsFree(map, p) && Dirs.Count(d => IsFree(map, p + d)) == 2; + bool IsRoad(Map map, Complex p) => + IsFree(map, p) && Dirs.Count(d => IsFree(map, p + d)) == 2; Map ParseMap(string input) { - var lines = input.Split('\n'); + var lines = input.Split('\n'); return ( from irow in Enumerable.Range(0, lines.Length) from icol in Enumerable.Range(0, lines[0].Length) let pos = new Complex(icol, irow) - select new KeyValuePair(pos, lines[irow][icol]) + select new KeyValuePair<Complex, char>(pos, lines[irow][icol]) ).ToDictionary(); } } diff --git a/2023/24/index.html b/2023/24/index.html index 5c594796..17265674 100644 --- a/2023/24/index.html +++ b/2023/24/index.html @@ -309,25 +309,25 @@

Never Tell Me The Odds

record Particle2(Vec2 pos, Vec2 vel); record Particle3(Vec3 pos, Vec3 vel); -[ProblemName("Never Tell Me The Odds")] +[ProblemName("Never Tell Me The Odds")] class Solution : Solver { public object PartOne(string input) { - var particles = Project(ParseParticles(input), v => (v.x0, v.x1)); + var particles = Project(ParseParticles(input), v => (v.x0, v.x1)); - var inRange = (decimal d) => 2e14m <= d && d <= 4e14m; + var inRange = (decimal d) => 2e14m <= d && d <= 4e14m; - var inFuture = (Particle2 p, Vec2 pos) => + var inFuture = (Particle2 p, Vec2 pos) => Math.Sign(pos.x0 - p.pos.x0) == Math.Sign(p.vel.x0); var res = 0; - for (var i = 0; i < particles.Length; i++) { - for (var j = i + 1; j < particles.Length; j++) { + for (var i = 0; i < particles.Length; i++) { + for (var j = i + 1; j < particles.Length; j++) { var pos = Intersection(particles[i], particles[j]); - if (pos != null && - inRange(pos.x0) && - inRange(pos.x1) && - inFuture(particles[i], pos) && + if (pos != null && + inRange(pos.x0) && + inRange(pos.x1) && + inFuture(particles[i], pos) && inFuture(particles[j], pos) ) { res++; @@ -339,35 +339,35 @@

Never Tell Me The Odds

public object PartTwo(string input) { var particles = ParseParticles(input); - var stoneXY = Solve2D(Project(particles, vec => (vec.x0, vec.x1))); - var stoneXZ = Solve2D(Project(particles, vec => (vec.x0, vec.x2))); + var stoneXY = Solve2D(Project(particles, vec => (vec.x0, vec.x1))); + var stoneXZ = Solve2D(Project(particles, vec => (vec.x0, vec.x2))); return Math.Round(stoneXY.x0 + stoneXY.x1 + stoneXZ.x1); } Vec2 Solve2D(Particle2[] particles) { // We try to guess the speed of our stone (a for loop), then supposing // that it is the right velocity we create a new reference frame that - // moves with that speed. The stone doesn't move in this frame, it has + // moves with that speed. The stone doesn't move in this frame, it has // some fixed unknown coordinates. Now transform each particle into // this reference frame as well. Since the stone is not moving, if we // properly guessed the speed, we find that each particle meets at the - // same point. This must be the stone's location. + // same point. This must be the stone's location. - var translateV = (Particle2 p, Vec2 vel) => + var translateV = (Particle2 p, Vec2 vel) => new Particle2(p.pos, new Vec2(p.vel.x0 - vel.x0, p.vel.x1 - vel.x1)); var s = 500; //arbitrary limits for the brute force that worked for me. - for (var v1 = -s; v1 < s; v1++) { - for (var v2 = -s; v2 < s; v2++) { + for (var v1 = -s; v1 < s; v1++) { + for (var v2 = -s; v2 < s; v2++) { var vel = new Vec2(v1, v2); - // p0 and p1 are linearly independent (for me) => stone != null + // p0 and p1 are linearly independent (for me) => stone != null var stone = Intersection( translateV(particles[0], vel), translateV(particles[1], vel) ); - if (particles.All(p => Hits(translateV(p, vel), stone))) { + if (particles.All(p => Hits(translateV(p, vel), stone))) { return stone; } } @@ -377,14 +377,14 @@

Never Tell Me The Odds

bool Hits(Particle2 p, Vec2 pos) { var d = (pos.x0 - p.pos.x0) * p.vel.x1 - (pos.x1 - p.pos.x1) * p.vel.x0; - return Math.Abs(d) < (decimal)0.0001; + return Math.Abs(d) < (decimal)0.0001; } Vec2 Intersection(Particle2 p1, Particle2 p2) { // this would look way better if I had a matrix library at my disposal. var determinant = p1.vel.x0 * p2.vel.x1 - p1.vel.x1 * p2.vel.x0; if (determinant == 0) { - return null; //particles don't meet + return null; //particles don't meet } var b0 = p1.vel.x0 * p1.pos.x1 - p1.vel.x1 * p1.pos.x0; @@ -396,18 +396,18 @@

Never Tell Me The Odds

); } - Particle3[] ParseParticles(string input) => [.. - from line in input.Split('\n') + Particle3[] ParseParticles(string input) => [.. + from line in input.Split('\n') let v = ParseNum(line) select new Particle3(new (v[0], v[1], v[2]), new (v[3], v[4], v[5])) ]; - decimal[] ParseNum(string l) => [.. - from m in Regex.Matches(l, @"-?\d+") select decimal.Parse(m.Value) + decimal[] ParseNum(string l) => [.. + from m in Regex.Matches(l, @"-?\d+") select decimal.Parse(m.Value) ]; // Project particles to a 2D plane: - Particle2[] Project(Particle3[] ps, Func proj) => [.. + Particle2[] Project(Particle3[] ps, Func<Vec3, (decimal, decimal)> proj) => [.. from p in ps select new Particle2( new Vec2(proj(p.pos).Item1, proj(p.pos).Item2), new Vec2(proj(p.vel).Item1, proj(p.vel).Item2) diff --git a/2023/25/index.html b/2023/25/index.html index 0258b854..97768c17 100644 --- a/2023/25/index.html +++ b/2023/25/index.html @@ -304,13 +304,13 @@

Snowverload

using System.Collections.Generic; using System.Linq; -[ProblemName("Snowverload")] +[ProblemName("Snowverload")] class Solution : Solver { public object PartOne(string input) { Random r = new Random(25); - // run Karger's algorithm until it finds a cut with 3 edges + // run Karger's algorithm until it finds a cut with 3 edges var (cutSize, c1, c2) = FindCut(input, r); while (cutSize != 3) { (cutSize, c1, c2) = FindCut(input, r); @@ -319,17 +319,17 @@

Snowverload

} // https://en.wikipedia.org/wiki/Karger%27s_algorithm - // Karger's algorithm finds a cut of a graph and returns its size. - // It's not necessarily the minimal cut, because it's a randomized algorithm - // but it's 'likely' to find the minimal cut in reasonable time. + // Karger's algorithm finds a cut of a graph and returns its size. + // It's not necessarily the minimal cut, because it's a randomized algorithm + // but it's 'likely' to find the minimal cut in reasonable time. // The algorithm is extended to return the sizes of the two components // separated by the cut as well. (int size, int c1, int c2) FindCut(string input, Random r) { var graph = Parse(input); - var componentSize = graph.Keys.ToDictionary(k => k, _ => 1); + var componentSize = graph.Keys.ToDictionary(k => k, _ => 1); // updates backreferences of oldNode to point to newNode - var rebind = (string oldNode, string newNode) => { + var rebind = (string oldNode, string newNode) => { foreach (var n in graph[oldNode]) { while (graph[n].Remove(oldNode)) { graph[n].Add(newNode); @@ -337,16 +337,16 @@

Snowverload

} }; - for (var id = 0; graph.Count > 2; id++) { + for (var id = 0; graph.Count > 2; id++) { // decrease the the number of nodes by one. First select two nodes u // and v connected with an edge. Introduce a new node that inherits // every edge going out of these (excluding the edges between them). - // Set the new nodes' component size to the sum of the component + // Set the new nodes' component size to the sum of the component // sizes of u and v. Remove u and v from the graph. var u = graph.Keys.ElementAt(r.Next(graph.Count)); var v = graph[u][r.Next(graph[u].Count)]; - var merged = "merge-" + id; + var merged = "merge-" + id; graph[merged] = [ ..from n in graph[u] where n != v select n, ..from n in graph[v] where n != u select n @@ -370,20 +370,20 @@

Snowverload

// returns an adjacency list representation of the input. Edges are recorded // both ways, unlike in the input which contains them in one direction only. - Dictionary> Parse(string input) { - var graph = new Dictionary>(); + Dictionary<string, List<string>> Parse(string input) { + var graph = new Dictionary<string, List<string>>(); - var registerEdge = (string u, string v) => { + var registerEdge = (string u, string v) => { if (!graph.ContainsKey(u)) { graph[u] = new(); } graph[u].Add(v); }; - foreach (var line in input.Split('\n')) { - var parts = line.Split(": "); + foreach (var line in input.Split('\n')) { + var parts = line.Split(": "); var u = parts[0]; - var nodes = parts[1].Split(' '); + var nodes = parts[1].Split(' '); foreach (var v in nodes) { registerEdge(u, v); registerEdge(v, u); diff --git a/2023/3/index.html b/2023/3/index.html index 7bd20094..3ad25f49 100644 --- a/2023/3/index.html +++ b/2023/3/index.html @@ -290,29 +290,29 @@

Gear Ratios

using System.Linq; using System.Text.RegularExpressions; -[ProblemName("Gear Ratios")] +[ProblemName("Gear Ratios")] class Solution : Solver { - // Introduce a Parse function that returns the interesting 'blocks' of texts + // Introduce a Parse function that returns the interesting 'blocks' of texts // and positions using a regex. Then just filter and match these according // to the problem spec. public object PartOne(string input) { - var rows = input.Split("\n"); - var symbols = Parse(rows, new Regex(@"[^.0-9]")); - var nums = Parse(rows, new Regex(@"\d+")); + var rows = input.Split("\n"); + var symbols = Parse(rows, new Regex(@"[^.0-9]")); + var nums = Parse(rows, new Regex(@"\d+")); return ( from n in nums - where symbols.Any(s => Adjacent(s, n)) + where symbols.Any(s => Adjacent(s, n)) select n.Int ).Sum(); } public object PartTwo(string input) { - var rows = input.Split("\n"); - var gears = Parse(rows, new Regex(@"\*")); - var numbers = Parse(rows, new Regex(@"\d+")); + var rows = input.Split("\n"); + var gears = Parse(rows, new Regex(@"\*")); + var numbers = Parse(rows, new Regex(@"\d+")); return ( from g in gears @@ -324,13 +324,13 @@

Gear Ratios

// checks that the parts are touching each other, i.e. rows are within 1 // step and also the columns (using https://stackoverflow.com/a/3269471). - bool Adjacent(Part p1, Part p2) => - Math.Abs(p2.Irow - p1.Irow) <= 1 && - p1.Icol <= p2.Icol + p2.Text.Length && - p2.Icol <= p1.Icol + p1.Text.Length; + bool Adjacent(Part p1, Part p2) => + Math.Abs(p2.Irow - p1.Irow) <= 1 && + p1.Icol <= p2.Icol + p2.Text.Length && + p2.Icol <= p1.Icol + p1.Text.Length; // returns the matches of rx with its coordinates - Part[] Parse(string[] rows, Regex rx) => ( + Part[] Parse(string[] rows, Regex rx) => ( from irow in Enumerable.Range(0, rows.Length) from match in rx.Matches(rows[irow]) select new Part(match.Value, irow, match.Index) @@ -338,7 +338,7 @@

Gear Ratios

} record Part(string Text, int Irow, int Icol) { - public int Int => int.Parse(Text); + public int Int => int.Parse(Text); }

Please ☆ my repo if you like it!

diff --git a/2023/4/index.html b/2023/4/index.html index 390c0730..200e0b58 100644 --- a/2023/4/index.html +++ b/2023/4/index.html @@ -292,24 +292,24 @@

Scratchcards

record Card(int matches); -[ProblemName("Scratchcards")] +[ProblemName("Scratchcards")] class Solution : Solver { - public object PartOne(string input) => ( - from line in input.Split("\n") + public object PartOne(string input) => ( + from line in input.Split("\n") let card = ParseCard(line) - where card.matches > 0 + where card.matches > 0 select Math.Pow(2, card.matches - 1) ).Sum(); // Quite imperatively, just walk over the cards keeping track of the counts. public object PartTwo(string input) { - var cards = input.Split("\n").Select(ParseCard).ToArray(); - var counts = cards.Select(_ => 1).ToArray(); + var cards = input.Split("\n").Select(ParseCard).ToArray(); + var counts = cards.Select(_ => 1).ToArray(); - for (var i = 0; i < cards.Length; i++) { + for (var i = 0; i < cards.Length; i++) { var (card, count) = (cards[i], counts[i]); - for (var j = 0; j < card.matches; j++) { + for (var j = 0; j < card.matches; j++) { counts[i + j + 1] += count; } } @@ -318,9 +318,9 @@

Scratchcards

// Only the match count is relevant for a card Card ParseCard(string line) { - var parts = line.Split(':', '|'); - var l = from m in Regex.Matches(parts[1], @"\d+") select m.Value; - var r = from m in Regex.Matches(parts[2], @"\d+") select m.Value; + var parts = line.Split(':', '|'); + var l = from m in Regex.Matches(parts[1], @"\d+") select m.Value; + var r = from m in Regex.Matches(parts[2], @"\d+") select m.Value; return new Card(l.Intersect(r).Count()); } } diff --git a/2023/5/index.html b/2023/5/index.html index 710a7928..4a4cf134 100644 --- a/2023/5/index.html +++ b/2023/5/index.html @@ -290,42 +290,42 @@

If You Give A Seed A Fertilizer

record Range(long begin, long end); -[ProblemName("If You Give A Seed A Fertilizer")] +[ProblemName("If You Give A Seed A Fertilizer")] class Solution : Solver { - public object PartOne(string input) => Solve(input, PartOneRanges); - public object PartTwo(string input) => Solve(input, PartTwoRanges); + public object PartOne(string input) => Solve(input, PartOneRanges); + public object PartTwo(string input) => Solve(input, PartTwoRanges); - long Solve(string input, Func, IEnumerable> parseSeeds) { - var blocks = input.Split("\n\n"); + long Solve(string input, Func<IEnumerable<long>, IEnumerable<Range>> parseSeeds) { + var blocks = input.Split("\n\n"); var seedRanges = parseSeeds(ParseNumbers(blocks[0])).ToList(); var maps = blocks.Skip(1).Select(ParseMap).ToArray(); // Project each range through the series of maps, this will result some // new ranges. Return the leftmost value (minimum) of these. - return maps.Aggregate(seedRanges, Project).Select(r => r.begin).Min(); + return maps.Aggregate(seedRanges, Project).Select(r => r.begin).Min(); } - List Project(List inputRanges, Dictionary map) { - var input = new Queue(inputRanges); - var output = new List(); + List<Range> Project(List<Range> inputRanges, Dictionary<Range, Range> map) { + var input = new Queue<Range>(inputRanges); + var output = new List<Range>(); while (input.Any()) { var range = input.Dequeue(); - // If no entry intersects our range -> just add it to the output. - // If an entry completely contains the range -> add after mapping. - // Otherwise, some entry partly covers the range. In this case 'chop' + // If no entry intersects our range -> just add it to the output. + // If an entry completely contains the range -> add after mapping. + // Otherwise, some entry partly covers the range. In this case 'chop' // the range into two halfs getting rid of the intersection. The new // pieces are added back to the queue for further processing and will be // ultimately consumed by the first two cases. - var src = map.Keys.FirstOrDefault(src => Intersects(src, range)); + var src = map.Keys.FirstOrDefault(src => Intersects(src, range)); if (src == null) { output.Add(range); - } else if (src.begin <= range.begin && range.end <= src.end) { + } else if (src.begin <= range.begin && range.end <= src.end) { var dst = map[src]; var shift = dst.begin - src.begin; output.Add(new Range(range.begin + shift, range.end + shift)); - } else if (range.begin < src.begin) { + } else if (range.begin < src.begin) { input.Enqueue(new Range(range.begin, src.begin - 1)); input.Enqueue(new Range(src.begin, range.end)); } else { @@ -337,23 +337,23 @@

If You Give A Seed A Fertilizer

} // see https://stackoverflow.com/a/3269471 - bool Intersects(Range r1, Range r2) => r1.begin <= r2.end && r2.begin <= r1.end; + bool Intersects(Range r1, Range r2) => r1.begin <= r2.end && r2.begin <= r1.end; // consider each number as a range of 1 length - IEnumerable PartOneRanges(IEnumerable numbers) => + IEnumerable<Range> PartOneRanges(IEnumerable<long> numbers) => from n in numbers select new Range(n, n); // chunk is a great way to iterate over the pairs of numbers - IEnumerable PartTwoRanges(IEnumerable numbers) => + IEnumerable<Range> PartTwoRanges(IEnumerable<long> numbers) => from n in numbers.Chunk(2) select new Range(n[0], n[0] + n[1] - 1); - IEnumerable ParseNumbers(string input) => - from m in Regex.Matches(input, @"\d+") select long.Parse(m.Value); + IEnumerable<long> ParseNumbers(string input) => + from m in Regex.Matches(input, @"\d+") select long.Parse(m.Value); - Dictionary ParseMap(string input) => ( - from line in input.Split("\n").Skip(1) + Dictionary<Range, Range> ParseMap(string input) => ( + from line in input.Split("\n").Skip(1) let parts = ParseNumbers(line).ToArray() - select new KeyValuePair( + select new KeyValuePair<Range, Range>( new Range(parts[1], parts[2] + parts[1] - 1), new Range(parts[0], parts[2] + parts[0] - 1)) ).ToDictionary(); diff --git a/2023/6/index.html b/2023/6/index.html index 610084eb..73165121 100644 --- a/2023/6/index.html +++ b/2023/6/index.html @@ -288,19 +288,19 @@

Wait For It

using System.Linq; using System.Text.RegularExpressions; -[ProblemName("Wait For It")] +[ProblemName("Wait For It")] class Solution : Solver { - public object PartOne(string input) => Solve(input); - public object PartTwo(string input) => Solve(input.Replace(" ", "")); + public object PartOne(string input) => Solve(input); + public object PartTwo(string input) => Solve(input.Replace(" ", "")); long Solve(string input) { - var rows = input.Split("\n"); + var rows = input.Split("\n"); var times = Parse(rows[0]); var records = Parse(rows[1]); var res = 1L; - for (var i = 0; i < times.Length; i++) { + for (var i = 0; i < times.Length; i++) { res *= WinningMoves(times[i], records[i]); } return res; @@ -308,8 +308,8 @@

Wait For It

long WinningMoves(long time, long record) { // If we wait x ms, our boat moves `(time - x) * x` millimeters. - // This breaks the record when `(time - x) * x > record` - // or `-x^2 + time * x - record > 0`. + // This breaks the record when `(time - x) * x > record` + // or `-x^2 + time * x - record > 0`. // get the roots first var (x1, x2) = SolveEq(-1, time, -record); @@ -328,8 +328,8 @@

Wait For It

return (Math.Min(x1, x2), Math.Max(x1, x2)); } - long[] Parse(string input) => ( - from m in Regex.Matches(input, @"\d+") + long[] Parse(string input) => ( + from m in Regex.Matches(input, @"\d+") select long.Parse(m.Value) ).ToArray(); } diff --git a/2023/7/index.html b/2023/7/index.html index 73bf2ed6..e470be8c 100644 --- a/2023/7/index.html +++ b/2023/7/index.html @@ -289,48 +289,48 @@

Camel Cards

using System.Collections.Generic; using System.Linq; -[ProblemName("Camel Cards")] +[ProblemName("Camel Cards")] class Solution : Solver { - // Each 'hand' gets points based on the card's individual value and + // Each 'hand' gets points based on the card's individual value and // pattern value. - public object PartOne(string input) => Solve(input, Part1Points); - public object PartTwo(string input) => Solve(input, Part2Points); + public object PartOne(string input) => Solve(input, Part1Points); + public object PartTwo(string input) => Solve(input, Part2Points); - (long, long) Part1Points(string hand) => - (PatternValue(hand), CardValue(hand, "123456789TJQKA")); + (long, long) Part1Points(string hand) => + (PatternValue(hand), CardValue(hand, "123456789TJQKA")); (long, long) Part2Points(string hand) { - var cards = "J123456789TQKA"; + var cards = "J123456789TQKA"; var patternValue = - cards.Select(ch => PatternValue(hand.Replace('J', ch))).Max(); + cards.Select(ch => PatternValue(hand.Replace('J', ch))).Max(); return (patternValue, CardValue(hand, cards)); } // map cards to their indices in cardOrder. E.g. for 123456789TJQKA // A8A8A becomes (13)(7)(13)(7)(13), 9A34Q becomes (8)(13)(2)(3)(11) - long CardValue(string hand, string cardOrder) => - Pack(hand.Select(card => cardOrder.IndexOf(card))); + long CardValue(string hand, string cardOrder) => + Pack(hand.Select(card => cardOrder.IndexOf(card))); // map cards to the number of their occurrences in the hand then order them // such thatA8A8A becomes 33322, 9A34Q becomes 11111 and K99AA becomes 22221 - long PatternValue(string hand) => - Pack(hand.Select(card => hand.Count(x => x == card)).OrderDescending()); + long PatternValue(string hand) => + Pack(hand.Select(card => hand.Count(x => x == card)).OrderDescending()); - long Pack(IEnumerable numbers) => - numbers.Aggregate(1L, (a, v) => (a * 256) + v); + long Pack(IEnumerable<int> numbers) => + numbers.Aggregate(1L, (a, v) => (a * 256) + v); - int Solve(string input, Func getPoints) { + int Solve(string input, Func<string, (long, long)> getPoints) { var bidsByRanking = ( - from line in input.Split("\n") - let hand = line.Split(" ")[0] - let bid = int.Parse(line.Split(" ")[1]) + from line in input.Split("\n") + let hand = line.Split(" ")[0] + let bid = int.Parse(line.Split(" ")[1]) orderby getPoints(hand) select bid ); - return bidsByRanking.Select((bid, rank) => (rank + 1) * bid).Sum(); + return bidsByRanking.Select((bid, rank) => (rank + 1) * bid).Sum(); } } diff --git a/2023/8/index.html b/2023/8/index.html index 4cbff010..96e41e76 100644 --- a/2023/8/index.html +++ b/2023/8/index.html @@ -288,16 +288,16 @@

Haunted Wasteland

using System.Linq; using System.Text.RegularExpressions; -using Map = System.Collections.Generic.Dictionary; +using Map = System.Collections.Generic.Dictionary<string, (string Left, string Right)>; -[ProblemName("Haunted Wasteland")] +[ProblemName("Haunted Wasteland")] class Solution : Solver { - public object PartOne(string input) => Solve(input, "AAA", "ZZZ"); - public object PartTwo(string input) => Solve(input, "A", "Z"); + public object PartOne(string input) => Solve(input, "AAA", "ZZZ"); + public object PartTwo(string input) => Solve(input, "A", "Z"); long Solve(string input, string aMarker, string zMarker) { - var blocks = input.Split("\n\n"); + var blocks = input.Split("\n\n"); var dirs = blocks[0]; var map = ParseMap(blocks[1]); @@ -307,28 +307,28 @@

Haunted Wasteland

// The input was set up this way, which justifies the use of LCM in // computing the final result. return map.Keys - .Where(w => w.EndsWith(aMarker)) - .Select(w => StepsToZ(w, zMarker, dirs, map)) + .Where(w => w.EndsWith(aMarker)) + .Select(w => StepsToZ(w, zMarker, dirs, map)) .Aggregate(1L, Lcm); } - long Lcm(long a, long b) => a * b / Gcd(a, b); - long Gcd(long a, long b) => b == 0 ? a : Gcd(b, a % b); + long Lcm(long a, long b) => a * b / Gcd(a, b); + long Gcd(long a, long b) => b == 0 ? a : Gcd(b, a % b); long StepsToZ(string current, string zMarker, string dirs, Map map) { var i = 0; while (!current.EndsWith(zMarker)) { var dir = dirs[i % dirs.Length]; - current = dir == 'L' ? map[current].Left : map[current].Right; + current = dir == 'L' ? map[current].Left : map[current].Right; i++; } return i; } - Map ParseMap(string input) => - input.Split("\n") - .Select(line => Regex.Matches(line, "[A-Z]+")) - .ToDictionary(m => m[0].Value, m => (m[1].Value, m[2].Value)); + Map ParseMap(string input) => + input.Split("\n") + .Select(line => Regex.Matches(line, "[A-Z]+")) + .ToDictionary(m => m[0].Value, m => (m[1].Value, m[2].Value)); }

Please ☆ my repo if you like it!

diff --git a/2023/9/index.html b/2023/9/index.html index e005ea63..26fcdc9d 100644 --- a/2023/9/index.html +++ b/2023/9/index.html @@ -287,28 +287,28 @@

Mirage Maintenance

using System; using System.Linq; -[ProblemName("Mirage Maintenance")] +[ProblemName("Mirage Maintenance")] class Solution : Solver { - public object PartOne(string input) => Solve(input, ExtrapolateRight); - public object PartTwo(string input) => Solve(input, ExtrapolateLeft); + public object PartOne(string input) => Solve(input, ExtrapolateRight); + public object PartTwo(string input) => Solve(input, ExtrapolateLeft); - long Solve(string input, Func extrapolate) => - input.Split("\n").Select(ParseNumbers).Select(extrapolate).Sum(); + long Solve(string input, Func<long[], long> extrapolate) => + input.Split("\n").Select(ParseNumbers).Select(extrapolate).Sum(); - long[] ParseNumbers(string line) => - line.Split(" ").Select(long.Parse).ToArray(); + long[] ParseNumbers(string line) => + line.Split(" ").Select(long.Parse).ToArray(); - // It's a common trick to zip a sequence with the skipped version of itself - long[] Diff(long[] numbers) => - numbers.Zip(numbers.Skip(1)).Select(p => p.Second - p.First).ToArray(); + // It's a common trick to zip a sequence with the skipped version of itself + long[] Diff(long[] numbers) => + numbers.Zip(numbers.Skip(1)).Select(p => p.Second - p.First).ToArray(); - // I went a bit further and recurse until there are no numbers left. It's - // more compact this way and doesn't affect the runtime much. - long ExtrapolateRight(long[] numbers) => + // I went a bit further and recurse until there are no numbers left. It's + // more compact this way and doesn't affect the runtime much. + long ExtrapolateRight(long[] numbers) => !numbers.Any() ? 0 : ExtrapolateRight(Diff(numbers)) + numbers.Last(); - long ExtrapolateLeft(long[] numbers) => + long ExtrapolateLeft(long[] numbers) => ExtrapolateRight(numbers.Reverse().ToArray()); } diff --git a/2024/1/index.html b/2024/1/index.html index f34025f5..a9921db1 100644 --- a/2024/1/index.html +++ b/2024/1/index.html @@ -287,25 +287,25 @@

Historian Hysteria

using System.Collections.Immutable; using System.Linq; -[ProblemName("Historian Hysteria")] +[ProblemName("Historian Hysteria")] class Solution : Solver { - public object PartOne(string input) => + public object PartOne(string input) => // go over the sorted columns pairwise and sum the difference of the pairs Enumerable.Zip(Column(input, 0), Column(input, 1)) - .Select(p => Math.Abs(p.First - p.Second)) + .Select(p => Math.Abs(p.First - p.Second)) .Sum(); public object PartTwo(string input) { // sum the elements of the left column weighted by its occurrences in the right // ⭐ .Net 9 comes with a new CountBy function - var weights = Column(input, 1).CountBy(x=>x).ToDictionary(); - return Column(input, 0).Select(num => weights.GetValueOrDefault(num) * num).Sum(); + var weights = Column(input, 1).CountBy(x=>x).ToDictionary(); + return Column(input, 0).Select(num => weights.GetValueOrDefault(num) * num).Sum(); } - IEnumerable Column(string input, int column) => - from line in input.Split("\n") - let nums = line.Split(" ").Select(int.Parse).ToArray() + IEnumerable<int> Column(string input, int column) => + from line in input.Split("\n") + let nums = line.Split(" ").Select(int.Parse).ToArray() orderby nums[column] select nums[column]; } diff --git a/2024/10/index.html b/2024/10/index.html index a31022e5..82e0a34b 100644 --- a/2024/10/index.html +++ b/2024/10/index.html @@ -291,9 +291,9 @@

Hoof It

using System.Linq; using System.Numerics; -using Map = System.Collections.Immutable.ImmutableDictionary; +using Map = System.Collections.Immutable.ImmutableDictionary<System.Numerics.Complex, char>; -[ProblemName("Hoof It")] +[ProblemName("Hoof It")] class Solution : Solver { Complex Up = Complex.ImaginaryOne; @@ -301,24 +301,24 @@

Hoof It

Complex Left = -1; Complex Right = 1; - public object PartOne(string input) => GetAllTrails(input).Sum(t => t.Value.Distinct().Count()); - public object PartTwo(string input) => GetAllTrails(input).Sum(t => t.Value.Count()); + public object PartOne(string input) => GetAllTrails(input).Sum(t => t.Value.Distinct().Count()); + public object PartTwo(string input) => GetAllTrails(input).Sum(t => t.Value.Count()); - Dictionary> GetAllTrails(string input) { + Dictionary<Complex, List<Complex>> GetAllTrails(string input) { var map = GetMap(input); - return GetTrailHeads(map).ToDictionary(t => t, t => GetTrailsFrom(map, t)); + return GetTrailHeads(map).ToDictionary(t => t, t => GetTrailsFrom(map, t)); } - IEnumerable GetTrailHeads(Map map) => map.Keys.Where(pos => map[pos] == '0'); + IEnumerable<Complex> GetTrailHeads(Map map) => map.Keys.Where(pos => map[pos] == '0'); - List GetTrailsFrom(Map map, Complex trailHead) { + List<Complex> GetTrailsFrom(Map map, Complex trailHead) { // standard floodfill algorithm using a queue - var positions = new Queue(); + var positions = new Queue<Complex>(); positions.Enqueue(trailHead); - var trails = new List(); + var trails = new List<Complex>(); while (positions.Any()) { var point = positions.Dequeue(); - if (map[point] == '9') { + if (map[point] == '9') { trails.Add(point); } else { foreach (var dir in new[] { Up, Down, Left, Right }) { @@ -334,11 +334,11 @@

Hoof It

// store the points in a dictionary so that we can iterate over them and // to easily deal with points outside the area using GetValueOrDefault Map GetMap(string input) { - var map = input.Split("\n"); + var map = input.Split("\n"); return ( from y in Enumerable.Range(0, map.Length) from x in Enumerable.Range(0, map[0].Length) - select new KeyValuePair(x + y * Down, map[y][x]) + select new KeyValuePair<Complex, char>(x + y * Down, map[y][x]) ).ToImmutableDictionary(); } } diff --git a/2024/11/index.html b/2024/11/index.html index 99bad4e1..38a7f2b0 100644 --- a/2024/11/index.html +++ b/2024/11/index.html @@ -287,36 +287,36 @@

Plutonian Pebbles

using System.Linq; -using Cache = System.Collections.Concurrent.ConcurrentDictionary<(string, int), long>; +using Cache = System.Collections.Concurrent.ConcurrentDictionary<(string, int), long>; -[ProblemName("Plutonian Pebbles")] +[ProblemName("Plutonian Pebbles")] class Solution : Solver { - public object PartOne(string input) => StoneCount(input, 25); + public object PartOne(string input) => StoneCount(input, 25); - public object PartTwo(string input) => StoneCount(input, 75); + public object PartTwo(string input) => StoneCount(input, 75); long StoneCount(string input, int blinks) { var cache = new Cache(); - return input.Split(" ").Sum(n => Eval(long.Parse(n), blinks, cache)); + return input.Split(" ").Sum(n => Eval(long.Parse(n), blinks, cache)); } // Recursively calculates the total number of stones generated by a single engravement (n) // after a specified number of blinks. Uses caching to optimize and prevent exponential // computation by storing intermediate results. - long Eval(long n, int blinks, Cache cache) => - cache.GetOrAdd((n.ToString(), blinks), key => + long Eval(long n, int blinks, Cache cache) => + cache.GetOrAdd((n.ToString(), blinks), key => key switch { - (_, 0) => 1, + (_, 0) => 1, - ("0", _) => + ("0", _) => Eval(1, blinks - 1, cache), - (var st, _) when st.Length % 2 == 0 => + (var st, _) when st.Length % 2 == 0 => Eval(long.Parse(st[0..(st.Length / 2)]), blinks - 1, cache) + Eval(long.Parse(st[(st.Length / 2)..]), blinks - 1, cache), - _ => + _ => Eval(2024 * n, blinks - 1, cache) } ); diff --git a/2024/12/index.html b/2024/12/index.html index 2cc2c12d..32fed9d1 100644 --- a/2024/12/index.html +++ b/2024/12/index.html @@ -305,9 +305,9 @@

Garden Groups

using System.Linq; using System.Numerics; -using Region = System.Collections.Generic.HashSet; +using Region = System.Collections.Generic.HashSet<System.Numerics.Complex>; -[ProblemName("Garden Groups")] +[ProblemName("Garden Groups")] class Solution : Solver { Complex Up = Complex.ImaginaryOne; @@ -315,9 +315,9 @@

Garden Groups

Complex Left = -1; Complex Right = 1; - public object PartOne(string input) => CalculateFencePrice(input, FindEdges); + public object PartOne(string input) => CalculateFencePrice(input, FindEdges); - public object PartTwo(string input) => CalculateFencePrice(input, FindCorners); + public object PartTwo(string input) => CalculateFencePrice(input, FindCorners); int CalculateFencePrice(string input, MeasurePerimeter measure){ var regions = GetRegions(input); @@ -332,9 +332,9 @@

Garden Groups

return res; } - delegate int MeasurePerimeter(Dictionary map, Complex pt); + delegate int MeasurePerimeter(Dictionary<Complex, Region> map, Complex pt); - int FindEdges(Dictionary map, Complex pt) { + int FindEdges(Dictionary<Complex, Region> map, Complex pt) { var res = 0; var region = map[pt]; foreach (var du in new[] { Right, Down, Left, Up}) { @@ -346,7 +346,7 @@

Garden Groups

return res; } - int FindCorners(Dictionary map, Complex pt) { + int FindCorners(Dictionary<Complex, Region> map, Complex pt) { var res = 0; var region = map[pt]; @@ -354,7 +354,7 @@

Garden Groups

foreach (var (du, dv) in new[] { (Up, Right), (Right, Down), (Down, Left), (Left, Up) }) { // .. // x. convex corner - if (map.GetValueOrDefault(pt + du) != region && + if (map.GetValueOrDefault(pt + du) != region && map.GetValueOrDefault(pt + dv) != region ) { res++; @@ -362,8 +362,8 @@

Garden Groups

// x. // xx concave corner - if (map.GetValueOrDefault(pt + du) == region && - map.GetValueOrDefault(pt + dv) == region && + if (map.GetValueOrDefault(pt + du) == region && + map.GetValueOrDefault(pt + dv) == region && map.GetValueOrDefault(pt + du + dv) != region ) { res++; @@ -374,22 +374,22 @@

Garden Groups

// Maps the positions of plants in a garden to their corresponding regions, grouping plants // of the same type into contiguous regions. - Dictionary GetRegions(string input) { - var lines = input.Split("\n"); + Dictionary<Complex, Region> GetRegions(string input) { + var lines = input.Split("\n"); var garden = ( from y in Enumerable.Range(0, lines.Length) from x in Enumerable.Range(0, lines[0].Length) - select new KeyValuePair(x + y * Down, lines[y][x]) + select new KeyValuePair<Complex, char>(x + y * Down, lines[y][x]) ).ToDictionary(); // go over the positions of the garden and use a floodfill to determine the region - var res = new Dictionary(); + var res = new Dictionary<Complex, Region>(); var positions = garden.Keys.ToHashSet(); while (positions.Any()) { var pivot = positions.First(); var region = new Region { pivot }; - var q = new Queue(); + var q = new Queue<Complex>(); q.Enqueue(pivot); var plant = garden[pivot]; @@ -399,7 +399,7 @@

Garden Groups

res[point] = region; positions.Remove(point); foreach (var dir in new[] { Up, Down, Left, Right }) { - if (!region.Contains(point + dir) && garden.GetValueOrDefault(point + dir) == plant) { + if (!region.Contains(point + dir) && garden.GetValueOrDefault(point + dir) == plant) { region.Add(point + dir); q.Enqueue(point + dir); } diff --git a/2024/13/index.html b/2024/13/index.html index 7fd8166b..3cbf7192 100644 --- a/2024/13/index.html +++ b/2024/13/index.html @@ -289,36 +289,36 @@

Claw Contraption

record struct Vec2(long x, long y); -[ProblemName("Claw Contraption")] +[ProblemName("Claw Contraption")] class Solution : Solver { - public object PartOne(string input) => Parse(input).Sum(GetPrize); - public object PartTwo(string input) => Parse(input, shift: 10000000000000).Sum(GetPrize); + public object PartOne(string input) => Parse(input).Sum(GetPrize); + public object PartTwo(string input) => Parse(input, shift: 10000000000000).Sum(GetPrize); long GetPrize(Machine m) { var (a, b, p) = m; - // solve a * i + b * j = p for i and j using Cramer's rule + // solve a * i + b * j = p for i and j using Cramer's rule var i = Det(p, b) / Det(a, b); var j = Det(a, p) / Det(a, b); // return the prize when a non negative _integer_ solution is found - if (i >= 0 && j >= 0 && a.x * i + b.x * j == p.x && a.y * i + b.y * j == p.y) { + if (i >= 0 && j >= 0 && a.x * i + b.x * j == p.x && a.y * i + b.y * j == p.y) { return 3 * i + j; } else { return 0; } } - long Det(Vec2 a, Vec2 b) => a.x * b.y - a.y * b.x; + long Det(Vec2 a, Vec2 b) => a.x * b.y - a.y * b.x; - IEnumerable Parse(string input, long shift=0) { - var blocks = input.Split("\n\n"); + IEnumerable<Machine> Parse(string input, long shift=0) { + var blocks = input.Split("\n\n"); foreach (var block in blocks) { var nums = - Regex.Matches(block, @"\d+", RegexOptions.Multiline) - .Select(m => int.Parse(m.Value)) - .Chunk(2).Select(p => new Vec2(p[0], p[1])) + Regex.Matches(block, @"\d+", RegexOptions.Multiline) + .Select(m => int.Parse(m.Value)) + .Chunk(2).Select(p => new Vec2(p[0], p[1])) .ToArray(); nums[2] = new Vec2(nums[2].x + shift, nums[2].y + shift); diff --git a/2024/14/index.html b/2024/14/index.html index 4f4a6e0b..2a85ff81 100644 --- a/2024/14/index.html +++ b/2024/14/index.html @@ -327,7 +327,7 @@

Restroom Redoubt

record struct Vec2(int x, int y); record struct Robot(Vec2 pos, Vec2 vel); -[ProblemName("Restroom Redoubt")] +[ProblemName("Restroom Redoubt")] class Solution : Solver { const int width = 101; const int height = 103; @@ -337,20 +337,20 @@

Restroom Redoubt

var quadrants = Simulate(input) .ElementAt(100) .CountBy(GetQuadrant) - .Where(group => group.Key.x != 0 && group.Key.y != 0) - .Select(group => group.Value) + .Where(group => group.Key.x != 0 && group.Key.y != 0) + .Select(group => group.Value) .ToArray(); return quadrants[0] * quadrants[1] * quadrants[2] * quadrants[3]; } // i figured that the xmas tree pattern has a long horizontal ### pattern in it - public object PartTwo(string input) => + public object PartTwo(string input) => Simulate(input) - .TakeWhile(robots => !Plot(robots).Contains("#################")) + .TakeWhile(robots => !Plot(robots).Contains("#################")) .Count(); // an infinite simulation of robot movement - IEnumerable Simulate(string input) { + IEnumerable<Robot[]> Simulate(string input) { var robots = Parse(input).ToArray(); while (true) { yield return robots; @@ -358,35 +358,35 @@

Restroom Redoubt

} } - // advance a robot by its velocity taking care of the 'teleportation' - Robot Step(Robot robot) => robot with {pos = AddWithWrapAround(robot.pos, robot.vel) }; + // advance a robot by its velocity taking care of the 'teleportation' + Robot Step(Robot robot) => robot with {pos = AddWithWrapAround(robot.pos, robot.vel) }; // returns the direction (-1/0/1) of the robot to the center of the room - Vec2 GetQuadrant(Robot robot) => + Vec2 GetQuadrant(Robot robot) => new Vec2(Math.Sign(robot.pos.x - width / 2), Math.Sign(robot.pos.y - height / 2)); - Vec2 AddWithWrapAround(Vec2 a, Vec2 b) => + Vec2 AddWithWrapAround(Vec2 a, Vec2 b) => new Vec2((a.x + b.x + width) % width, (a.y + b.y + height) % height); // shows the robot locations in the room - string Plot(IEnumerable robots) { + string Plot(IEnumerable<Robot> robots) { var res = new char[height, width]; foreach (var robot in robots) { - res[robot.pos.y, robot.pos.x] = '#'; + res[robot.pos.y, robot.pos.x] = '#'; } var sb = new StringBuilder(); - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - sb.Append(res[y, x] == '#' ? "#" : " "); + for (var y = 0; y < height; y++) { + for (var x = 0; x < width; x++) { + sb.Append(res[y, x] == '#' ? "#" : " "); } sb.AppendLine(); } return sb.ToString(); } - IEnumerable Parse(string input) => - from line in input.Split("\n") - let nums = Regex.Matches(line, @"-?\d+").Select(m => int.Parse(m.Value)).ToArray() + IEnumerable<Robot> Parse(string input) => + from line in input.Split("\n") + let nums = Regex.Matches(line, @"-?\d+").Select(m => int.Parse(m.Value)).ToArray() select new Robot(new Vec2(nums[0], nums[1]), new Vec2(nums[2], nums[3])); }

Please ☆ my repo if you like it!

diff --git a/2024/15/index.html b/2024/15/index.html index db22a2dd..fc8093f9 100644 --- a/2024/15/index.html +++ b/2024/15/index.html @@ -291,9 +291,9 @@

Warehouse Woes

using System.Linq; using System.Numerics; -using Map = System.Collections.Immutable.IImmutableDictionary; +using Map = System.Collections.Immutable.IImmutableDictionary<System.Numerics.Complex, char>; -[ProblemName("Warehouse Woes")] +[ProblemName("Warehouse Woes")] class Solution : Solver { static Complex Up = -Complex.ImaginaryOne; @@ -301,13 +301,13 @@

Warehouse Woes

static Complex Left = -1; static Complex Right = 1; - public object PartOne(string input) => Solve(input); - public object PartTwo(string input) => Solve(ScaleUp(input)); + public object PartOne(string input) => Solve(input); + public object PartTwo(string input) => Solve(ScaleUp(input)); public double Solve(string input) { var (map, steps) = Parse(input); - var robot = map.Keys.Single(k => map[k] == '@'); + var robot = map.Keys.Single(k => map[k] == '@'); foreach (var dir in steps) { if (TryToStep(ref map, robot, dir)) { robot += dir; @@ -315,8 +315,8 @@

Warehouse Woes

} return map.Keys - .Where(k => map[k] == '[' || map[k] == 'O') - .Sum(box => box.Real + 100 * box.Imaginary); + .Where(k => map[k] == '[' || map[k] == 'O') + .Sum(box => box.Real + 100 * box.Imaginary); } // Attempts to move the robot in the given direction on the map, pushing boxes as necessary. @@ -325,41 +325,41 @@

Warehouse Woes

bool TryToStep(ref Map map, Complex pos, Complex dir) { var mapOrig = map; - if (map[pos] == '.') { + if (map[pos] == '.') { return true; - } else if (map[pos] == 'O' || map[pos] == '@') { + } else if (map[pos] == 'O' || map[pos] == '@') { if (TryToStep(ref map, pos + dir, dir)) { map = map .SetItem(pos + dir, map[pos]) - .SetItem(pos, '.'); + .SetItem(pos, '.'); return true; } - } else if (map[pos] == ']') { + } else if (map[pos] == ']') { return TryToStep(ref map, pos + Left, dir); - } else if (map[pos] == '[') { + } else if (map[pos] == '[') { if (dir == Left) { if (TryToStep(ref map, pos + Left, dir)) { map = map - .SetItem(pos + Left, '[') - .SetItem(pos, ']') - .SetItem(pos + Right, '.'); + .SetItem(pos + Left, '[') + .SetItem(pos, ']') + .SetItem(pos + Right, '.'); return true; } } else if (dir == Right) { if (TryToStep(ref map, pos + 2 * Right, dir)) { map = map - .SetItem(pos, '.') - .SetItem(pos + Right, '[') - .SetItem(pos + 2 * Right, ']'); + .SetItem(pos, '.') + .SetItem(pos + Right, '[') + .SetItem(pos + 2 * Right, ']'); return true; } } else { - if (TryToStep(ref map, pos + dir, dir) && TryToStep(ref map, pos + Right + dir, dir)) { + if (TryToStep(ref map, pos + dir, dir) && TryToStep(ref map, pos + Right + dir, dir)) { map = map - .SetItem(pos, '.') - .SetItem(pos + Right, '.') - .SetItem(pos + dir, '[') - .SetItem(pos + dir + Right, ']'); + .SetItem(pos, '.') + .SetItem(pos + Right, '.') + .SetItem(pos + dir, '[') + .SetItem(pos + dir + Right, ']'); return true; } } @@ -369,25 +369,25 @@

Warehouse Woes

return false; } - string ScaleUp(string input) => - input.Replace("#", "##").Replace(".", "..").Replace("O", "[]").Replace("@", "@."); + string ScaleUp(string input) => + input.Replace("#", "##").Replace(".", "..").Replace("O", "[]").Replace("@", "@."); (Map, Complex[]) Parse(string input) { - var blocks = input.Split("\n\n"); - var lines = blocks[0].Split("\n"); + var blocks = input.Split("\n\n"); + var lines = blocks[0].Split("\n"); var map = ( from y in Enumerable.Range(0, lines.Length) from x in Enumerable.Range(0, lines[0].Length) - select new KeyValuePair(x + y * Down, lines[y][x]) + select new KeyValuePair<Complex, char>(x + y * Down, lines[y][x]) ).ToImmutableDictionary(); - var steps = blocks[1].ReplaceLineEndings("").Select(ch => + var steps = blocks[1].ReplaceLineEndings("").Select(ch => ch switch { - '^' => Up, - '<' => Left, - '>' => Right, - 'v' => Down, - _ => throw new Exception() + '^' => Up, + '<' => Left, + '>' => Right, + 'v' => Down, + _ => throw new Exception() }); return (map, steps.ToArray()); diff --git a/2024/16/index.html b/2024/16/index.html index 021b3dbc..1b0dc6a4 100644 --- a/2024/16/index.html +++ b/2024/16/index.html @@ -288,10 +288,10 @@

Reindeer Maze

using System.Collections.Immutable; using System.Linq; using System.Numerics; -using Map = System.Collections.Generic.Dictionary; +using Map = System.Collections.Generic.Dictionary<System.Numerics.Complex, char>; using State = (System.Numerics.Complex pos, System.Numerics.Complex dir); -[ProblemName("Reindeer Maze")] +[ProblemName("Reindeer Maze")] class Solution : Solver { static readonly Complex North = -Complex.ImaginaryOne; @@ -300,8 +300,8 @@

Reindeer Maze

static readonly Complex East = 1; static readonly Complex[] Dirs = { North, East, West, South }; - public object PartOne(string input) => FindDistance(GetMap(input)); - public object PartTwo(string input) => FindBestSpots(GetMap(input)); + public object PartOne(string input) => FindDistance(GetMap(input)); + public object PartTwo(string input) => FindBestSpots(GetMap(input)); int FindDistance(Map map) { var dist = DistancesTo(map, Goal(map)); @@ -316,9 +316,9 @@

Reindeer Maze

// flood fill algorithm determines the best spots by following the shortest paths // using the distance map as guideline. - var q = new PriorityQueue(); + var q = new PriorityQueue<State, int>(); q.Enqueue(start, dist[start]); - var bestSpots = new HashSet { start }; + var bestSpots = new HashSet<State> { start }; while (q.TryDequeue(out var state, out var remainingScore)) { foreach (var (next, score) in Steps(map, state, forward: true)) { @@ -332,15 +332,15 @@

Reindeer Maze

} } } - return bestSpots.DistinctBy(state => state.pos).Count(); + return bestSpots.DistinctBy(state => state.pos).Count(); } - Dictionary DistancesTo(Map map, Complex goal) { - var res = new Dictionary(); + Dictionary<State, int> DistancesTo(Map map, Complex goal) { + var res = new Dictionary<State, int>(); // a flood fill algorithm, works backwards from the goal, and // computes the distances between any location in the map and the goal - var q = new PriorityQueue(); + var q = new PriorityQueue<State, int>(); foreach (var dir in Dirs) { q.Enqueue((goal, dir), 0); res[(goal, dir)] = 0; @@ -352,7 +352,7 @@

Reindeer Maze

} foreach (var (next, score) in Steps(map, state, forward: false)) { var nextCost = totalScore + score; - if (res.ContainsKey(next) && res[next] < nextCost) { + if (res.ContainsKey(next) && res[next] < nextCost) { continue; } @@ -367,11 +367,11 @@

Reindeer Maze

// returns the possible next or previous states and the associated costs for a given state. // in forward mode we scan the possible states from the start state towards the goal. // in backward mode we are working backwards from the goal to the start. - IEnumerable<(State, int cost)> Steps(Map map, State state, bool forward) { + IEnumerable<(State, int cost)> Steps(Map map, State state, bool forward) { foreach (var dir in Dirs) { if (dir == state.dir) { var pos = forward ? state.pos + dir : state.pos - dir; - if (map.GetValueOrDefault(pos) != '#') { + if (map.GetValueOrDefault(pos) != '#') { yield return ((pos, dir), 1); } } else if (dir != -state.dir) { @@ -383,15 +383,15 @@

Reindeer Maze

// store the points in a dictionary so that we can iterate over them and // to easily deal with points outside the area using GetValueOrDefault Map GetMap(string input) { - var map = input.Split("\n"); + var map = input.Split("\n"); return ( from y in Enumerable.Range(0, map.Length) from x in Enumerable.Range(0, map[0].Length) - select new KeyValuePair(Complex.ImaginaryOne * y + x, map[y][x]) + select new KeyValuePair<Complex, char>(Complex.ImaginaryOne * y + x, map[y][x]) ).ToDictionary(); } - Complex Goal(Map map) => map.Keys.Single(k => map[k] == 'E'); - State Start(Map map) => (map.Keys.Single(k => map[k] == 'S'), East); + Complex Goal(Map map) => map.Keys.Single(k => map[k] == 'E'); + State Start(Map map) => (map.Keys.Single(k => map[k] == 'S'), East); }

Please ☆ my repo if you like it!

diff --git a/2024/2/index.html b/2024/2/index.html index dddddaaf..69a7fdd2 100644 --- a/2024/2/index.html +++ b/2024/2/index.html @@ -287,23 +287,23 @@

Red-Nosed Reports

using System.Collections.Generic; using System.Linq; -[ProblemName("Red-Nosed Reports")] +[ProblemName("Red-Nosed Reports")] class Solution : Solver { - public object PartOne(string input) => + public object PartOne(string input) => ParseSamples(input).Count(Valid); - public object PartTwo(string input) => - ParseSamples(input).Count(samples => Attenuate(samples).Any(Valid)); + public object PartTwo(string input) => + ParseSamples(input).Count(samples => Attenuate(samples).Any(Valid)); - IEnumerable ParseSamples(string input) => - from line in input.Split("\n") - let samples = line.Split(" ").Select(int.Parse) + IEnumerable<int[]> ParseSamples(string input) => + from line in input.Split("\n") + let samples = line.Split(" ").Select(int.Parse) select samples.ToArray(); // Generates all possible variations of the input sequence by omitting // either zero or one element from it. - IEnumerable Attenuate(int[] samples) => + IEnumerable<int[]> Attenuate(int[] samples) => from i in Enumerable.Range(0, samples.Length+1) let before = samples.Take(i - 1) let after = samples.Skip(i) @@ -313,8 +313,8 @@

Red-Nosed Reports

bool Valid(int[] samples) { var pairs = Enumerable.Zip(samples, samples.Skip(1)); return - pairs.All(p => 1 <= p.Second - p.First && p.Second - p.First <= 3) || - pairs.All(p => 1 <= p.First - p.Second && p.First - p.Second <= 3); + pairs.All(p => 1 <= p.Second - p.First && p.Second - p.First <= 3) || + pairs.All(p => 1 <= p.First - p.Second && p.First - p.Second <= 3); } } diff --git a/2024/3/index.html b/2024/3/index.html index 0ef78e41..bc667858 100644 --- a/2024/3/index.html +++ b/2024/3/index.html @@ -285,27 +285,27 @@

Mull It Over

using System.Linq; using System.Text.RegularExpressions; -[ProblemName("Mull It Over")] +[ProblemName("Mull It Over")] class Solution : Solver { - public object PartOne(string input) => Solve(input, @"mul\((\d{1,3}),(\d{1,3})\)"); + public object PartOne(string input) => Solve(input, @"mul\((\d{1,3}),(\d{1,3})\)"); - public object PartTwo(string input) => Solve(input, @"mul\((\d{1,3}),(\d{1,3})\)|don't\(\)|do\(\)"); + public object PartTwo(string input) => Solve(input, @"mul\((\d{1,3}),(\d{1,3})\)|don't\(\)|do\(\)"); long Solve(string input, string rx) { // overly functionaly approach... var matches = Regex.Matches(input, rx, RegexOptions.Multiline); return matches.Aggregate( (enabled: true, res: 0L), - (acc, m) => + (acc, m) => (m.Value, acc.res, acc.enabled) switch { - ("don't()", _, _) => (false, acc.res), - ("do()", _, _) => (true, acc.res), - (_, var res, true) => + ("don't()", _, _) => (false, acc.res), + ("do()", _, _) => (true, acc.res), + (_, var res, true) => (true, res + int.Parse(m.Groups[1].Value) * int.Parse(m.Groups[2].Value)), - _ => acc + _ => acc }, - acc => acc.res + acc => acc.res ); } } diff --git a/2024/4/index.html b/2024/4/index.html index 196481e3..386ec132 100644 --- a/2024/4/index.html +++ b/2024/4/index.html @@ -290,9 +290,9 @@

Ceres Search

using System.Numerics; using System.Linq; -using Map = System.Collections.Immutable.ImmutableDictionary; +using Map = System.Collections.Immutable.ImmutableDictionary<System.Numerics.Complex, char>; -[ProblemName("Ceres Search")] +[ProblemName("Ceres Search")] class Solution : Solver { Complex Up = -Complex.ImaginaryOne; @@ -305,7 +305,7 @@

Ceres Search

return ( from pt in mat.Keys from dir in new[] { Right, Right + Down, Down + Left, Down} - where Matches(mat, pt, dir, "XMAS") + where Matches(mat, pt, dir, "XMAS") select 1 ).Count(); } @@ -315,8 +315,8 @@

Ceres Search

return ( from pt in mat.Keys where - Matches(mat, pt + Up + Left, Down + Right, "MAS") && - Matches(mat, pt + Down + Left, Up + Right, "MAS") + Matches(mat, pt + Up + Left, Down + Right, "MAS") && + Matches(mat, pt + Down + Left, Up + Right, "MAS") select 1 ).Count(); } @@ -325,7 +325,7 @@

Ceres Search

// starting from pt bool Matches(Map map, Complex pt, Complex dir, string pattern) { var chars = Enumerable.Range(0, pattern.Length) - .Select(i => map.GetValueOrDefault(pt + i * dir)) + .Select(i => map.GetValueOrDefault(pt + i * dir)) .ToArray(); return Enumerable.SequenceEqual(chars, pattern) || @@ -335,11 +335,11 @@

Ceres Search

// store the points in a dictionary so that we can iterate over them and // to easily deal with points outside the area using GetValueOrDefault Map GetMap(string input) { - var map = input.Split("\n"); + var map = input.Split("\n"); return ( from y in Enumerable.Range(0, map.Length) from x in Enumerable.Range(0, map[0].Length) - select new KeyValuePair(Complex.ImaginaryOne * y + x, map[y][x]) + select new KeyValuePair<Complex, char>(Complex.ImaginaryOne * y + x, map[y][x]) ).ToImmutableDictionary(); } } diff --git a/2024/5/index.html b/2024/5/index.html index 171d4ef0..478503a2 100644 --- a/2024/5/index.html +++ b/2024/5/index.html @@ -287,39 +287,39 @@

Print Queue

using System.Collections.Generic; using System.Linq; -[ProblemName("Print Queue")] +[ProblemName("Print Queue")] class Solution : Solver { public object PartOne(string input) { var (updates, comparer) = Parse(input); return updates - .Where(pages => Sorted(pages, comparer)) + .Where(pages => Sorted(pages, comparer)) .Sum(GetMiddlePage); } public object PartTwo(string input) { var (updates, comparer) = Parse(input); return updates - .Where(pages => !Sorted(pages, comparer)) - .Select(pages => pages.OrderBy(p => p, comparer).ToArray()) + .Where(pages => !Sorted(pages, comparer)) + .Select(pages => pages.OrderBy(p => p, comparer).ToArray()) .Sum(GetMiddlePage); } - (string[][] updates, Comparer) Parse(string input) { - var parts = input.Split("\n\n"); + (string[][] updates, Comparer<string>) Parse(string input) { + var parts = input.Split("\n\n"); - var ordering = new HashSet(parts[0].Split("\n")); + var ordering = new HashSet<string>(parts[0].Split("\n")); var comparer = - Comparer.Create((p1, p2) => ordering.Contains(p1 + "|" + p2) ? -1 : 1); + Comparer<string>.Create((p1, p2) => ordering.Contains(p1 + "|" + p2) ? -1 : 1); - var updates = parts[1].Split("\n").Select(line => line.Split(",")).ToArray(); + var updates = parts[1].Split("\n").Select(line => line.Split(",")).ToArray(); return (updates, comparer); } - int GetMiddlePage(string[] nums) => int.Parse(nums[nums.Length / 2]); + int GetMiddlePage(string[] nums) => int.Parse(nums[nums.Length / 2]); - bool Sorted(string[] pages, Comparer comparer) => - Enumerable.SequenceEqual(pages, pages.OrderBy(x=>x, comparer)); + bool Sorted(string[] pages, Comparer<string> comparer) => + Enumerable.SequenceEqual(pages, pages.OrderBy(x=>x, comparer)); } diff --git a/2024/6/index.html b/2024/6/index.html index 9d414727..de90992b 100644 --- a/2024/6/index.html +++ b/2024/6/index.html @@ -291,9 +291,9 @@

Guard Gallivant

using System.Linq; using System.Numerics; -using Map = System.Collections.Generic.Dictionary; +using Map = System.Collections.Generic.Dictionary<System.Numerics.Complex, char>; -[ProblemName("Guard Gallivant")] +[ProblemName("Guard Gallivant")] class Solution : Solver { Complex Up = Complex.ImaginaryOne; @@ -309,31 +309,31 @@

Guard Gallivant

var positions = Walk(map, start).positions; var loops = 0; // simply try a blocker in each locations visited by the guard and count the loops - foreach (var block in positions.Where(pos => map[pos] == '.')) { - map[block] = '#'; + foreach (var block in positions.Where(pos => map[pos] == '.')) { + map[block] = '#'; if (Walk(map, start).isLoop) { loops++; } - map[block] = '.'; + map[block] = '.'; } return loops; } - // returns the positions visited when starting from 'pos', isLoop is set if the + // returns the positions visited when starting from 'pos', isLoop is set if the // guard enters a cycle. - (IEnumerable positions, bool isLoop) Walk(Map map, Complex pos) { - var seen = new HashSet<(Complex pos, Complex dir)>(); + (IEnumerable<Complex> positions, bool isLoop) Walk(Map map, Complex pos) { + var seen = new HashSet<(Complex pos, Complex dir)>(); var dir = Up; - while (map.ContainsKey(pos) && !seen.Contains((pos, dir))) { + while (map.ContainsKey(pos) && !seen.Contains((pos, dir))) { seen.Add((pos, dir)); - if (map.GetValueOrDefault(pos + dir) == '#') { + if (map.GetValueOrDefault(pos + dir) == '#') { dir *= TurnRight; } else { pos += dir; } } return ( - positions: seen.Select(s => s.pos).Distinct(), + positions: seen.Select(s => s.pos).Distinct(), isLoop: seen.Contains((pos, dir)) ); } @@ -341,14 +341,14 @@

Guard Gallivant

// store the grid in a dictionary, to make bounds checks and navigation simple // start represents the starting postion of the guard (Map map, Complex start) Parse(string input) { - var lines = input.Split("\n"); + var lines = input.Split("\n"); var map = ( from y in Enumerable.Range(0, lines.Length) from x in Enumerable.Range(0, lines[0].Length) - select new KeyValuePair(-Up * y + x, lines[y][x]) + select new KeyValuePair<Complex, char>(-Up * y + x, lines[y][x]) ).ToDictionary(); - var start = map.First(x => x.Value == '^').Key; + var start = map.First(x => x.Value == '^').Key; return (map, start); } diff --git a/2024/7/index.html b/2024/7/index.html index de4eb08d..66620206 100644 --- a/2024/7/index.html +++ b/2024/7/index.html @@ -289,16 +289,16 @@

Bridge Repair

using System.Linq; using System.Text.RegularExpressions; -[ProblemName("Bridge Repair")] +[ProblemName("Bridge Repair")] class Solution : Solver { - public object PartOne(string input) => Filter(input, Check1).Sum(); - public object PartTwo(string input) => Filter(input, Check2).Sum(); + public object PartOne(string input) => Filter(input, Check1).Sum(); + public object PartTwo(string input) => Filter(input, Check2).Sum(); // returns those calibrations that are valid according to the checker - private IEnumerable Filter(string input, Func, bool> check) => - from line in input.Split("\n") - let parts = Regex.Matches(line, @"\d+").Select(m=>long.Parse(m.Value)) + private IEnumerable<long> Filter(string input, Func<long,long,List<long>, bool> check) => + from line in input.Split("\n") + let parts = Regex.Matches(line, @"\d+").Select(m=>long.Parse(m.Value)) let target = parts.First() let nums = parts.Skip(1).ToList() where check(target, nums[0], nums[1..]) @@ -307,18 +307,18 @@

Bridge Repair

// separate checkers provided for the two parts, these recursive functions go // over the numbers and use all allowed operators to update the accumulated result. // at the end of the recursion we simply check if we reached the target - private bool Check1(long target, long acc, List nums) => + private bool Check1(long target, long acc, List<long> nums) => nums switch { - [] => target == acc, - _ => Check1(target, acc * nums[0], nums[1..]) || + [] => target == acc, + _ => Check1(target, acc * nums[0], nums[1..]) || Check1(target, acc + nums[0], nums[1..]) }; - private bool Check2(long target, long acc, List nums) => + private bool Check2(long target, long acc, List<long> nums) => nums switch { - _ when acc > target => false, // optimization: early exit from deadend - [] => target == acc, - _ => Check2(target, long.Parse($"{acc}{nums[0]}"), nums[1..]) || + _ when acc > target => false, // optimization: early exit from deadend + [] => target == acc, + _ => Check2(target, long.Parse($"{acc}{nums[0]}"), nums[1..]) || Check2(target, acc * nums[0], nums[1..]) || Check2(target, acc + nums[0], nums[1..]) }; diff --git a/2024/8/index.html b/2024/8/index.html index 92a6c98e..eeb06ca6 100644 --- a/2024/8/index.html +++ b/2024/8/index.html @@ -291,14 +291,14 @@

Resonant Collinearity

using System.Linq; using System.Numerics; -using Map = System.Collections.Immutable.ImmutableDictionary; +using Map = System.Collections.Immutable.ImmutableDictionary<System.Numerics.Complex, char>; -[ProblemName("Resonant Collinearity")] +[ProblemName("Resonant Collinearity")] class Solution : Solver { - public object PartOne(string input) => GetUniquePositions(input, GetAntinodes1).Count(); - public object PartTwo(string input) => GetUniquePositions(input, GetAntinodes2).Count(); + public object PartOne(string input) => GetUniquePositions(input, GetAntinodes1).Count(); + public object PartTwo(string input) => GetUniquePositions(input, GetAntinodes2).Count(); - HashSet GetUniquePositions(string input, GetAntinodes getAntinodes) { + HashSet<Complex> GetUniquePositions(string input, GetAntinodes getAntinodes) { var map = GetMap(input); var antennaLocations = ( @@ -310,17 +310,17 @@

Resonant Collinearity

return ( from srcAntenna in antennaLocations from dstAntenna in antennaLocations - where srcAntenna != dstAntenna && map[srcAntenna] == map[dstAntenna] + where srcAntenna != dstAntenna && map[srcAntenna] == map[dstAntenna] from antinode in getAntinodes(srcAntenna, dstAntenna, map) select antinode ).ToHashSet(); } // returns the antinode positions of srcAntenna on the dstAntenna side - delegate IEnumerable GetAntinodes(Complex srcAntenna, Complex dstAntenna, Map map); + delegate IEnumerable<Complex> GetAntinodes(Complex srcAntenna, Complex dstAntenna, Map map); // in part 1 we just look at the immediate neighbour - IEnumerable GetAntinodes1(Complex srcAntenna, Complex dstAntenna, Map map) { + IEnumerable<Complex> GetAntinodes1(Complex srcAntenna, Complex dstAntenna, Map map) { var dir = dstAntenna - srcAntenna; var antinote = dstAntenna + dir; if (map.Keys.Contains(antinote)) { @@ -329,7 +329,7 @@

Resonant Collinearity

} // in part 2 this becomes a cycle, plus dstAntenna is also a valid position now - IEnumerable GetAntinodes2(Complex srcAntenna, Complex dstAntenna, Map map) { + IEnumerable<Complex> GetAntinodes2(Complex srcAntenna, Complex dstAntenna, Map map) { var dir = dstAntenna - srcAntenna; var antinote = dstAntenna; while (map.Keys.Contains(antinote)) { @@ -341,11 +341,11 @@

Resonant Collinearity

// store the points in a dictionary so that we can iterate over them and // to easily deal with points outside the area using GetValueOrDefault Map GetMap(string input) { - var map = input.Split("\n"); + var map = input.Split("\n"); return ( from y in Enumerable.Range(0, map.Length) from x in Enumerable.Range(0, map[0].Length) - select new KeyValuePair(x - y * Complex.ImaginaryOne, map[y][x]) + select new KeyValuePair<Complex, char>(x - y * Complex.ImaginaryOne, map[y][x]) ).ToImmutableDictionary(); } } diff --git a/2024/9/index.html b/2024/9/index.html index 7a215cd3..1d7176a9 100644 --- a/2024/9/index.html +++ b/2024/9/index.html @@ -285,16 +285,16 @@

Disk Fragmenter

using System.Linq; -using Fs = System.Collections.Generic.LinkedList; -using Node = System.Collections.Generic.LinkedListNode; +using Fs = System.Collections.Generic.LinkedList<Block>; +using Node = System.Collections.Generic.LinkedListNode<Block>; record struct Block(int fileId, int length) { } -[ProblemName("Disk Fragmenter")] +[ProblemName("Disk Fragmenter")] class Solution : Solver { - public object PartOne(string input) => Checksum(CompactFs(Parse(input), fragmentsEnabled: true)); + public object PartOne(string input) => Checksum(CompactFs(Parse(input), fragmentsEnabled: true)); - public object PartTwo(string input) => Checksum(CompactFs(Parse(input), fragmentsEnabled: false)); + public object PartTwo(string input) => Checksum(CompactFs(Parse(input), fragmentsEnabled: false)); // moves used blocks of the filesystem towards the beginning of the disk using RelocateBlock Fs CompactFs(Fs fs, bool fragmentsEnabled) { @@ -326,13 +326,13 @@

Disk Fragmenter

} else if (i.Value.length == j.Value.length) { (i.Value, j.Value) = (j.Value, i.Value); return; - } else if (i.Value.length > j.Value.length) { + } else if (i.Value.length > j.Value.length) { var d = i.Value.length - j.Value.length; i.Value = j.Value; j.Value = j.Value with { fileId = -1 }; fs.AddAfter(i, new Block(-1, d)); return; - } else if (i.Value.length < j.Value.length && fragmentsEnabled) { + } else if (i.Value.length < j.Value.length && fragmentsEnabled) { var d = j.Value.length - i.Value.length; i.Value = i.Value with { fileId = j.Value.fileId }; j.Value = j.Value with { length = d }; @@ -345,7 +345,7 @@

Disk Fragmenter

var res = 0L; var l = 0; for (var i = fs.First; i != null; i = i.Next) { - for (var k = 0; k < i.Value.length; k++) { + for (var k = 0; k < i.Value.length; k++) { if (i.Value.fileId != -1) { res += l * i.Value.fileId; } @@ -356,7 +356,7 @@

Disk Fragmenter

} Fs Parse(string input) { - return new Fs(input.Select((ch, i) => new Block(i % 2 == 1 ? -1 : i / 2, ch - '0'))); + return new Fs(input.Select((ch, i) => new Block(i % 2 == 1 ? -1 : i / 2, ch - '0'))); } }