From 4b3d0fd0b6d1cd3839cf6cb55d66041e1d466cbb Mon Sep 17 00:00:00 2001 From: "Valeriano A.R." Date: Sat, 2 Dec 2023 18:27:00 +0100 Subject: [PATCH] Code cleanup --- .editorconfig | 33 + .../.idea/codeStyles/codeStyleConfig.xml | 5 + AdventOfCode.sln.DotSettings | 7 + AdventOfCode2017.Tests/Day01_Tests.cs | 193 ++- AdventOfCode2017.Tests/Day02_Tests.cs | 47 +- AdventOfCode2017.Tests/Usings.cs | 1 + AdventOfCode2017/Day01.cs | 144 +- AdventOfCode2017/Day02.cs | 159 +- AdventOfCode2017/Day03.cs | 79 +- AdventOfCode2017/IDay.cs | 13 +- AdventOfCode2017/Program.cs | 41 +- .../ChronoLicenceNode_Tests.cs | 49 +- AdventOfCode2018.Tests/ChronoPoint_Tests.cs | 113 +- AdventOfCode2018.Tests/Claim_Tests.cs | 177 +- AdventOfCode2018.Tests/Day01_Tests.cs | 193 ++- AdventOfCode2018.Tests/Day02_Tests.cs | 63 +- AdventOfCode2018.Tests/Day03_Tests.cs | 47 +- AdventOfCode2018.Tests/Day04_Tests.cs | 203 ++- AdventOfCode2018.Tests/Day05_Tests.cs | 381 +++-- AdventOfCode2018.Tests/Day06_Tests.cs | 60 +- AdventOfCode2018.Tests/Day07_Tests.cs | 63 +- AdventOfCode2018.Tests/Day08_Tests.cs | 31 +- AdventOfCode2018.Tests/Day09_Tests.cs | 87 +- AdventOfCode2018.Tests/Day10_Tests.cs | 180 +- AdventOfCode2018.Tests/Day11_Tests.cs | 123 +- AdventOfCode2018.Tests/Day12_Tests.cs | 53 +- AdventOfCode2018.Tests/Day13_Tests.cs | 91 +- AdventOfCode2018.Tests/Day14_Tests.cs | 173 +- AdventOfCode2018.Tests/Day15_Tests.cs | 423 +++-- AdventOfCode2018.Tests/Day23_Tests.cs | 66 +- AdventOfCode2018.Tests/GuardEvent_Tests.cs | 250 ++- AdventOfCode2018.Tests/MarbleGame_Tests.cs | 99 +- AdventOfCode2018.Tests/Usings.cs | 1 + AdventOfCode2018/Day01.cs | 186 ++- AdventOfCode2018/Day02.cs | 220 ++- AdventOfCode2018/Day03.cs | 304 ++-- AdventOfCode2018/Day04.cs | 485 +++--- AdventOfCode2018/Day05.cs | 232 ++- AdventOfCode2018/Day06.cs | 413 +++-- AdventOfCode2018/Day07.cs | 492 +++--- AdventOfCode2018/Day08.cs | 298 ++-- AdventOfCode2018/Day09.cs | 318 ++-- AdventOfCode2018/Day10.cs | 557 ++++--- AdventOfCode2018/Day11.cs | 396 +++-- AdventOfCode2018/Day12.cs | 476 +++--- AdventOfCode2018/Day13.cs | 934 ++++++----- AdventOfCode2018/Day14.cs | 342 ++-- AdventOfCode2018/Day15.cs | 1464 ++++++++--------- AdventOfCode2018/Day23.cs | 355 ++-- AdventOfCode2018/IDay.cs | 11 +- AdventOfCode2018/Program.cs | 67 +- AdventOfCode2020.Tests/Day01_Tests.cs | 81 +- AdventOfCode2020.Tests/Day02_Tests.cs | 69 +- AdventOfCode2020.Tests/Day03_Tests.cs | 79 +- AdventOfCode2020.Tests/Day04_Tests.cs | 127 +- AdventOfCode2020.Tests/Day05_Tests.cs | 75 +- AdventOfCode2020.Tests/Day06_Tests.cs | 95 +- AdventOfCode2020.Tests/Day07_Tests.cs | 67 +- AdventOfCode2020.Tests/Day08_Tests.cs | 71 +- AdventOfCode2020.Tests/Day09_Tests.cs | 115 +- AdventOfCode2020.Tests/Day10_Tests.cs | 67 +- AdventOfCode2020.Tests/Day11_Tests.cs | 67 +- AdventOfCode2020.Tests/Usings.cs | 1 + AdventOfCode2020/Day01.cs | 81 +- AdventOfCode2020/Day02.cs | 90 +- AdventOfCode2020/Day03.cs | 63 +- AdventOfCode2020/Day04.cs | 262 ++- AdventOfCode2020/Day05.cs | 257 ++- AdventOfCode2020/Day06.cs | 121 +- AdventOfCode2020/Day07.cs | 247 ++- AdventOfCode2020/Day08.cs | 221 ++- AdventOfCode2020/Day09.cs | 133 +- AdventOfCode2020/Day10.cs | 25 +- AdventOfCode2020/Day11.cs | 25 +- AdventOfCode2020/IDay.cs | 13 +- AdventOfCode2020/Program.cs | 107 +- AdventOfCode2023.Tests/Day01_Tests.cs | 4 +- AdventOfCode2023/Day01.cs | 3 +- 78 files changed, 6814 insertions(+), 6950 deletions(-) create mode 100644 .editorconfig create mode 100644 .idea/.idea.AdventOfCode/.idea/codeStyles/codeStyleConfig.xml create mode 100644 AdventOfCode.sln.DotSettings create mode 100644 AdventOfCode2017.Tests/Usings.cs create mode 100644 AdventOfCode2018.Tests/Usings.cs create mode 100644 AdventOfCode2020.Tests/Usings.cs diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f9b4e8c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,33 @@ + +[*] + +# Microsoft .NET properties +csharp_indent_braces = false +csharp_new_line_before_members_in_object_initializers = false +csharp_new_line_before_open_brace = accessors,anonymous_methods,control_blocks,events,indexers,lambdas,local_functions,methods,properties,types +csharp_preferred_modifier_order = private, public, protected, internal, file, new, readonly, abstract, virtual, sealed, static, override, extern, unsafe, volatile, async, required:suggestion +csharp_prefer_braces = true:none +csharp_preserve_single_line_blocks = true +csharp_style_var_elsewhere = false:suggestion +csharp_style_var_for_built_in_types = false:suggestion +csharp_style_var_when_type_is_apparent = false:suggestion +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:none +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:none +dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none + +# ReSharper properties +resharper_accessor_owner_body = accessors_with_block_body +resharper_blank_lines_after_block_statements = 0 +resharper_csharp_max_line_length = 195 +resharper_csharp_remove_blank_lines_near_braces_in_code = false +resharper_instance_members_qualify_declared_in = base_class +resharper_keep_existing_declaration_block_arrangement = false +resharper_max_array_initializer_elements_on_line = 2 +resharper_max_initializer_elements_on_line = 2 +resharper_parentheses_non_obvious_operations = none, multiplicative, additive, arithmetic, shift, bitwise_and, bitwise_exclusive_or, bitwise_inclusive_or, bitwise +resharper_parentheses_redundancy_style = remove +resharper_parentheses_same_type_operations = true +resharper_place_simple_embedded_statement_on_same_line = true +resharper_trailing_comma_in_multiline_lists = true +resharper_wrap_array_initializer_style = chop_always +resharper_wrap_object_and_collection_initializer_style = chop_always diff --git a/.idea/.idea.AdventOfCode/.idea/codeStyles/codeStyleConfig.xml b/.idea/.idea.AdventOfCode/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/.idea.AdventOfCode/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/AdventOfCode.sln.DotSettings b/AdventOfCode.sln.DotSettings new file mode 100644 index 0000000..9747d0b --- /dev/null +++ b/AdventOfCode.sln.DotSettings @@ -0,0 +1,7 @@ + + BFS + ID + VM + VX + VY + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /> \ No newline at end of file diff --git a/AdventOfCode2017.Tests/Day01_Tests.cs b/AdventOfCode2017.Tests/Day01_Tests.cs index 8566739..1fc5b35 100644 --- a/AdventOfCode2017.Tests/Day01_Tests.cs +++ b/AdventOfCode2017.Tests/Day01_Tests.cs @@ -1,105 +1,102 @@ -using Xunit; +namespace AdventOfCode2017.Tests; -namespace AdventOfCode2017.Tests +public class Day01_Tests { - public class Day01_Tests + #region ResolvePart1 + + [Fact] + public void ResolvePart1__Test1() { - #region ResolvePart1 + Day01 day01 = new(); - [Fact] - public void ResolvePart1__Test1() - { - Day01 day01 = new Day01(); + string result = day01.ResolvePart1(new[] { "1122", }); - string result = day01.ResolvePart1(new string[] { "1122", }); - - Assert.Equal("3", result); - } - - [Fact] - public void ResolvePart1__Test2() - { - Day01 day01 = new Day01(); - - string result = day01.ResolvePart1(new string[] { "1111", }); - - Assert.Equal("4", result); - } - - [Fact] - public void ResolvePart1__Test3() - { - Day01 day01 = new Day01(); - - string result = day01.ResolvePart1(new string[] { "1234", }); - - Assert.Equal("0", result); - } - - [Fact] - public void ResolvePart1__Test4() - { - Day01 day01 = new Day01(); - - string result = day01.ResolvePart1(new string[] { "91212129", }); - - Assert.Equal("9", result); - } - - #endregion ResolvePart1 - - #region ResolvePart2 - - [Fact] - public void ResolvePart2__Test1() - { - Day01 day01 = new Day01(); - - string result = day01.ResolvePart2(new string[] { "1212", }); - - Assert.Equal("6", result); - } - - [Fact] - public void ResolvePart2__Test2() - { - Day01 day01 = new Day01(); - - string result = day01.ResolvePart2(new string[] { "1221", }); - - Assert.Equal("0", result); - } - - [Fact] - public void ResolvePart2__Test3() - { - Day01 day01 = new Day01(); - - string result = day01.ResolvePart2(new string[] { "123425", }); - - Assert.Equal("4", result); - } - - [Fact] - public void ResolvePart2__Test4() - { - Day01 day01 = new Day01(); - - string result = day01.ResolvePart2(new string[] { "123123", }); - - Assert.Equal("12", result); - } - - [Fact] - public void ResolvePart2__Test5() - { - Day01 day01 = new Day01(); - - string result = day01.ResolvePart2(new string[] { "12131415", }); - - Assert.Equal("4", result); - } - - #endregion ResolvePart2 + Assert.Equal("3", result); } + + [Fact] + public void ResolvePart1__Test2() + { + Day01 day01 = new(); + + string result = day01.ResolvePart1(new[] { "1111", }); + + Assert.Equal("4", result); + } + + [Fact] + public void ResolvePart1__Test3() + { + Day01 day01 = new(); + + string result = day01.ResolvePart1(new[] { "1234", }); + + Assert.Equal("0", result); + } + + [Fact] + public void ResolvePart1__Test4() + { + Day01 day01 = new(); + + string result = day01.ResolvePart1(new[] { "91212129", }); + + Assert.Equal("9", result); + } + + #endregion ResolvePart1 + + #region ResolvePart2 + + [Fact] + public void ResolvePart2__Test1() + { + Day01 day01 = new(); + + string result = day01.ResolvePart2(new[] { "1212", }); + + Assert.Equal("6", result); + } + + [Fact] + public void ResolvePart2__Test2() + { + Day01 day01 = new(); + + string result = day01.ResolvePart2(new[] { "1221", }); + + Assert.Equal("0", result); + } + + [Fact] + public void ResolvePart2__Test3() + { + Day01 day01 = new(); + + string result = day01.ResolvePart2(new[] { "123425", }); + + Assert.Equal("4", result); + } + + [Fact] + public void ResolvePart2__Test4() + { + Day01 day01 = new(); + + string result = day01.ResolvePart2(new[] { "123123", }); + + Assert.Equal("12", result); + } + + [Fact] + public void ResolvePart2__Test5() + { + Day01 day01 = new(); + + string result = day01.ResolvePart2(new[] { "12131415", }); + + Assert.Equal("4", result); + } + + #endregion ResolvePart2 } \ No newline at end of file diff --git a/AdventOfCode2017.Tests/Day02_Tests.cs b/AdventOfCode2017.Tests/Day02_Tests.cs index ce70b10..c28b107 100644 --- a/AdventOfCode2017.Tests/Day02_Tests.cs +++ b/AdventOfCode2017.Tests/Day02_Tests.cs @@ -1,35 +1,32 @@ -using Xunit; +namespace AdventOfCode2017.Tests; -namespace AdventOfCode2017.Tests +public class Day02_Tests { - public class Day02_Tests + [Fact] + public void ResolvePart1__Test() { - [Fact] - public void ResolvePart1__Test() - { - Day02 day02 = new Day02(); + Day02 day02 = new(); - string result = day02.ResolvePart1(new string[] { - "5 1 9 5", - "7 5 3", - "2 4 6 8", - }); + string result = day02.ResolvePart1(new[] { + "5 1 9 5", + "7 5 3", + "2 4 6 8", + }); - Assert.Equal("18", result); - } + Assert.Equal("18", result); + } - [Fact] - public void ResolvePart2__Test() - { - Day02 day02 = new Day02(); + [Fact] + public void ResolvePart2__Test() + { + Day02 day02 = new(); - string result = day02.ResolvePart2(new string[] { - "5 9 2 8", - "9 4 7 3", - "3 8 6 5", - }); + string result = day02.ResolvePart2(new[] { + "5 9 2 8", + "9 4 7 3", + "3 8 6 5", + }); - Assert.Equal("9", result); - } + Assert.Equal("9", result); } } \ No newline at end of file diff --git a/AdventOfCode2017.Tests/Usings.cs b/AdventOfCode2017.Tests/Usings.cs new file mode 100644 index 0000000..8c927eb --- /dev/null +++ b/AdventOfCode2017.Tests/Usings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file diff --git a/AdventOfCode2017/Day01.cs b/AdventOfCode2017/Day01.cs index 3adaa56..833db54 100644 --- a/AdventOfCode2017/Day01.cs +++ b/AdventOfCode2017/Day01.cs @@ -1,80 +1,78 @@ -namespace AdventOfCode2017 +namespace AdventOfCode2017; +/* + * +--- Day 1: Inverse Captcha --- + +The night before Christmas, one of Santa's Elves calls you in a panic. "The printer's broken! We can't print the Naughty or Nice List!" By the time you make it to sub-basement 17, there are only a few minutes until midnight. "We have a big problem," she says; "there must be almost fifty bugs in this system, but nothing else can print The List. Stand in this square, quick! There's no time to explain; if you can convince them to pay you in stars, you'll be able to--" She pulls a lever and the world goes blurry. + +When your eyes can focus again, everything seems a lot more pixelated than before. She must have sent you inside the computer! You check the system clock: 25 milliseconds until midnight. With that much time, you should be able to collect all fifty stars by December 25th. + +Collect stars by solving puzzles. Two puzzles will be made available on each day millisecond in the advent calendar; the second puzzle is unlocked when you complete the first. Each puzzle grants one star. Good luck! + +You're standing in a room with "digitization quarantine" written in LEDs along one wall. The only door is locked, but it includes a small interface. "Restricted Area - Strictly No Digitized Users Allowed." + +It goes on to explain that you may only leave by solving a captcha to prove you're not a human. Apparently, you only get one millisecond to solve the captcha: too fast for a normal human, but it feels like hours to you. + +The captcha requires you to review a sequence of digits (your puzzle input) and find the sum of all digits that match the next digit in the list. The list is circular, so the digit after the last digit is the first digit in the list. + +For example: + + 1122 produces a sum of 3 (1 + 2) because the first digit (1) matches the second digit and the third digit (2) matches the fourth digit. + 1111 produces 4 because each digit (all 1) matches the next. + 1234 produces 0 because no digit matches the next. + 91212129 produces 9 because the only digit that matches the next one is the last digit, 9. + +What is the solution to your captcha? + +--- Part Two --- + +You notice a progress bar that jumps to 50% completion. Apparently, the door isn't yet satisfied, but it did emit a star as encouragement. The instructions change: + +Now, instead of considering the next digit, it wants you to consider the digit halfway around the circular list. That is, if your list contains 10 items, only include a digit in your sum if the digit 10/2 = 5 steps forward matches it. Fortunately, your list has an even number of elements. + +For example: + + 1212 produces 6: the list contains 4 items, and all four digits match the digit 2 items ahead. + 1221 produces 0, because every comparison is between a 1 and a 2. + 123425 produces 4, because both 2s match each other, but no other digit has a match. + 123123 produces 12. + 12131415 produces 4. + +What is the solution to your new captcha? + +*/ + +public class Day01 : IDay { - /* - * - --- Day 1: Inverse Captcha --- - - The night before Christmas, one of Santa's Elves calls you in a panic. "The printer's broken! We can't print the Naughty or Nice List!" By the time you make it to sub-basement 17, there are only a few minutes until midnight. "We have a big problem," she says; "there must be almost fifty bugs in this system, but nothing else can print The List. Stand in this square, quick! There's no time to explain; if you can convince them to pay you in stars, you'll be able to--" She pulls a lever and the world goes blurry. - - When your eyes can focus again, everything seems a lot more pixelated than before. She must have sent you inside the computer! You check the system clock: 25 milliseconds until midnight. With that much time, you should be able to collect all fifty stars by December 25th. - - Collect stars by solving puzzles. Two puzzles will be made available on each day millisecond in the advent calendar; the second puzzle is unlocked when you complete the first. Each puzzle grants one star. Good luck! - - You're standing in a room with "digitization quarantine" written in LEDs along one wall. The only door is locked, but it includes a small interface. "Restricted Area - Strictly No Digitized Users Allowed." - - It goes on to explain that you may only leave by solving a captcha to prove you're not a human. Apparently, you only get one millisecond to solve the captcha: too fast for a normal human, but it feels like hours to you. - - The captcha requires you to review a sequence of digits (your puzzle input) and find the sum of all digits that match the next digit in the list. The list is circular, so the digit after the last digit is the first digit in the list. - - For example: - - 1122 produces a sum of 3 (1 + 2) because the first digit (1) matches the second digit and the third digit (2) matches the fourth digit. - 1111 produces 4 because each digit (all 1) matches the next. - 1234 produces 0 because no digit matches the next. - 91212129 produces 9 because the only digit that matches the next one is the last digit, 9. - - What is the solution to your captcha? - - --- Part Two --- - - You notice a progress bar that jumps to 50% completion. Apparently, the door isn't yet satisfied, but it did emit a star as encouragement. The instructions change: - - Now, instead of considering the next digit, it wants you to consider the digit halfway around the circular list. That is, if your list contains 10 items, only include a digit in your sum if the digit 10/2 = 5 steps forward matches it. Fortunately, your list has an even number of elements. - - For example: - - 1212 produces 6: the list contains 4 items, and all four digits match the digit 2 items ahead. - 1221 produces 0, because every comparison is between a 1 and a 2. - 123425 produces 4, because both 2s match each other, but no other digit has a match. - 123123 produces 12. - 12131415 produces 4. - - What is the solution to your new captcha? - - */ - - public class Day01 : IDay + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) + string input = inputs[0]; + int value = 0; + for(int i = 0; i < input.Length; i++) { - string input = inputs[0]; - int value = 0; - for(int i = 0; i < input.Length; i++) + int nextI = (i + 1) % input.Length; + if(input[i] == input[nextI]) { - int nextI = (i + 1) % input.Length; - if(input[i] == input[nextI]) - { - value += (input[i] - '0'); - } + value += (input[i] - '0'); } - return value.ToString(); - } - - public string ResolvePart2(string[] inputs) - { - string input = inputs[0]; - int value = 0; - int inputLength = input.Length; - int inputHalfLength = inputLength / 2; - for (int i = 0; i < inputLength; i++) - { - int nextI = (i + inputHalfLength) % inputLength; - if (input[i] == input[nextI]) - { - value += (input[i] - '0'); - } - } - return value.ToString(); } + return value.ToString(); } -} + + public string ResolvePart2(string[] inputs) + { + string input = inputs[0]; + int value = 0; + int inputLength = input.Length; + int inputHalfLength = inputLength / 2; + for (int i = 0; i < inputLength; i++) + { + int nextI = (i + inputHalfLength) % inputLength; + if (input[i] == input[nextI]) + { + value += (input[i] - '0'); + } + } + return value.ToString(); + } +} \ No newline at end of file diff --git a/AdventOfCode2017/Day02.cs b/AdventOfCode2017/Day02.cs index 07d790b..da30836 100644 --- a/AdventOfCode2017/Day02.cs +++ b/AdventOfCode2017/Day02.cs @@ -1,99 +1,94 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace AdventOfCode2017 +namespace AdventOfCode2017; +/* + +--- Day 2: Corruption Checksum --- + +As you walk through the door, a glowing humanoid shape yells in your direction. "You there! Your state appears to be idle. Come help us repair the corruption in this spreadsheet - if we take another millisecond, we'll have to display an hourglass cursor!" + +The spreadsheet consists of rows of apparently-random numbers. To make sure the recovery process is on the right track, they need you to calculate the spreadsheet's checksum. For each row, determine the difference between the largest value and the smallest value; the checksum is the sum of all of these differences. + +For example, given the following spreadsheet: + +5 1 9 5 +7 5 3 +2 4 6 8 + + The first row's largest and smallest values are 9 and 1, and their difference is 8. + The second row's largest and smallest values are 7 and 3, and their difference is 4. + The third row's difference is 6. + +In this example, the spreadsheet's checksum would be 8 + 4 + 6 = 18. + +What is the checksum for the spreadsheet in your puzzle input? + +--- Part Two --- + +"Great work; looks like we're on the right track after all. Here's a star for your effort." However, the program seems a little worried. Can programs be worried? + +"Based on what we're seeing, it looks like all the User wanted is some information about the evenly divisible values in the spreadsheet. Unfortunately, none of us are equipped for that kind of calculation - most of us specialize in bitwise operations." + +It sounds like the goal is to find the only two numbers in each row where one evenly divides the other - that is, where the result of the division operation is a whole number. They would like you to find those numbers on each line, divide them, and add up each line's result. + +For example, given the following spreadsheet: + +5 9 2 8 +9 4 7 3 +3 8 6 5 + + In the first row, the only two numbers that evenly divide are 8 and 2; the result of this division is 4. + In the second row, the two numbers are 9 and 3; the result is 3. + In the third row, the result is 2. + +In this example, the sum of the results would be 4 + 3 + 2 = 9. + +What is the sum of each row's result in your puzzle input? + +*/ + +public class Day02 : IDay { - /* - - --- Day 2: Corruption Checksum --- - - As you walk through the door, a glowing humanoid shape yells in your direction. "You there! Your state appears to be idle. Come help us repair the corruption in this spreadsheet - if we take another millisecond, we'll have to display an hourglass cursor!" - - The spreadsheet consists of rows of apparently-random numbers. To make sure the recovery process is on the right track, they need you to calculate the spreadsheet's checksum. For each row, determine the difference between the largest value and the smallest value; the checksum is the sum of all of these differences. - - For example, given the following spreadsheet: - - 5 1 9 5 - 7 5 3 - 2 4 6 8 - - The first row's largest and smallest values are 9 and 1, and their difference is 8. - The second row's largest and smallest values are 7 and 3, and their difference is 4. - The third row's difference is 6. - - In this example, the spreadsheet's checksum would be 8 + 4 + 6 = 18. - - What is the checksum for the spreadsheet in your puzzle input? - - --- Part Two --- - - "Great work; looks like we're on the right track after all. Here's a star for your effort." However, the program seems a little worried. Can programs be worried? - - "Based on what we're seeing, it looks like all the User wanted is some information about the evenly divisible values in the spreadsheet. Unfortunately, none of us are equipped for that kind of calculation - most of us specialize in bitwise operations." - - It sounds like the goal is to find the only two numbers in each row where one evenly divides the other - that is, where the result of the division operation is a whole number. They would like you to find those numbers on each line, divide them, and add up each line's result. - - For example, given the following spreadsheet: - - 5 9 2 8 - 9 4 7 3 - 3 8 6 5 - - In the first row, the only two numbers that evenly divide are 8 and 2; the result of this division is 4. - In the second row, the two numbers are 9 and 3; the result is 3. - In the third row, the result is 2. - - In this example, the sum of the results would be 4 + 3 + 2 = 9. - - What is the sum of each row's result in your puzzle input? - - */ - - public class Day02 : IDay + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) + int checksum = 0; + foreach(string input in inputs) { - int checksum = 0; - foreach(string input in inputs) - { - int[] row = input - .Split(new string[] { " ", " " }, StringSplitOptions.RemoveEmptyEntries) - .Select(cell => Convert.ToInt32(cell)) - .ToArray(); - int max = row.Max(); - int min = row.Min(); - checksum += (max - min); - } - return checksum.ToString(); + int[] row = input + .Split(new[] { " ", " " }, StringSplitOptions.RemoveEmptyEntries) + .Select(cell => Convert.ToInt32(cell)) + .ToArray(); + int max = row.Max(); + int min = row.Min(); + checksum += (max - min); } + return checksum.ToString(); + } - public string ResolvePart2(string[] inputs) + public string ResolvePart2(string[] inputs) + { + int checksum = 0; + foreach (string input in inputs) { - int checksum = 0; - foreach (string input in inputs) - { - int[] row = input - .Split(new string[] { " ", " " }, StringSplitOptions.RemoveEmptyEntries) - .Select(cell => Convert.ToInt32(cell)) - .ToArray(); + int[] row = input + .Split(new[] { " ", " " }, StringSplitOptions.RemoveEmptyEntries) + .Select(cell => Convert.ToInt32(cell)) + .ToArray(); - for (int i = 0; i < (row.Length - 1); i++) + for (int i = 0; i < (row.Length - 1); i++) + { + for (int j = i + 1; j < row.Length; j++) { - for (int j = i + 1; j < row.Length; j++) + int max = Math.Max(row[i], row[j]); + int min = Math.Min(row[i], row[j]); + if ((max % min) == 0) { - int max = Math.Max(row[i], row[j]); - int min = Math.Min(row[i], row[j]); - if ((max % min) == 0) - { - checksum += (max / min); - } + checksum += (max / min); } } } - return checksum.ToString(); } + return checksum.ToString(); } -} +} \ No newline at end of file diff --git a/AdventOfCode2017/Day03.cs b/AdventOfCode2017/Day03.cs index 21ef38e..ae02610 100644 --- a/AdventOfCode2017/Day03.cs +++ b/AdventOfCode2017/Day03.cs @@ -1,47 +1,40 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace AdventOfCode2017; -namespace AdventOfCode2017 +/* + * +--- Day 3: Spiral Memory --- + +You come across an experimental new kind of memory stored on an infinite two-dimensional grid. + +Each square on the grid is allocated in a spiral pattern starting at a location marked 1 and then counting up while spiraling outward. For example, the first few squares are allocated like this: + +17 16 15 14 13 +18 5 4 3 12 +19 6 1 2 11 +20 7 8 9 10 +21 22 23---> ... + +While this is very space-efficient (no squares are skipped), requested data must be carried back to square 1 (the location of the only access port for this memory system) by programs that can only move up, down, left, or right. They always take the shortest path: the Manhattan Distance between the location of the data and square 1. + +For example: + + Data from square 1 is carried 0 steps, since it's at the access port. + Data from square 12 is carried 3 steps, such as: down, left, left. + Data from square 23 is carried only 2 steps: up twice. + Data from square 1024 must be carried 31 steps. + +How many steps are required to carry the data from the square identified in your puzzle input all the way to the access port? + +*/ +public class Day03 : IDay { - /* - * - --- Day 3: Spiral Memory --- - - You come across an experimental new kind of memory stored on an infinite two-dimensional grid. - - Each square on the grid is allocated in a spiral pattern starting at a location marked 1 and then counting up while spiraling outward. For example, the first few squares are allocated like this: - - 17 16 15 14 13 - 18 5 4 3 12 - 19 6 1 2 11 - 20 7 8 9 10 - 21 22 23---> ... - - While this is very space-efficient (no squares are skipped), requested data must be carried back to square 1 (the location of the only access port for this memory system) by programs that can only move up, down, left, or right. They always take the shortest path: the Manhattan Distance between the location of the data and square 1. - - For example: - - Data from square 1 is carried 0 steps, since it's at the access port. - Data from square 12 is carried 3 steps, such as: down, left, left. - Data from square 23 is carried only 2 steps: up twice. - Data from square 1024 must be carried 31 steps. - - How many steps are required to carry the data from the square identified in your puzzle input all the way to the access port? - - */ - public class Day03 : IDay + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) - { - return null; - } - - public string ResolvePart2(string[] inputs) - { - return null; - } + return null; } -} + + public string ResolvePart2(string[] inputs) + { + return null; + } +} \ No newline at end of file diff --git a/AdventOfCode2017/IDay.cs b/AdventOfCode2017/IDay.cs index abd4c8c..906ca49 100644 --- a/AdventOfCode2017/IDay.cs +++ b/AdventOfCode2017/IDay.cs @@ -1,8 +1,7 @@ -namespace AdventOfCode2017 +namespace AdventOfCode2017; + +public interface IDay { - public interface IDay - { - string ResolvePart1(string[] inputs); - string ResolvePart2(string[] inputs); - } -} + string ResolvePart1(string[] inputs); + string ResolvePart2(string[] inputs); +} \ No newline at end of file diff --git a/AdventOfCode2017/Program.cs b/AdventOfCode2017/Program.cs index 1809437..995f607 100644 --- a/AdventOfCode2017/Program.cs +++ b/AdventOfCode2017/Program.cs @@ -1,29 +1,28 @@ using System; using System.IO; -namespace AdventOfCode2017 +namespace AdventOfCode2017; + +public class Program { - public class Program + private static void Main() { - private static void Main(string[] args) + int currentDayNumber = 3; + IDay currentDay = null; + + switch (currentDayNumber) { - int currentDayNumber = 3; - IDay currentDay = null; - - switch (currentDayNumber) - { - case 1: currentDay = new Day01(); break; - case 2: currentDay = new Day02(); break; - case 3: currentDay = new Day03(); break; - } - - string[] linesDay = File.ReadAllLines(string.Format("inputs/Day{0:00}.txt", currentDayNumber)); - string resultPart1 = currentDay.ResolvePart1(linesDay); - Console.WriteLine("Day{1:00} Result Part1: {0}", resultPart1, currentDayNumber); - string resultPart2 = currentDay.ResolvePart2(linesDay); - Console.WriteLine("Day{1:00} Result Part2: {0}", resultPart2, currentDayNumber); - - Console.Read(); + case 1: currentDay = new Day01(); break; + case 2: currentDay = new Day02(); break; + case 3: currentDay = new Day03(); break; } + + string[] linesDay = File.ReadAllLines($"inputs/Day{currentDayNumber:00}.txt"); + string resultPart1 = currentDay.ResolvePart1(linesDay); + Console.WriteLine("Day{1:00} Result Part1: {0}", resultPart1, currentDayNumber); + string resultPart2 = currentDay.ResolvePart2(linesDay); + Console.WriteLine("Day{1:00} Result Part2: {0}", resultPart2, currentDayNumber); + + Console.Read(); } -} +} \ No newline at end of file diff --git a/AdventOfCode2018.Tests/ChronoLicenceNode_Tests.cs b/AdventOfCode2018.Tests/ChronoLicenceNode_Tests.cs index e7be7e7..14e063e 100644 --- a/AdventOfCode2018.Tests/ChronoLicenceNode_Tests.cs +++ b/AdventOfCode2018.Tests/ChronoLicenceNode_Tests.cs @@ -1,36 +1,31 @@ -using Xunit; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class ChronoLicenceNode_Tests { - public class ChronoLicenceNode_Tests + [Fact] + public void BuildFromIntStream__Test() { - [Fact] - public void BuildFromIntStream__Test() - { - Day08 day = new Day08(); + IntStream values = new("2 3 0 3 10 11 12 1 1 0 1 99 2 1 1 2"); + ChronoLicenceNode result = ChronoLicenceNode.BuildFromIntStream(values); - IntStream values = new IntStream("2 3 0 3 10 11 12 1 1 0 1 99 2 1 1 2"); - ChronoLicenceNode result = ChronoLicenceNode.BuildFromIntStream(values); + Assert.Equal(2, result.Childs.Count); + Assert.Equal(3, result.Metadata.Count); + Assert.Equal(1, result.Metadata[0]); + Assert.Equal(1, result.Metadata[1]); + Assert.Equal(2, result.Metadata[2]); - Assert.Equal(2, result.Childs.Count); - Assert.Equal(3, result.Metadata.Count); - Assert.Equal(1, result.Metadata[0]); - Assert.Equal(1, result.Metadata[1]); - Assert.Equal(2, result.Metadata[2]); + Assert.Empty(result.Childs[0].Childs); + Assert.Equal(3, result.Childs[0].Metadata.Count); + Assert.Equal(10, result.Childs[0].Metadata[0]); + Assert.Equal(11, result.Childs[0].Metadata[1]); + Assert.Equal(12, result.Childs[0].Metadata[2]); - Assert.Equal(0, result.Childs[0].Childs.Count); - Assert.Equal(3, result.Childs[0].Metadata.Count); - Assert.Equal(10, result.Childs[0].Metadata[0]); - Assert.Equal(11, result.Childs[0].Metadata[1]); - Assert.Equal(12, result.Childs[0].Metadata[2]); + Assert.Single(result.Childs[1].Childs); + Assert.Single(result.Childs[1].Metadata); + Assert.Equal(2, result.Childs[1].Metadata[0]); - Assert.Equal(1, result.Childs[1].Childs.Count); - Assert.Equal(1, result.Childs[1].Metadata.Count); - Assert.Equal(2, result.Childs[1].Metadata[0]); - - Assert.Equal(0, result.Childs[1].Childs[0].Childs.Count); - Assert.Equal(1, result.Childs[1].Childs[0].Metadata.Count); - Assert.Equal(99, result.Childs[1].Childs[0].Metadata[0]); - } + Assert.Empty(result.Childs[1].Childs[0].Childs); + Assert.Single(result.Childs[1].Childs[0].Metadata); + Assert.Equal(99, result.Childs[1].Childs[0].Metadata[0]); } } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/ChronoPoint_Tests.cs b/AdventOfCode2018.Tests/ChronoPoint_Tests.cs index 133c582..2413117 100644 --- a/AdventOfCode2018.Tests/ChronoPoint_Tests.cs +++ b/AdventOfCode2018.Tests/ChronoPoint_Tests.cs @@ -1,64 +1,61 @@ -using Xunit; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class ChronoPoint_Tests { - public class ChronoPoint_Tests + #region FromString + + [Fact] + public void FromString__Test1() { - #region FromString + ChronoPoint point = ChronoPoint.FromString("1, 1"); - [Fact] - public void FromString__Test1() - { - ChronoPoint point = ChronoPoint.FromString("1, 1"); - - Assert.Equal(1, point.X); - Assert.Equal(1, point.Y); - } - - [Fact] - public void FromString__Test2() - { - ChronoPoint point = ChronoPoint.FromString("1, 6"); - - Assert.Equal(1, point.X); - Assert.Equal(6, point.Y); - } - - [Fact] - public void FromString__Test3() - { - ChronoPoint point = ChronoPoint.FromString("8, 9"); - - Assert.Equal(8, point.X); - Assert.Equal(9, point.Y); - } - - #endregion FromString - - #region ManhattanDistance - - [Fact] - public void ManhattanDistance__Test1() - { - ChronoPoint p0 = ChronoPoint.FromString("8, 9"); - ChronoPoint p1 = ChronoPoint.FromString("1, 6"); - - int distance = ChronoPoint.ManhattanDistance(p0, p1); - - Assert.Equal(10, distance); - } - - [Fact] - public void ManhattanDistance__Test2() - { - ChronoPoint p0 = ChronoPoint.FromString("1, 1"); - ChronoPoint p1 = ChronoPoint.FromString("1, 6"); - - int distance = ChronoPoint.ManhattanDistance(p0, p1); - - Assert.Equal(5, distance); - } - - #endregion ManhattanDistance + Assert.Equal(1, point.X); + Assert.Equal(1, point.Y); } + + [Fact] + public void FromString__Test2() + { + ChronoPoint point = ChronoPoint.FromString("1, 6"); + + Assert.Equal(1, point.X); + Assert.Equal(6, point.Y); + } + + [Fact] + public void FromString__Test3() + { + ChronoPoint point = ChronoPoint.FromString("8, 9"); + + Assert.Equal(8, point.X); + Assert.Equal(9, point.Y); + } + + #endregion FromString + + #region ManhattanDistance + + [Fact] + public void ManhattanDistance__Test1() + { + ChronoPoint p0 = ChronoPoint.FromString("8, 9"); + ChronoPoint p1 = ChronoPoint.FromString("1, 6"); + + int distance = ChronoPoint.ManhattanDistance(p0, p1); + + Assert.Equal(10, distance); + } + + [Fact] + public void ManhattanDistance__Test2() + { + ChronoPoint p0 = ChronoPoint.FromString("1, 1"); + ChronoPoint p1 = ChronoPoint.FromString("1, 6"); + + int distance = ChronoPoint.ManhattanDistance(p0, p1); + + Assert.Equal(5, distance); + } + + #endregion ManhattanDistance } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/Claim_Tests.cs b/AdventOfCode2018.Tests/Claim_Tests.cs index fce2cd9..6a9f296 100644 --- a/AdventOfCode2018.Tests/Claim_Tests.cs +++ b/AdventOfCode2018.Tests/Claim_Tests.cs @@ -1,96 +1,93 @@ -using Xunit; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class Claim_Tests { - public class Claim_Tests + #region FromString + + [Fact] + public void FromString__Test1() { - #region FromString + Day03.Claim claim = Day03.Claim.FromString("#123 @ 3,2: 5x4"); - [Fact] - public void FromString__Test1() - { - Day03.Claim claim = Day03.Claim.FromString("#123 @ 3,2: 5x4"); - - Assert.Equal(123, claim.ID); - Assert.Equal(3, claim.Left); - Assert.Equal(2, claim.Top); - Assert.Equal(5, claim.Width); - Assert.Equal(4, claim.Height); - } - - [Fact] - public void FromString__Test2() - { - Day03.Claim claim = Day03.Claim.FromString("#1 @ 1,3: 4x4"); - - Assert.Equal(1, claim.ID); - Assert.Equal(1, claim.Left); - Assert.Equal(3, claim.Top); - Assert.Equal(4, claim.Width); - Assert.Equal(4, claim.Height); - } - - [Fact] - public void FromString__Test3() - { - Day03.Claim claim = Day03.Claim.FromString("#2 @ 3,1: 4x4"); - - Assert.Equal(2, claim.ID); - Assert.Equal(3, claim.Left); - Assert.Equal(1, claim.Top); - Assert.Equal(4, claim.Width); - Assert.Equal(4, claim.Height); - } - - [Fact] - public void FromString__Test4() - { - Day03.Claim claim = Day03.Claim.FromString("#3 @ 5,5: 2x2"); - - Assert.Equal(3, claim.ID); - Assert.Equal(5, claim.Left); - Assert.Equal(5, claim.Top); - Assert.Equal(2, claim.Width); - Assert.Equal(2, claim.Height); - } - - #endregion FromString - - #region Overlaps - - [Fact] - public void Overlaps__Test1() - { - Day03.Claim claim1 = Day03.Claim.FromString("#1 @ 1,3: 4x4"); - Day03.Claim claim2 = Day03.Claim.FromString("#3 @ 5,5: 2x2"); - - bool result = Day03.Claim.Overlaps(claim1, claim2); - - Assert.Equal(false, result); - } - - [Fact] - public void Overlaps__Test2() - { - Day03.Claim claim1 = Day03.Claim.FromString("#2 @ 3,1: 4x4"); - Day03.Claim claim2 = Day03.Claim.FromString("#3 @ 5,5: 2x2"); - - bool result = Day03.Claim.Overlaps(claim1, claim2); - - Assert.Equal(false, result); - } - - [Fact] - public void Overlaps__Test3() - { - Day03.Claim claim1 = Day03.Claim.FromString("#1 @ 1,3: 4x4"); - Day03.Claim claim2 = Day03.Claim.FromString("#2 @ 3,1: 4x4"); - - bool result = Day03.Claim.Overlaps(claim1, claim2); - - Assert.Equal(true, result); - } - - #endregion Overlaps + Assert.Equal(123, claim.ID); + Assert.Equal(3, claim.Left); + Assert.Equal(2, claim.Top); + Assert.Equal(5, claim.Width); + Assert.Equal(4, claim.Height); } + + [Fact] + public void FromString__Test2() + { + Day03.Claim claim = Day03.Claim.FromString("#1 @ 1,3: 4x4"); + + Assert.Equal(1, claim.ID); + Assert.Equal(1, claim.Left); + Assert.Equal(3, claim.Top); + Assert.Equal(4, claim.Width); + Assert.Equal(4, claim.Height); + } + + [Fact] + public void FromString__Test3() + { + Day03.Claim claim = Day03.Claim.FromString("#2 @ 3,1: 4x4"); + + Assert.Equal(2, claim.ID); + Assert.Equal(3, claim.Left); + Assert.Equal(1, claim.Top); + Assert.Equal(4, claim.Width); + Assert.Equal(4, claim.Height); + } + + [Fact] + public void FromString__Test4() + { + Day03.Claim claim = Day03.Claim.FromString("#3 @ 5,5: 2x2"); + + Assert.Equal(3, claim.ID); + Assert.Equal(5, claim.Left); + Assert.Equal(5, claim.Top); + Assert.Equal(2, claim.Width); + Assert.Equal(2, claim.Height); + } + + #endregion FromString + + #region Overlaps + + [Fact] + public void Overlaps__Test1() + { + Day03.Claim claim1 = Day03.Claim.FromString("#1 @ 1,3: 4x4"); + Day03.Claim claim2 = Day03.Claim.FromString("#3 @ 5,5: 2x2"); + + bool result = Day03.Claim.Overlaps(claim1, claim2); + + Assert.False(result); + } + + [Fact] + public void Overlaps__Test2() + { + Day03.Claim claim1 = Day03.Claim.FromString("#2 @ 3,1: 4x4"); + Day03.Claim claim2 = Day03.Claim.FromString("#3 @ 5,5: 2x2"); + + bool result = Day03.Claim.Overlaps(claim1, claim2); + + Assert.False(result); + } + + [Fact] + public void Overlaps__Test3() + { + Day03.Claim claim1 = Day03.Claim.FromString("#1 @ 1,3: 4x4"); + Day03.Claim claim2 = Day03.Claim.FromString("#2 @ 3,1: 4x4"); + + bool result = Day03.Claim.Overlaps(claim1, claim2); + + Assert.True(result); + } + + #endregion Overlaps } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/Day01_Tests.cs b/AdventOfCode2018.Tests/Day01_Tests.cs index 8902a15..f9e27b0 100644 --- a/AdventOfCode2018.Tests/Day01_Tests.cs +++ b/AdventOfCode2018.Tests/Day01_Tests.cs @@ -1,105 +1,102 @@ -using Xunit; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class Day01_Tests { - public class Day01_Tests + #region ResolvePart1 + + [Fact] + public void ResolvePart1__Test1() { - #region ResolvePart1 + Day01 day01 = new(); - [Fact] - public void ResolvePart1__Test1() - { - Day01 day01 = new Day01(); + string result = day01.ResolvePart1(new[] { "+1", "-2", "+3", "+1", }); - string result = day01.ResolvePart1(new string[] { "+1", "-2", "+3", "+1", }); - - Assert.Equal("3", result); - } - - [Fact] - public void ResolvePart1__Test2() - { - Day01 day01 = new Day01(); - - string result = day01.ResolvePart1(new string[] { "+1", "+1", "+1", }); - - Assert.Equal("3", result); - } - - [Fact] - public void ResolvePart1__Test3() - { - Day01 day01 = new Day01(); - - string result = day01.ResolvePart1(new string[] { "+1", "+1", "-2", }); - - Assert.Equal("0", result); - } - - [Fact] - public void ResolvePart1__Test4() - { - Day01 day01 = new Day01(); - - string result = day01.ResolvePart1(new string[] { "-1", "-2", "-3", }); - - Assert.Equal("-6", result); - } - - #endregion ResolveDay01 - - #region ResolvePart2 - - [Fact] - public void ResolvePart2__Test1() - { - Day01 day01 = new Day01(); - - string result = day01.ResolvePart2(new string[] { "+1", "-2", "+3", "+1", }); - - Assert.Equal("2", result); - } - - [Fact] - public void ResolvePart2__Test2() - { - Day01 day01 = new Day01(); - - string result = day01.ResolvePart2(new string[] { "+1", "-1", }); - - Assert.Equal("0", result); - } - - [Fact] - public void ResolvePart2__Test3() - { - Day01 day01 = new Day01(); - - string result = day01.ResolvePart2(new string[] { "+3", "+3", "+4", "-2", "-4", }); - - Assert.Equal("10", result); - } - - [Fact] - public void ResolvePart2__Test4() - { - Day01 day01 = new Day01(); - - string result = day01.ResolvePart2(new string[] { "-6", "+3", "+8", "+5", "-6", }); - - Assert.Equal("5", result); - } - - [Fact] - public void ResolvePart2__Test5() - { - Day01 day01 = new Day01(); - - string result = day01.ResolvePart2(new string[] { "+7", "+7", "-2", "-7", "-4", }); - - Assert.Equal("14", result); - } - - #endregion ResolvePart2 + Assert.Equal("3", result); } + + [Fact] + public void ResolvePart1__Test2() + { + Day01 day01 = new(); + + string result = day01.ResolvePart1(new[] { "+1", "+1", "+1", }); + + Assert.Equal("3", result); + } + + [Fact] + public void ResolvePart1__Test3() + { + Day01 day01 = new(); + + string result = day01.ResolvePart1(new[] { "+1", "+1", "-2", }); + + Assert.Equal("0", result); + } + + [Fact] + public void ResolvePart1__Test4() + { + Day01 day01 = new(); + + string result = day01.ResolvePart1(new[] { "-1", "-2", "-3", }); + + Assert.Equal("-6", result); + } + + #endregion ResolveDay01 + + #region ResolvePart2 + + [Fact] + public void ResolvePart2__Test1() + { + Day01 day01 = new(); + + string result = day01.ResolvePart2(new[] { "+1", "-2", "+3", "+1", }); + + Assert.Equal("2", result); + } + + [Fact] + public void ResolvePart2__Test2() + { + Day01 day01 = new(); + + string result = day01.ResolvePart2(new[] { "+1", "-1", }); + + Assert.Equal("0", result); + } + + [Fact] + public void ResolvePart2__Test3() + { + Day01 day01 = new(); + + string result = day01.ResolvePart2(new[] { "+3", "+3", "+4", "-2", "-4", }); + + Assert.Equal("10", result); + } + + [Fact] + public void ResolvePart2__Test4() + { + Day01 day01 = new(); + + string result = day01.ResolvePart2(new[] { "-6", "+3", "+8", "+5", "-6", }); + + Assert.Equal("5", result); + } + + [Fact] + public void ResolvePart2__Test5() + { + Day01 day01 = new(); + + string result = day01.ResolvePart2(new[] { "+7", "+7", "-2", "-7", "-4", }); + + Assert.Equal("14", result); + } + + #endregion ResolvePart2 } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/Day02_Tests.cs b/AdventOfCode2018.Tests/Day02_Tests.cs index 2fe53bb..a7b288c 100644 --- a/AdventOfCode2018.Tests/Day02_Tests.cs +++ b/AdventOfCode2018.Tests/Day02_Tests.cs @@ -1,43 +1,40 @@ -using Xunit; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class Day02_Tests { - public class Day02_Tests + [Fact] + public void ResolvePart1__Test1() { - [Fact] - public void ResolvePart1__Test1() - { - Day02 day02 = new Day02(); + Day02 day02 = new(); - string result = day02.ResolvePart1(new string[] { - "abcdef", - "bababc", - "abbcde", - "abcccd", - "aabcdd", - "abcdee", - "ababab", - }); + string result = day02.ResolvePart1(new[] { + "abcdef", + "bababc", + "abbcde", + "abcccd", + "aabcdd", + "abcdee", + "ababab", + }); - Assert.Equal("12", result); - } + Assert.Equal("12", result); + } - [Fact] - public void ResolvePart2__Test() - { - Day02 day02 = new Day02(); + [Fact] + public void ResolvePart2__Test() + { + Day02 day02 = new(); - string result = day02.ResolvePart2(new string[] { - "abcde", - "fghij", - "klmno", - "pqrst", - "fguij", - "axcye", - "wvxyz", - }); + string result = day02.ResolvePart2(new[] { + "abcde", + "fghij", + "klmno", + "pqrst", + "fguij", + "axcye", + "wvxyz", + }); - Assert.Equal("fgij", result); - } + Assert.Equal("fgij", result); } } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/Day03_Tests.cs b/AdventOfCode2018.Tests/Day03_Tests.cs index 34aede0..152f290 100644 --- a/AdventOfCode2018.Tests/Day03_Tests.cs +++ b/AdventOfCode2018.Tests/Day03_Tests.cs @@ -1,35 +1,32 @@ -using Xunit; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class Day03_Tests { - public class Day03_Tests + [Fact] + public void ResolvePart1__Test() { - [Fact] - public void ResolvePart1__Test() - { - Day03 day03 = new Day03(); + Day03 day03 = new(); - string result = day03.ResolvePart1(new string[] { - "#1 @ 1,3: 4x4", - "#2 @ 3,1: 4x4", - "#3 @ 5,5: 2x2", - }); + string result = day03.ResolvePart1(new[] { + "#1 @ 1,3: 4x4", + "#2 @ 3,1: 4x4", + "#3 @ 5,5: 2x2", + }); - Assert.Equal("4", result); - } + Assert.Equal("4", result); + } - [Fact] - public void ResolvePart2__Test() - { - Day03 day03 = new Day03(); + [Fact] + public void ResolvePart2__Test() + { + Day03 day03 = new(); - string result = day03.ResolvePart2(new string[] { - "#1 @ 1,3: 4x4", - "#2 @ 3,1: 4x4", - "#3 @ 5,5: 2x2", - }); + string result = day03.ResolvePart2(new[] { + "#1 @ 1,3: 4x4", + "#2 @ 3,1: 4x4", + "#3 @ 5,5: 2x2", + }); - Assert.Equal("3", result); - } + Assert.Equal("3", result); } } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/Day04_Tests.cs b/AdventOfCode2018.Tests/Day04_Tests.cs index b0ffa46..9ac1d3c 100644 --- a/AdventOfCode2018.Tests/Day04_Tests.cs +++ b/AdventOfCode2018.Tests/Day04_Tests.cs @@ -1,120 +1,117 @@ -using Xunit; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class Day04_Tests { - public class Day04_Tests + [Fact] + public void ResolvePart1__BaseStatement() { - [Fact] - public void ResolvePart1__BaseStatement() - { - Day04 day04 = new Day04(); + Day04 day04 = new(); - string result = day04.ResolvePart1(new string[] { - "[1518-11-01 00:00] Guard #10 begins shift", - "[1518-11-01 00:05] falls asleep", - "[1518-11-01 00:25] wakes up", - "[1518-11-01 00:30] falls asleep", - "[1518-11-01 00:55] wakes up", - "[1518-11-01 23:58] Guard #99 begins shift", - "[1518-11-02 00:40] falls asleep", - "[1518-11-02 00:50] wakes up", - "[1518-11-03 00:05] Guard #10 begins shift", - "[1518-11-03 00:24] falls asleep", - "[1518-11-03 00:29] wakes up", - "[1518-11-04 00:02] Guard #99 begins shift", - "[1518-11-04 00:36] falls asleep", - "[1518-11-04 00:46] wakes up", - "[1518-11-05 00:03] Guard #99 begins shift", - "[1518-11-05 00:45] falls asleep", - "[1518-11-05 00:55] wakes up", - }); + string result = day04.ResolvePart1(new[] { + "[1518-11-01 00:00] Guard #10 begins shift", + "[1518-11-01 00:05] falls asleep", + "[1518-11-01 00:25] wakes up", + "[1518-11-01 00:30] falls asleep", + "[1518-11-01 00:55] wakes up", + "[1518-11-01 23:58] Guard #99 begins shift", + "[1518-11-02 00:40] falls asleep", + "[1518-11-02 00:50] wakes up", + "[1518-11-03 00:05] Guard #10 begins shift", + "[1518-11-03 00:24] falls asleep", + "[1518-11-03 00:29] wakes up", + "[1518-11-04 00:02] Guard #99 begins shift", + "[1518-11-04 00:36] falls asleep", + "[1518-11-04 00:46] wakes up", + "[1518-11-05 00:03] Guard #99 begins shift", + "[1518-11-05 00:45] falls asleep", + "[1518-11-05 00:55] wakes up", + }); - Assert.Equal("240", result); - } + Assert.Equal("240", result); + } - [Fact] - public void ResolvePart1__BaseStatementUnsorted() - { - Day04 day04 = new Day04(); + [Fact] + public void ResolvePart1__BaseStatementUnsorted() + { + Day04 day04 = new(); - string result = day04.ResolvePart1(new string[] { - "[1518-11-04 00:36] falls asleep", - "[1518-11-04 00:46] wakes up", - "[1518-11-05 00:03] Guard #99 begins shift", - "[1518-11-01 00:05] falls asleep", - "[1518-11-01 00:25] wakes up", - "[1518-11-02 00:40] falls asleep", - "[1518-11-01 00:30] falls asleep", - "[1518-11-03 00:29] wakes up", - "[1518-11-02 00:50] wakes up", - "[1518-11-03 00:05] Guard #10 begins shift", - "[1518-11-03 00:24] falls asleep", - "[1518-11-01 00:00] Guard #10 begins shift", - "[1518-11-04 00:02] Guard #99 begins shift", - "[1518-11-05 00:45] falls asleep", - "[1518-11-01 00:55] wakes up", - "[1518-11-01 23:58] Guard #99 begins shift", - "[1518-11-05 00:55] wakes up", - }); + string result = day04.ResolvePart1(new[] { + "[1518-11-04 00:36] falls asleep", + "[1518-11-04 00:46] wakes up", + "[1518-11-05 00:03] Guard #99 begins shift", + "[1518-11-01 00:05] falls asleep", + "[1518-11-01 00:25] wakes up", + "[1518-11-02 00:40] falls asleep", + "[1518-11-01 00:30] falls asleep", + "[1518-11-03 00:29] wakes up", + "[1518-11-02 00:50] wakes up", + "[1518-11-03 00:05] Guard #10 begins shift", + "[1518-11-03 00:24] falls asleep", + "[1518-11-01 00:00] Guard #10 begins shift", + "[1518-11-04 00:02] Guard #99 begins shift", + "[1518-11-05 00:45] falls asleep", + "[1518-11-01 00:55] wakes up", + "[1518-11-01 23:58] Guard #99 begins shift", + "[1518-11-05 00:55] wakes up", + }); - Assert.Equal("240", result); - } + Assert.Equal("240", result); + } - [Fact] - public void ResolvePart2__BaseStatement() - { - Day04 day04 = new Day04(); + [Fact] + public void ResolvePart2__BaseStatement() + { + Day04 day04 = new(); - string result = day04.ResolvePart2(new string[] { - "[1518-11-01 00:00] Guard #10 begins shift", - "[1518-11-01 00:05] falls asleep", - "[1518-11-01 00:25] wakes up", - "[1518-11-01 00:30] falls asleep", - "[1518-11-01 00:55] wakes up", - "[1518-11-01 23:58] Guard #99 begins shift", - "[1518-11-02 00:40] falls asleep", - "[1518-11-02 00:50] wakes up", - "[1518-11-03 00:05] Guard #10 begins shift", - "[1518-11-03 00:24] falls asleep", - "[1518-11-03 00:29] wakes up", - "[1518-11-04 00:02] Guard #99 begins shift", - "[1518-11-04 00:36] falls asleep", - "[1518-11-04 00:46] wakes up", - "[1518-11-05 00:03] Guard #99 begins shift", - "[1518-11-05 00:45] falls asleep", - "[1518-11-05 00:55] wakes up", - }); + string result = day04.ResolvePart2(new[] { + "[1518-11-01 00:00] Guard #10 begins shift", + "[1518-11-01 00:05] falls asleep", + "[1518-11-01 00:25] wakes up", + "[1518-11-01 00:30] falls asleep", + "[1518-11-01 00:55] wakes up", + "[1518-11-01 23:58] Guard #99 begins shift", + "[1518-11-02 00:40] falls asleep", + "[1518-11-02 00:50] wakes up", + "[1518-11-03 00:05] Guard #10 begins shift", + "[1518-11-03 00:24] falls asleep", + "[1518-11-03 00:29] wakes up", + "[1518-11-04 00:02] Guard #99 begins shift", + "[1518-11-04 00:36] falls asleep", + "[1518-11-04 00:46] wakes up", + "[1518-11-05 00:03] Guard #99 begins shift", + "[1518-11-05 00:45] falls asleep", + "[1518-11-05 00:55] wakes up", + }); - Assert.Equal("4455", result); - } + Assert.Equal("4455", result); + } - [Fact] - public void ResolvePart2__BaseStatementUnsorted() - { - Day04 day04 = new Day04(); + [Fact] + public void ResolvePart2__BaseStatementUnsorted() + { + Day04 day04 = new(); - string result = day04.ResolvePart2(new string[] { - "[1518-11-04 00:36] falls asleep", - "[1518-11-04 00:46] wakes up", - "[1518-11-05 00:03] Guard #99 begins shift", - "[1518-11-01 00:05] falls asleep", - "[1518-11-01 00:25] wakes up", - "[1518-11-02 00:40] falls asleep", - "[1518-11-01 00:30] falls asleep", - "[1518-11-03 00:29] wakes up", - "[1518-11-02 00:50] wakes up", - "[1518-11-03 00:05] Guard #10 begins shift", - "[1518-11-03 00:24] falls asleep", - "[1518-11-01 00:00] Guard #10 begins shift", - "[1518-11-04 00:02] Guard #99 begins shift", - "[1518-11-05 00:45] falls asleep", - "[1518-11-01 00:55] wakes up", - "[1518-11-01 23:58] Guard #99 begins shift", - "[1518-11-05 00:55] wakes up", - }); + string result = day04.ResolvePart2(new[] { + "[1518-11-04 00:36] falls asleep", + "[1518-11-04 00:46] wakes up", + "[1518-11-05 00:03] Guard #99 begins shift", + "[1518-11-01 00:05] falls asleep", + "[1518-11-01 00:25] wakes up", + "[1518-11-02 00:40] falls asleep", + "[1518-11-01 00:30] falls asleep", + "[1518-11-03 00:29] wakes up", + "[1518-11-02 00:50] wakes up", + "[1518-11-03 00:05] Guard #10 begins shift", + "[1518-11-03 00:24] falls asleep", + "[1518-11-01 00:00] Guard #10 begins shift", + "[1518-11-04 00:02] Guard #99 begins shift", + "[1518-11-05 00:45] falls asleep", + "[1518-11-01 00:55] wakes up", + "[1518-11-01 23:58] Guard #99 begins shift", + "[1518-11-05 00:55] wakes up", + }); - Assert.Equal("4455", result); - } + Assert.Equal("4455", result); } } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/Day05_Tests.cs b/AdventOfCode2018.Tests/Day05_Tests.cs index 4e606a6..579bbdd 100644 --- a/AdventOfCode2018.Tests/Day05_Tests.cs +++ b/AdventOfCode2018.Tests/Day05_Tests.cs @@ -1,199 +1,196 @@ -using Xunit; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class Day05_Tests { - public class Day05_Tests + [Fact] + public void ResolvePart1__Test() { - [Fact] - public void ResolvePart1__Test() - { - Day05 day05 = new Day05(); + Day05 day05 = new(); - string result = day05.ResolvePart1(new string[] { "dabAcCaCBAcCcaDA" }); + string result = day05.ResolvePart1(new[] { "dabAcCaCBAcCcaDA" }); - Assert.Equal("10", result); - } - - [Fact] - public void ResolvePart2__Test() - { - Day05 day05 = new Day05(); - - string result = day05.ResolvePart2(new string[] { "dabAcCaCBAcCcaDA" }); - - Assert.Equal("4", result); - } - - #region ReducePolymer - - [Fact] - public void ReducePolymer__Remove_cC() - { - Day05 day05 = new Day05(); - - string result = day05.ReducePolymer("dabAcCaCBA"); - - Assert.Equal("dabAaCBA", result); - } - - [Fact] - public void ReducePolymer__Remove_cC_AtEnd() - { - Day05 day05 = new Day05(); - - string result = day05.ReducePolymer("dabAcC"); - - Assert.Equal("dabA", result); - } - - [Fact] - public void ReducePolymer__Remove_Only_cC() - { - Day05 day05 = new Day05(); - - string result = day05.ReducePolymer("cC"); - - Assert.Equal("", result); - } - - [Fact] - public void ReducePolymer__Remove_cC_AtStart() - { - Day05 day05 = new Day05(); - - string result = day05.ReducePolymer("cCAAAA"); - - Assert.Equal("AAAA", result); - } - - [Fact] - public void ReducePolymer__Remove_Aa() - { - Day05 day05 = new Day05(); - - string result = day05.ReducePolymer("dabAaCBA"); - - Assert.Equal("dabCBA", result); - } - - [Fact] - public void ReducePolymer__Remove_cCc() - { - Day05 day05 = new Day05(); - - string result = day05.ReducePolymer("dabCBAcCcaDA"); - - Assert.Equal("dabCBAcaDA", result); - } - - [Fact] - public void ReducePolymer__Irreductible() - { - Day05 day05 = new Day05(); - - string result = day05.ReducePolymer("dabCBAcaDA"); - - Assert.Equal("dabCBAcaDA", result); - } - - #endregion ReducePolymer - - #region FullyReducePolymer - - [Fact] - public void FullyReducePolymer__Test() - { - Day05 day05 = new Day05(); - - string result = day05.FullyReducePolymer("dabAcCaCBAcCcaDA"); - - Assert.Equal("dabCBAcaDA", result); - } - - #endregion FullyReducePolymer - - #region RemoveUnitTypeFromPolymer - - [Fact] - public void RemoveUnitTypeFromPolymer__Remove_a() - { - Day05 day05 = new Day05(); - - string result = day05.RemoveUnitTypeFromPolymer("dabAcCaCBAcCcaDA", 'a'); - - Assert.Equal("dbcCCBcCcD", result); - } - - [Fact] - public void RemoveUnitTypeFromPolymer__Remove_b() - { - Day05 day05 = new Day05(); - - string result = day05.RemoveUnitTypeFromPolymer("dabAcCaCBAcCcaDA", 'b'); - - Assert.Equal("daAcCaCAcCcaDA", result); - } - - [Fact] - public void RemoveUnitTypeFromPolymer__Remove_c() - { - Day05 day05 = new Day05(); - - string result = day05.RemoveUnitTypeFromPolymer("dabAcCaCBAcCcaDA", 'c'); - - Assert.Equal("dabAaBAaDA", result); - } - - [Fact] - public void RemoveUnitTypeFromPolymer__Remove_d() - { - Day05 day05 = new Day05(); - - string result = day05.RemoveUnitTypeFromPolymer("dabAcCaCBAcCcaDA", 'd'); - - Assert.Equal("abAcCaCBAcCcaA", result); - } - - [Fact] - public void RemoveUnitTypeFromPolymer__Remove_A() - { - Day05 day05 = new Day05(); - - string result = day05.RemoveUnitTypeFromPolymer("dabAcCaCBAcCcaDA", 'A'); - - Assert.Equal("dbcCCBcCcD", result); - } - - [Fact] - public void RemoveUnitTypeFromPolymer__Remove_B() - { - Day05 day05 = new Day05(); - - string result = day05.RemoveUnitTypeFromPolymer("dabAcCaCBAcCcaDA", 'B'); - - Assert.Equal("daAcCaCAcCcaDA", result); - } - - [Fact] - public void RemoveUnitTypeFromPolymer__Remove_C() - { - Day05 day05 = new Day05(); - - string result = day05.RemoveUnitTypeFromPolymer("dabAcCaCBAcCcaDA", 'C'); - - Assert.Equal("dabAaBAaDA", result); - } - - [Fact] - public void RemoveUnitTypeFromPolymer__Remove_D() - { - Day05 day05 = new Day05(); - - string result = day05.RemoveUnitTypeFromPolymer("dabAcCaCBAcCcaDA", 'D'); - - Assert.Equal("abAcCaCBAcCcaA", result); - } - - #endregion RemoveUnitTypeFromPolymer + Assert.Equal("10", result); } + + [Fact] + public void ResolvePart2__Test() + { + Day05 day05 = new(); + + string result = day05.ResolvePart2(new[] { "dabAcCaCBAcCcaDA" }); + + Assert.Equal("4", result); + } + + #region ReducePolymer + + [Fact] + public void ReducePolymer__Remove_cC() + { + Day05 day05 = new(); + + string result = day05.ReducePolymer("dabAcCaCBA"); + + Assert.Equal("dabAaCBA", result); + } + + [Fact] + public void ReducePolymer__Remove_cC_AtEnd() + { + Day05 day05 = new(); + + string result = day05.ReducePolymer("dabAcC"); + + Assert.Equal("dabA", result); + } + + [Fact] + public void ReducePolymer__Remove_Only_cC() + { + Day05 day05 = new(); + + string result = day05.ReducePolymer("cC"); + + Assert.Equal("", result); + } + + [Fact] + public void ReducePolymer__Remove_cC_AtStart() + { + Day05 day05 = new(); + + string result = day05.ReducePolymer("cCAAAA"); + + Assert.Equal("AAAA", result); + } + + [Fact] + public void ReducePolymer__Remove_Aa() + { + Day05 day05 = new(); + + string result = day05.ReducePolymer("dabAaCBA"); + + Assert.Equal("dabCBA", result); + } + + [Fact] + public void ReducePolymer__Remove_cCc() + { + Day05 day05 = new(); + + string result = day05.ReducePolymer("dabCBAcCcaDA"); + + Assert.Equal("dabCBAcaDA", result); + } + + [Fact] + public void ReducePolymer__Irreductible() + { + Day05 day05 = new(); + + string result = day05.ReducePolymer("dabCBAcaDA"); + + Assert.Equal("dabCBAcaDA", result); + } + + #endregion ReducePolymer + + #region FullyReducePolymer + + [Fact] + public void FullyReducePolymer__Test() + { + Day05 day05 = new(); + + string result = day05.FullyReducePolymer("dabAcCaCBAcCcaDA"); + + Assert.Equal("dabCBAcaDA", result); + } + + #endregion FullyReducePolymer + + #region RemoveUnitTypeFromPolymer + + [Fact] + public void RemoveUnitTypeFromPolymer__Remove_a() + { + Day05 day05 = new(); + + string result = day05.RemoveUnitTypeFromPolymer("dabAcCaCBAcCcaDA", 'a'); + + Assert.Equal("dbcCCBcCcD", result); + } + + [Fact] + public void RemoveUnitTypeFromPolymer__Remove_b() + { + Day05 day05 = new(); + + string result = day05.RemoveUnitTypeFromPolymer("dabAcCaCBAcCcaDA", 'b'); + + Assert.Equal("daAcCaCAcCcaDA", result); + } + + [Fact] + public void RemoveUnitTypeFromPolymer__Remove_c() + { + Day05 day05 = new(); + + string result = day05.RemoveUnitTypeFromPolymer("dabAcCaCBAcCcaDA", 'c'); + + Assert.Equal("dabAaBAaDA", result); + } + + [Fact] + public void RemoveUnitTypeFromPolymer__Remove_d() + { + Day05 day05 = new(); + + string result = day05.RemoveUnitTypeFromPolymer("dabAcCaCBAcCcaDA", 'd'); + + Assert.Equal("abAcCaCBAcCcaA", result); + } + + [Fact] + public void RemoveUnitTypeFromPolymer__Remove_A() + { + Day05 day05 = new(); + + string result = day05.RemoveUnitTypeFromPolymer("dabAcCaCBAcCcaDA", 'A'); + + Assert.Equal("dbcCCBcCcD", result); + } + + [Fact] + public void RemoveUnitTypeFromPolymer__Remove_B() + { + Day05 day05 = new(); + + string result = day05.RemoveUnitTypeFromPolymer("dabAcCaCBAcCcaDA", 'B'); + + Assert.Equal("daAcCaCAcCcaDA", result); + } + + [Fact] + public void RemoveUnitTypeFromPolymer__Remove_C() + { + Day05 day05 = new(); + + string result = day05.RemoveUnitTypeFromPolymer("dabAcCaCBAcCcaDA", 'C'); + + Assert.Equal("dabAaBAaDA", result); + } + + [Fact] + public void RemoveUnitTypeFromPolymer__Remove_D() + { + Day05 day05 = new(); + + string result = day05.RemoveUnitTypeFromPolymer("dabAcCaCBAcCcaDA", 'D'); + + Assert.Equal("abAcCaCBAcCcaA", result); + } + + #endregion RemoveUnitTypeFromPolymer } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/Day06_Tests.cs b/AdventOfCode2018.Tests/Day06_Tests.cs index 5012c86..7d7493b 100644 --- a/AdventOfCode2018.Tests/Day06_Tests.cs +++ b/AdventOfCode2018.Tests/Day06_Tests.cs @@ -1,42 +1,38 @@ -using System.Collections.Generic; -using Xunit; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class Day06_Tests { - public class Day06_Tests + [Fact] + public void ResolvePart1__Test() { - [Fact] - public void ResolvePart1__Test() - { - Day06 day06 = new Day06(); + Day06 day06 = new(); - string result = day06.ResolvePart1(new string[] { - "1, 1", - "1, 6", - "8, 3", - "3, 4", - "5, 5", - "8, 9", - }); + string result = day06.ResolvePart1(new[] { + "1, 1", + "1, 6", + "8, 3", + "3, 4", + "5, 5", + "8, 9", + }); - Assert.Equal("17", result); - } + Assert.Equal("17", result); + } - [Fact] - public void ResolvePart2__Test() - { - Day06 day06 = new Day06 { DistanceThresold = 32, }; + [Fact] + public void ResolvePart2__Test() + { + Day06 day06 = new() { DistanceThresold = 32, }; - string result = day06.ResolvePart2(new string[] { - "1, 1", - "1, 6", - "8, 3", - "3, 4", - "5, 5", - "8, 9", - }); + string result = day06.ResolvePart2(new[] { + "1, 1", + "1, 6", + "8, 3", + "3, 4", + "5, 5", + "8, 9", + }); - Assert.Equal("16", result); - } + Assert.Equal("16", result); } } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/Day07_Tests.cs b/AdventOfCode2018.Tests/Day07_Tests.cs index d21ca5d..83e54ef 100644 --- a/AdventOfCode2018.Tests/Day07_Tests.cs +++ b/AdventOfCode2018.Tests/Day07_Tests.cs @@ -1,43 +1,40 @@ -using Xunit; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class Day07_Tests { - public class Day07_Tests + [Fact] + public void ResolvePart1__Test() { - [Fact] - public void ResolvePart1__Test() - { - Day07 day07 = new Day07(); + Day07 day07 = new(); - string result = day07.ResolvePart1(new string[] { - "Step C must be finished before step A can begin.", - "Step C must be finished before step F can begin.", - "Step A must be finished before step B can begin.", - "Step A must be finished before step D can begin.", - "Step B must be finished before step E can begin.", - "Step D must be finished before step E can begin.", - "Step F must be finished before step E can begin.", - }); + string result = day07.ResolvePart1(new[] { + "Step C must be finished before step A can begin.", + "Step C must be finished before step F can begin.", + "Step A must be finished before step B can begin.", + "Step A must be finished before step D can begin.", + "Step B must be finished before step E can begin.", + "Step D must be finished before step E can begin.", + "Step F must be finished before step E can begin.", + }); - Assert.Equal("CABDFE", result); - } + Assert.Equal("CABDFE", result); + } - [Fact] - public void ResolvePart2__Test() - { - Day07 day07 = new Day07 { BaseCost = 0, NumberOfWorkers = 2 }; + [Fact] + public void ResolvePart2__Test() + { + Day07 day07 = new() { BaseCost = 0, NumberOfWorkers = 2 }; - string result = day07.ResolvePart2(new string[] { - "Step C must be finished before step A can begin.", - "Step C must be finished before step F can begin.", - "Step A must be finished before step B can begin.", - "Step A must be finished before step D can begin.", - "Step B must be finished before step E can begin.", - "Step D must be finished before step E can begin.", - "Step F must be finished before step E can begin.", - }); + string result = day07.ResolvePart2(new[] { + "Step C must be finished before step A can begin.", + "Step C must be finished before step F can begin.", + "Step A must be finished before step B can begin.", + "Step A must be finished before step D can begin.", + "Step B must be finished before step E can begin.", + "Step D must be finished before step E can begin.", + "Step F must be finished before step E can begin.", + }); - Assert.Equal("15", result); - } + Assert.Equal("15", result); } } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/Day08_Tests.cs b/AdventOfCode2018.Tests/Day08_Tests.cs index ac5bac6..abf129a 100644 --- a/AdventOfCode2018.Tests/Day08_Tests.cs +++ b/AdventOfCode2018.Tests/Day08_Tests.cs @@ -1,27 +1,24 @@ -using Xunit; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class Day08_Tests { - public class Day08_Tests + [Fact] + public void ResolvePart1__Test() { - [Fact] - public void ResolvePart1__Test() - { - Day08 day = new Day08(); + Day08 day = new(); - string result = day.ResolvePart1(new string[] { "2 3 0 3 10 11 12 1 1 0 1 99 2 1 1 2", }); + string result = day.ResolvePart1(new[] { "2 3 0 3 10 11 12 1 1 0 1 99 2 1 1 2", }); - Assert.Equal("138", result); - } + Assert.Equal("138", result); + } - [Fact] - public void ResolvePart2__Test() - { - Day08 day = new Day08(); + [Fact] + public void ResolvePart2__Test() + { + Day08 day = new(); - string result = day.ResolvePart2(new string[] { "2 3 0 3 10 11 12 1 1 0 1 99 2 1 1 2", }); + string result = day.ResolvePart2(new[] { "2 3 0 3 10 11 12 1 1 0 1 99 2 1 1 2", }); - Assert.Equal("66", result); - } + Assert.Equal("66", result); } } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/Day09_Tests.cs b/AdventOfCode2018.Tests/Day09_Tests.cs index 70d9841..337e221 100644 --- a/AdventOfCode2018.Tests/Day09_Tests.cs +++ b/AdventOfCode2018.Tests/Day09_Tests.cs @@ -1,67 +1,64 @@ -using Xunit; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class Day09_Tests { - public class Day09_Tests + [Fact] + public void ResolvePart1__Test1() { - [Fact] - public void ResolvePart1__Test1() - { - Day09 day = new Day09(); + Day09 day = new(); - string result = day.ResolvePart1(new string[] { "9 players; last marble is worth 25 points" }); + string result = day.ResolvePart1(new[] { "9 players; last marble is worth 25 points" }); - Assert.Equal("32", result); - } + Assert.Equal("32", result); + } - [Fact] - public void ResolvePart1__Test2() - { - Day09 day = new Day09(); + [Fact] + public void ResolvePart1__Test2() + { + Day09 day = new(); - string result = day.ResolvePart1(new string[] { "10 players; last marble is worth 1618 points" }); + string result = day.ResolvePart1(new[] { "10 players; last marble is worth 1618 points" }); - Assert.Equal("8317", result); - } + Assert.Equal("8317", result); + } - [Fact] - public void ResolvePart1__Test3() - { - Day09 day = new Day09(); + [Fact] + public void ResolvePart1__Test3() + { + Day09 day = new(); - string result = day.ResolvePart1(new string[] { "13 players; last marble is worth 7999 points" }); + string result = day.ResolvePart1(new[] { "13 players; last marble is worth 7999 points" }); - Assert.Equal("146373", result); - } + Assert.Equal("146373", result); + } - [Fact] - public void ResolvePart1__Test4() - { - Day09 day = new Day09(); + [Fact] + public void ResolvePart1__Test4() + { + Day09 day = new(); - string result = day.ResolvePart1(new string[] { "17 players; last marble is worth 1104 points" }); + string result = day.ResolvePart1(new[] { "17 players; last marble is worth 1104 points" }); - Assert.Equal("2764", result); - } + Assert.Equal("2764", result); + } - [Fact] - public void ResolvePart1__Test5() - { - Day09 day = new Day09(); + [Fact] + public void ResolvePart1__Test5() + { + Day09 day = new(); - string result = day.ResolvePart1(new string[] { "21 players; last marble is worth 6111 points" }); + string result = day.ResolvePart1(new[] { "21 players; last marble is worth 6111 points" }); - Assert.Equal("54718", result); - } + Assert.Equal("54718", result); + } - [Fact] - public void ResolvePart1__Test6() - { - Day09 day = new Day09(); + [Fact] + public void ResolvePart1__Test6() + { + Day09 day = new(); - string result = day.ResolvePart1(new string[] { "30 players; last marble is worth 5807 points" }); + string result = day.ResolvePart1(new[] { "30 players; last marble is worth 5807 points" }); - Assert.Equal("37305", result); - } + Assert.Equal("37305", result); } } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/Day10_Tests.cs b/AdventOfCode2018.Tests/Day10_Tests.cs index 31633c4..80d910a 100644 --- a/AdventOfCode2018.Tests/Day10_Tests.cs +++ b/AdventOfCode2018.Tests/Day10_Tests.cs @@ -1,102 +1,100 @@ using System; -using Xunit; -namespace AdventOfCode2018.Tests +namespace AdventOfCode2018.Tests; + +public class Day10_Tests { - public class Day10_Tests + [Fact] + public void ResolvePart1__Test() { - [Fact] - public void ResolvePart1__Test() - { - Day10 day = new Day10 { Width = 12, Height = 10 }; + Day10 day = new() { Width = 12, Height = 10 }; - string result = day.ResolvePart1(new string[] { - "position=< 9, 1> velocity=< 0, 2>", - "position=< 7, 0> velocity=<-1, 0>", - "position=< 3, -2> velocity=<-1, 1>", - "position=< 6, 10> velocity=<-2, -1>", - "position=< 2, -4> velocity=< 2, 2>", - "position=<-6, 10> velocity=< 2, -2>", - "position=< 1, 8> velocity=< 1, -1>", - "position=< 1, 7> velocity=< 1, 0>", - "position=<-3, 11> velocity=< 1, -2>", - "position=< 7, 6> velocity=<-1, -1>", - "position=<-2, 3> velocity=< 1, 0>", - "position=<-4, 3> velocity=< 2, 0>", - "position=<10, -3> velocity=<-1, 1>", - "position=< 5, 11> velocity=< 1, -2>", - "position=< 4, 7> velocity=< 0, -1>", - "position=< 8, -2> velocity=< 0, 1>", - "position=<15, 0> velocity=<-2, 0>", - "position=< 1, 6> velocity=< 1, 0>", - "position=< 8, 9> velocity=< 0, -1>", - "position=< 3, 3> velocity=<-1, 1>", - "position=< 0, 5> velocity=< 0, -1>", - "position=<-2, 2> velocity=< 2, 0>", - "position=< 5, -2> velocity=< 1, 2>", - "position=< 1, 4> velocity=< 2, 1>", - "position=<-2, 7> velocity=< 2, -2>", - "position=< 3, 6> velocity=<-1, -1>", - "position=< 5, 0> velocity=< 1, 0>", - "position=<-6, 0> velocity=< 2, 0>", - "position=< 5, 9> velocity=< 1, -2>", - "position=<14, 7> velocity=<-2, 0>", - "position=<-3, 6> velocity=< 2, -1>", - }); + string result = day.ResolvePart1(new[] { + "position=< 9, 1> velocity=< 0, 2>", + "position=< 7, 0> velocity=<-1, 0>", + "position=< 3, -2> velocity=<-1, 1>", + "position=< 6, 10> velocity=<-2, -1>", + "position=< 2, -4> velocity=< 2, 2>", + "position=<-6, 10> velocity=< 2, -2>", + "position=< 1, 8> velocity=< 1, -1>", + "position=< 1, 7> velocity=< 1, 0>", + "position=<-3, 11> velocity=< 1, -2>", + "position=< 7, 6> velocity=<-1, -1>", + "position=<-2, 3> velocity=< 1, 0>", + "position=<-4, 3> velocity=< 2, 0>", + "position=<10, -3> velocity=<-1, 1>", + "position=< 5, 11> velocity=< 1, -2>", + "position=< 4, 7> velocity=< 0, -1>", + "position=< 8, -2> velocity=< 0, 1>", + "position=<15, 0> velocity=<-2, 0>", + "position=< 1, 6> velocity=< 1, 0>", + "position=< 8, 9> velocity=< 0, -1>", + "position=< 3, 3> velocity=<-1, 1>", + "position=< 0, 5> velocity=< 0, -1>", + "position=<-2, 2> velocity=< 2, 0>", + "position=< 5, -2> velocity=< 1, 2>", + "position=< 1, 4> velocity=< 2, 1>", + "position=<-2, 7> velocity=< 2, -2>", + "position=< 3, 6> velocity=<-1, -1>", + "position=< 5, 0> velocity=< 1, 0>", + "position=<-6, 0> velocity=< 2, 0>", + "position=< 5, 9> velocity=< 1, -2>", + "position=<14, 7> velocity=<-2, 0>", + "position=<-3, 6> velocity=< 2, -1>", + }); - Assert.Equal( - Environment.NewLine + "............" + - Environment.NewLine + ".#...#..###." + - Environment.NewLine + ".#...#...#.." + - Environment.NewLine + ".#...#...#.." + - Environment.NewLine + ".#####...#.." + - Environment.NewLine + ".#...#...#.." + - Environment.NewLine + ".#...#...#.." + - Environment.NewLine + ".#...#...#.." + - Environment.NewLine + ".#...#..###." + - Environment.NewLine + "............", result); - } + Assert.Equal( + Environment.NewLine + "............" + + Environment.NewLine + ".#...#..###." + + Environment.NewLine + ".#...#...#.." + + Environment.NewLine + ".#...#...#.." + + Environment.NewLine + ".#####...#.." + + Environment.NewLine + ".#...#...#.." + + Environment.NewLine + ".#...#...#.." + + Environment.NewLine + ".#...#...#.." + + Environment.NewLine + ".#...#..###." + + Environment.NewLine + "............", result); + } - [Fact] - public void ResolvePart2__Test() - { - Day10 day = new Day10(); + [Fact] + public void ResolvePart2__Test() + { + Day10 day = new(); - string result = day.ResolvePart2(new string[] { - "position=< 9, 1> velocity=< 0, 2>", - "position=< 7, 0> velocity=<-1, 0>", - "position=< 3, -2> velocity=<-1, 1>", - "position=< 6, 10> velocity=<-2, -1>", - "position=< 2, -4> velocity=< 2, 2>", - "position=<-6, 10> velocity=< 2, -2>", - "position=< 1, 8> velocity=< 1, -1>", - "position=< 1, 7> velocity=< 1, 0>", - "position=<-3, 11> velocity=< 1, -2>", - "position=< 7, 6> velocity=<-1, -1>", - "position=<-2, 3> velocity=< 1, 0>", - "position=<-4, 3> velocity=< 2, 0>", - "position=<10, -3> velocity=<-1, 1>", - "position=< 5, 11> velocity=< 1, -2>", - "position=< 4, 7> velocity=< 0, -1>", - "position=< 8, -2> velocity=< 0, 1>", - "position=<15, 0> velocity=<-2, 0>", - "position=< 1, 6> velocity=< 1, 0>", - "position=< 8, 9> velocity=< 0, -1>", - "position=< 3, 3> velocity=<-1, 1>", - "position=< 0, 5> velocity=< 0, -1>", - "position=<-2, 2> velocity=< 2, 0>", - "position=< 5, -2> velocity=< 1, 2>", - "position=< 1, 4> velocity=< 2, 1>", - "position=<-2, 7> velocity=< 2, -2>", - "position=< 3, 6> velocity=<-1, -1>", - "position=< 5, 0> velocity=< 1, 0>", - "position=<-6, 0> velocity=< 2, 0>", - "position=< 5, 9> velocity=< 1, -2>", - "position=<14, 7> velocity=<-2, 0>", - "position=<-3, 6> velocity=< 2, -1>", - }); + string result = day.ResolvePart2(new[] { + "position=< 9, 1> velocity=< 0, 2>", + "position=< 7, 0> velocity=<-1, 0>", + "position=< 3, -2> velocity=<-1, 1>", + "position=< 6, 10> velocity=<-2, -1>", + "position=< 2, -4> velocity=< 2, 2>", + "position=<-6, 10> velocity=< 2, -2>", + "position=< 1, 8> velocity=< 1, -1>", + "position=< 1, 7> velocity=< 1, 0>", + "position=<-3, 11> velocity=< 1, -2>", + "position=< 7, 6> velocity=<-1, -1>", + "position=<-2, 3> velocity=< 1, 0>", + "position=<-4, 3> velocity=< 2, 0>", + "position=<10, -3> velocity=<-1, 1>", + "position=< 5, 11> velocity=< 1, -2>", + "position=< 4, 7> velocity=< 0, -1>", + "position=< 8, -2> velocity=< 0, 1>", + "position=<15, 0> velocity=<-2, 0>", + "position=< 1, 6> velocity=< 1, 0>", + "position=< 8, 9> velocity=< 0, -1>", + "position=< 3, 3> velocity=<-1, 1>", + "position=< 0, 5> velocity=< 0, -1>", + "position=<-2, 2> velocity=< 2, 0>", + "position=< 5, -2> velocity=< 1, 2>", + "position=< 1, 4> velocity=< 2, 1>", + "position=<-2, 7> velocity=< 2, -2>", + "position=< 3, 6> velocity=<-1, -1>", + "position=< 5, 0> velocity=< 1, 0>", + "position=<-6, 0> velocity=< 2, 0>", + "position=< 5, 9> velocity=< 1, -2>", + "position=<14, 7> velocity=<-2, 0>", + "position=<-3, 6> velocity=< 2, -1>", + }); - Assert.Equal("3", result); - } + Assert.Equal("3", result); } } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/Day11_Tests.cs b/AdventOfCode2018.Tests/Day11_Tests.cs index 168eb6f..510003a 100644 --- a/AdventOfCode2018.Tests/Day11_Tests.cs +++ b/AdventOfCode2018.Tests/Day11_Tests.cs @@ -1,76 +1,73 @@ -using Xunit; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class Day11_Tests { - public class Day11_Tests + [Fact] + public void CalculatePowerLevelOfCell__Test1() { - [Fact] - public void CalculatePowerLevelOfCell__Test1() - { - int powerLevel = Day11.CalculatePowerLevelOfCell(3, 5, 8); - Assert.Equal(4, powerLevel); - } + int powerLevel = Day11.CalculatePowerLevelOfCell(3, 5, 8); + Assert.Equal(4, powerLevel); + } - [Fact] - public void CalculatePowerLevelOfRegion__Test1() - { - int powerLevel = Day11.CalculatePowerLevelOfRegion(33, 45, 3, 18); - Assert.Equal(29, powerLevel); - } + [Fact] + public void CalculatePowerLevelOfRegion__Test1() + { + int powerLevel = Day11.CalculatePowerLevelOfRegion(33, 45, 3, 18); + Assert.Equal(29, powerLevel); + } - [Fact] - public void CalculatePowerLevelOfRegion__Test2() - { - int powerLevel = Day11.CalculatePowerLevelOfRegion(21, 61, 3, 42); - Assert.Equal(30, powerLevel); - } + [Fact] + public void CalculatePowerLevelOfRegion__Test2() + { + int powerLevel = Day11.CalculatePowerLevelOfRegion(21, 61, 3, 42); + Assert.Equal(30, powerLevel); + } - [Fact] - public void CalculatePowerLevelOfRegion__Test1_WithSumationField() - { - int[,] summationFiled = Day11.GenerateSumationField(300, 300, 18); - int powerLevel = Day11.CalculatePowerLevelOfRegion(33, 45, 3, summationFiled); - Assert.Equal(29, powerLevel); - } + [Fact] + public void CalculatePowerLevelOfRegion__Test1_WithSumationField() + { + int[,] summationFiled = Day11.GenerateSumationField(300, 300, 18); + int powerLevel = Day11.CalculatePowerLevelOfRegion(33, 45, 3, summationFiled); + Assert.Equal(29, powerLevel); + } - [Fact] - public void CalculatePowerLevelOfRegion__Test2_WithSumationField() - { - int[,] summationFiled = Day11.GenerateSumationField(300, 300, 42); - int powerLevel = Day11.CalculatePowerLevelOfRegion(21, 61, 3, summationFiled); - Assert.Equal(30, powerLevel); - } + [Fact] + public void CalculatePowerLevelOfRegion__Test2_WithSumationField() + { + int[,] summationFiled = Day11.GenerateSumationField(300, 300, 42); + int powerLevel = Day11.CalculatePowerLevelOfRegion(21, 61, 3, summationFiled); + Assert.Equal(30, powerLevel); + } - [Fact] - public void SearchBestRegionOfOneSize__Test1() - { - Day11.SearchBestRegionOfOneSize(300, 300, 3, 18, out int x, out int y); - Assert.Equal(33, x); - Assert.Equal(45, y); - } + [Fact] + public void SearchBestRegionOfOneSize__Test1() + { + Day11.SearchBestRegionOfOneSize(300, 300, 3, 18, out int x, out int y); + Assert.Equal(33, x); + Assert.Equal(45, y); + } - [Fact] - public void SearchBestRegionOfOneSize__Test2() - { - Day11.SearchBestRegionOfOneSize(300, 300, 3, 42, out int x, out int y); - Assert.Equal(21, x); - Assert.Equal(61, y); - } + [Fact] + public void SearchBestRegionOfOneSize__Test2() + { + Day11.SearchBestRegionOfOneSize(300, 300, 3, 42, out int x, out int y); + Assert.Equal(21, x); + Assert.Equal(61, y); + } - [Fact] - public void ResolvePart2__Test1() - { - Day11 day = new Day11(); - string result = day.ResolvePart2(new string[] { "18" }); - Assert.Equal("90,269,16", result); - } + [Fact] + public void ResolvePart2__Test1() + { + Day11 day = new(); + string result = day.ResolvePart2(new[] { "18" }); + Assert.Equal("90,269,16", result); + } - [Fact] - public void ResolvePart2__Test2() - { - Day11 day = new Day11(); - string result = day.ResolvePart2(new string[] { "42" }); - Assert.Equal("232,251,12", result); - } + [Fact] + public void ResolvePart2__Test2() + { + Day11 day = new(); + string result = day.ResolvePart2(new[] { "42" }); + Assert.Equal("232,251,12", result); } } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/Day12_Tests.cs b/AdventOfCode2018.Tests/Day12_Tests.cs index b49ed75..14f2095 100644 --- a/AdventOfCode2018.Tests/Day12_Tests.cs +++ b/AdventOfCode2018.Tests/Day12_Tests.cs @@ -1,35 +1,32 @@ -using Xunit; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class Day12_Tests { - public class Day12_Tests + [Fact] + public void ResolvePart1__Test() { - [Fact] - public void ResolvePart1__Test() + Day12 day = new(); + + string result = day.ResolvePart1(new[] { - Day12 day = new Day12(); + "initial state: #..#.#..##......###...###", + "", + "...## => #", + "..#.. => #", + ".#... => #", + ".#.#. => #", + ".#.## => #", + ".##.. => #", + ".#### => #", + "#.#.# => #", + "#.### => #", + "##.#. => #", + "##.## => #", + "###.. => #", + "###.# => #", + "####. => #", + }); - string result = day.ResolvePart1(new string[] - { - "initial state: #..#.#..##......###...###", - "", - "...## => #", - "..#.. => #", - ".#... => #", - ".#.#. => #", - ".#.## => #", - ".##.. => #", - ".#### => #", - "#.#.# => #", - "#.### => #", - "##.#. => #", - "##.## => #", - "###.. => #", - "###.# => #", - "####. => #", - }); - - Assert.Equal("325", result); - } + Assert.Equal("325", result); } } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/Day13_Tests.cs b/AdventOfCode2018.Tests/Day13_Tests.cs index 6e56880..6d97f53 100644 --- a/AdventOfCode2018.Tests/Day13_Tests.cs +++ b/AdventOfCode2018.Tests/Day13_Tests.cs @@ -1,60 +1,57 @@ -using Xunit; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class Day13_Tests { - public class Day13_Tests + [Fact] + public void ResolvePart1__Test1() { - [Fact] - public void ResolvePart1__Test1() - { - Day13 day = new Day13(); + Day13 day = new(); - string result = day.ResolvePart1(new string[] { - "|", - "v", - "|", - "|", - "|", - "^", - "|", - }); + string result = day.ResolvePart1(new[] { + "|", + "v", + "|", + "|", + "|", + "^", + "|", + }); - Assert.Equal("0,3", result); - } + Assert.Equal("0,3", result); + } - [Fact] - public void ResolvePart1__Test2() - { - Day13 day = new Day13(); + [Fact] + public void ResolvePart1__Test2() + { + Day13 day = new(); - string result = day.ResolvePart1(new string[] { - @"/->-\ ", - @"| | /----\", - @"| /-+--+-\ |", - @"| | | | v |", - @"\-+-/ \-+--/", - @" \------/ ", - }); + string result = day.ResolvePart1(new[] { + @"/->-\ ", + @"| | /----\", + @"| /-+--+-\ |", + @"| | | | v |", + @"\-+-/ \-+--/", + @" \------/ ", + }); - Assert.Equal("7,3", result); - } + Assert.Equal("7,3", result); + } - [Fact] - public void ResolvePart2__Test() - { - Day13 day = new Day13(); + [Fact] + public void ResolvePart2__Test() + { + Day13 day = new(); - string result = day.ResolvePart2(new string[] { - @"/>-<\ ", - @"| | ", - @"| /<+-\", - @"| | | v", - @"\>+/", - }); + string result = day.ResolvePart2(new[] { + @"/>-<\ ", + @"| | ", + @"| /<+-\", + @"| | | v", + @"\>+/", + }); - Assert.Equal("6,4", result); - } + Assert.Equal("6,4", result); } } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/Day14_Tests.cs b/AdventOfCode2018.Tests/Day14_Tests.cs index e28c4ed..ef9f327 100644 --- a/AdventOfCode2018.Tests/Day14_Tests.cs +++ b/AdventOfCode2018.Tests/Day14_Tests.cs @@ -1,95 +1,92 @@ -using Xunit; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class Day14_Tests { - public class Day14_Tests + #region ResolvePart1 + + [Fact] + public void ResolvePart1__Test1() { - #region ResolvePart1 + Day14 day = new(); - [Fact] - public void ResolvePart1__Test1() - { - Day14 day = new Day14(); + string result = day.ResolvePart1(new[] { "9", }); - string result = day.ResolvePart1(new string[] { "9", }); - - Assert.Equal("5158916779", result); - } - - [Fact] - public void ResolvePart1__Test2() - { - Day14 day = new Day14(); - - string result = day.ResolvePart1(new string[] { "5", }); - - Assert.Equal("0124515891", result); - } - - [Fact] - public void ResolvePart1__Test3() - { - Day14 day = new Day14(); - - string result = day.ResolvePart1(new string[] { "18", }); - - Assert.Equal("9251071085", result); - } - - [Fact] - public void ResolvePart1__Test4() - { - Day14 day = new Day14(); - - string result = day.ResolvePart1(new string[] { "2018", }); - - Assert.Equal("5941429882", result); - } - - #endregion ResolvePart1 - - #region ResolvePart2 - - [Fact] - public void ResolvePart2__Test1() - { - Day14 day = new Day14(); - - string result = day.ResolvePart2(new string[] { "51589", }); - - Assert.Equal("9", result); - } - - [Fact] - public void ResolvePart2__Test2() - { - Day14 day = new Day14(); - - string result = day.ResolvePart2(new string[] { "01245", }); - - Assert.Equal("5", result); - } - - [Fact] - public void ResolvePart2__Test3() - { - Day14 day = new Day14(); - - string result = day.ResolvePart2(new string[] { "92510", }); - - Assert.Equal("18", result); - } - - [Fact] - public void ResolvePart2__Test4() - { - Day14 day = new Day14(); - - string result = day.ResolvePart2(new string[] { "59414", }); - - Assert.Equal("2018", result); - } - - #endregion ResolvePart2 + Assert.Equal("5158916779", result); } + + [Fact] + public void ResolvePart1__Test2() + { + Day14 day = new(); + + string result = day.ResolvePart1(new[] { "5", }); + + Assert.Equal("0124515891", result); + } + + [Fact] + public void ResolvePart1__Test3() + { + Day14 day = new(); + + string result = day.ResolvePart1(new[] { "18", }); + + Assert.Equal("9251071085", result); + } + + [Fact] + public void ResolvePart1__Test4() + { + Day14 day = new(); + + string result = day.ResolvePart1(new[] { "2018", }); + + Assert.Equal("5941429882", result); + } + + #endregion ResolvePart1 + + #region ResolvePart2 + + [Fact] + public void ResolvePart2__Test1() + { + Day14 day = new(); + + string result = day.ResolvePart2(new[] { "51589", }); + + Assert.Equal("9", result); + } + + [Fact] + public void ResolvePart2__Test2() + { + Day14 day = new(); + + string result = day.ResolvePart2(new[] { "01245", }); + + Assert.Equal("5", result); + } + + [Fact] + public void ResolvePart2__Test3() + { + Day14 day = new(); + + string result = day.ResolvePart2(new[] { "92510", }); + + Assert.Equal("18", result); + } + + [Fact] + public void ResolvePart2__Test4() + { + Day14 day = new(); + + string result = day.ResolvePart2(new[] { "59414", }); + + Assert.Equal("2018", result); + } + + #endregion ResolvePart2 } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/Day15_Tests.cs b/AdventOfCode2018.Tests/Day15_Tests.cs index ad7d78b..9a185f6 100644 --- a/AdventOfCode2018.Tests/Day15_Tests.cs +++ b/AdventOfCode2018.Tests/Day15_Tests.cs @@ -1,223 +1,214 @@ -using Xunit; -using AdventOfCode2018; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class Day15_Tests { - public class Day15_Tests + #region ResolvePart1 + + [Fact] + public void ResolvePart1__Test1() { - #region ResolvePart1 + Day15 day = new(); - [Fact] - public void ResolvePart1__Test1() - { - Day15 day = new Day15(); + string result = day.ResolvePart1(new[] { + "#######", + "#.G...#", + "#...EG#", + "#.#.#G#", + "#..G#E#", + "#.....#", + "#######", + }); - string result = day.ResolvePart1(new string[] { - "#######", - "#.G...#", - "#...EG#", - "#.#.#G#", - "#..G#E#", - "#.....#", - "#######", - }); - - Assert.Equal("27730", result); - } - - [Fact] - public void ResolvePart1__Test2() - { - Day15 day = new Day15(); - - string result = day.ResolvePart1(new string[] { - "#######", - "#G..#E#", - "#E#E.E#", - "#G.##.#", - "#...#E#", - "#...E.#", - "#######", - }); - - Assert.Equal("36334", result); - } - - [Fact] - public void ResolvePart1__Test3() - { - Day15 day = new Day15(); - - string result = day.ResolvePart1(new string[] { - "#######", - "#E..EG#", - "#.#G.E#", - "#E.##E#", - "#G..#.#", - "#..E#.#", - "#######", - }); - - Assert.Equal("39514", result); - } - - [Fact] - public void ResolvePart1__Test4() - { - Day15 day = new Day15(); - - string result = day.ResolvePart1(new string[] { - "#######", - "#E.G#.#", - "#.#G..#", - "#G.#.G#", - "#G..#.#", - "#...E.#", - "#######", - }); - - Assert.Equal("27755", result); - } - - [Fact] - public void ResolvePart1__Test5() - { - Day15 day = new Day15(); - - string result = day.ResolvePart1(new string[] { - "#######", - "#.E...#", - "#.#..G#", - "#.###.#", - "#E#G#G#", - "#...#G#", - "#######", - }); - - Assert.Equal("28944", result); - } - - [Fact] - public void ResolvePart1__Test6() - { - Day15 day = new Day15(); - - string result = day.ResolvePart1(new string[] { - "#########", - "#G......#", - "#.E.#...#", - "#..##..G#", - "#...##..#", - "#...#...#", - "#.G...G.#", - "#.....G.#", - "#########", - }); - - Assert.Equal("18740", result); - } - - #endregion ResolvePart1 - - #region ResolvePart2 - - [Fact] - public void ResolvePart2__Test1() - { - Day15 day = new Day15(); - - string result = day.ResolvePart2(new string[] { - "#######", - "#.G...#", - "#...EG#", - "#.#.#G#", - "#..G#E#", - "#.....#", - "#######", - }); - - Assert.Equal("4988", result); - } - - [Fact] - public void ResolvePart2__Test3() - { - Day15 day = new Day15(); - - string result = day.ResolvePart2(new string[] { - "#######", - "#E..EG#", - "#.#G.E#", - "#E.##E#", - "#G..#.#", - "#..E#.#", - "#######", - }); - - Assert.Equal("31284", result); - } - - [Fact] - public void ResolvePart2__Test4() - { - Day15 day = new Day15(); - - string result = day.ResolvePart2(new string[] { - "#######", - "#E.G#.#", - "#.#G..#", - "#G.#.G#", - "#G..#.#", - "#...E.#", - "#######", - }); - - Assert.Equal("3478", result); - } - - [Fact] - public void ResolvePart2__Test5() - { - Day15 day = new Day15(); - - string result = day.ResolvePart2(new string[] { - "#######", - "#.E...#", - "#.#..G#", - "#.###.#", - "#E#G#G#", - "#...#G#", - "#######", - }); - - Assert.Equal("6474", result); - } - - [Fact] - public void ResolvePart2__Test6() - { - Day15 day = new Day15(); - - string result = day.ResolvePart2(new string[] { - "#########", - "#G......#", - "#.E.#...#", - "#..##..G#", - "#...##..#", - "#...#...#", - "#.G...G.#", - "#.....G.#", - "#########", - }); - - Assert.Equal("1140", result); - } - - #endregion ResolvePart2 + Assert.Equal("27730", result); } + + [Fact] + public void ResolvePart1__Test2() + { + Day15 day = new(); + + string result = day.ResolvePart1(new[] { + "#######", + "#G..#E#", + "#E#E.E#", + "#G.##.#", + "#...#E#", + "#...E.#", + "#######", + }); + + Assert.Equal("36334", result); + } + + [Fact] + public void ResolvePart1__Test3() + { + Day15 day = new(); + + string result = day.ResolvePart1(new[] { + "#######", + "#E..EG#", + "#.#G.E#", + "#E.##E#", + "#G..#.#", + "#..E#.#", + "#######", + }); + + Assert.Equal("39514", result); + } + + [Fact] + public void ResolvePart1__Test4() + { + Day15 day = new(); + + string result = day.ResolvePart1(new[] { + "#######", + "#E.G#.#", + "#.#G..#", + "#G.#.G#", + "#G..#.#", + "#...E.#", + "#######", + }); + + Assert.Equal("27755", result); + } + + [Fact] + public void ResolvePart1__Test5() + { + Day15 day = new(); + + string result = day.ResolvePart1(new[] { + "#######", + "#.E...#", + "#.#..G#", + "#.###.#", + "#E#G#G#", + "#...#G#", + "#######", + }); + + Assert.Equal("28944", result); + } + + [Fact] + public void ResolvePart1__Test6() + { + Day15 day = new(); + + string result = day.ResolvePart1(new[] { + "#########", + "#G......#", + "#.E.#...#", + "#..##..G#", + "#...##..#", + "#...#...#", + "#.G...G.#", + "#.....G.#", + "#########", + }); + + Assert.Equal("18740", result); + } + + #endregion ResolvePart1 + + #region ResolvePart2 + + [Fact] + public void ResolvePart2__Test1() + { + Day15 day = new(); + + string result = day.ResolvePart2(new[] { + "#######", + "#.G...#", + "#...EG#", + "#.#.#G#", + "#..G#E#", + "#.....#", + "#######", + }); + + Assert.Equal("4988", result); + } + + [Fact] + public void ResolvePart2__Test3() + { + Day15 day = new(); + + string result = day.ResolvePart2(new[] { + "#######", + "#E..EG#", + "#.#G.E#", + "#E.##E#", + "#G..#.#", + "#..E#.#", + "#######", + }); + + Assert.Equal("31284", result); + } + + [Fact] + public void ResolvePart2__Test4() + { + Day15 day = new(); + + string result = day.ResolvePart2(new[] { + "#######", + "#E.G#.#", + "#.#G..#", + "#G.#.G#", + "#G..#.#", + "#...E.#", + "#######", + }); + + Assert.Equal("3478", result); + } + + [Fact] + public void ResolvePart2__Test5() + { + Day15 day = new(); + + string result = day.ResolvePart2(new[] { + "#######", + "#.E...#", + "#.#..G#", + "#.###.#", + "#E#G#G#", + "#...#G#", + "#######", + }); + + Assert.Equal("6474", result); + } + + [Fact] + public void ResolvePart2__Test6() + { + Day15 day = new(); + + string result = day.ResolvePart2(new[] { + "#########", + "#G......#", + "#.E.#...#", + "#..##..G#", + "#...##..#", + "#...#...#", + "#.G...G.#", + "#.....G.#", + "#########", + }); + + Assert.Equal("1140", result); + } + + #endregion ResolvePart2 } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/Day23_Tests.cs b/AdventOfCode2018.Tests/Day23_Tests.cs index 5b570f2..fa4814f 100644 --- a/AdventOfCode2018.Tests/Day23_Tests.cs +++ b/AdventOfCode2018.Tests/Day23_Tests.cs @@ -1,45 +1,41 @@ -using AdventOfCode2018; -using Xunit; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class Day23_Tests { - public class Day23_Tests + [Fact] + public void ResolvePart1__Test() { - [Fact] - public void ResolvePart1__Test() - { - Day23 day = new Day23(); + Day23 day = new(); - string result = day.ResolvePart1(new string[] { - "pos=<0,0,0>, r=4", - "pos=<1,0,0>, r=1", - "pos=<4,0,0>, r=3", - "pos=<0,2,0>, r=1", - "pos=<0,5,0>, r=3", - "pos=<0,0,3>, r=1", - "pos=<1,1,1>, r=1", - "pos=<1,1,2>, r=1", - "pos=<1,3,1>, r=1", - }); + string result = day.ResolvePart1(new[] { + "pos=<0,0,0>, r=4", + "pos=<1,0,0>, r=1", + "pos=<4,0,0>, r=3", + "pos=<0,2,0>, r=1", + "pos=<0,5,0>, r=3", + "pos=<0,0,3>, r=1", + "pos=<1,1,1>, r=1", + "pos=<1,1,2>, r=1", + "pos=<1,3,1>, r=1", + }); - Assert.Equal("7", result); - } + Assert.Equal("7", result); + } - [Fact] - public void ResolvePart2__Test() - { - Day23 day = new Day23(); + [Fact] + public void ResolvePart2__Test() + { + Day23 day = new(); - string result = day.ResolvePart2(new string[] { - "pos=<10,12,12>, r=2", - "pos=<12,14,12>, r=2", - "pos=<16,12,12>, r=4", - "pos=<14,14,14>, r=6", - "pos=<50,50,50>, r=200", - "pos=<10,10,10>, r=5", - }); + string result = day.ResolvePart2(new[] { + "pos=<10,12,12>, r=2", + "pos=<12,14,12>, r=2", + "pos=<16,12,12>, r=4", + "pos=<14,14,14>, r=6", + "pos=<50,50,50>, r=200", + "pos=<10,10,10>, r=5", + }); - Assert.Equal("36", result); - } + Assert.Equal("36", result); } } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/GuardEvent_Tests.cs b/AdventOfCode2018.Tests/GuardEvent_Tests.cs index f2281a4..89a2ab1 100644 --- a/AdventOfCode2018.Tests/GuardEvent_Tests.cs +++ b/AdventOfCode2018.Tests/GuardEvent_Tests.cs @@ -1,133 +1,131 @@ using System.Collections.Generic; -using Xunit; -namespace AdventOfCode2018.Tests +namespace AdventOfCode2018.Tests; + +public class GuardEvent_Tests { - public class GuardEvent_Tests + #region FromString + + [Fact] + public void FromString__ShiftBegin() { - #region FromString + GuardEvent guardEvent = GuardEvent.FromString("[1518-11-01 00:00] Guard #10 begins shift"); - [Fact] - public void FromString__ShiftBegin() - { - GuardEvent guardEvent = GuardEvent.FromString("[1518-11-01 00:00] Guard #10 begins shift"); - - Assert.Equal(10, guardEvent.ID); - Assert.Equal(11, guardEvent.Date.Month); - Assert.Equal(1, guardEvent.Date.Day); - Assert.Equal(0, guardEvent.Date.Hour); - Assert.Equal(0, guardEvent.Date.Minute); - Assert.Equal(GuardEventType.ShiftBegin, guardEvent.Type); - } - - [Fact] - public void FromString__FallSleep() - { - GuardEvent guardEvent = GuardEvent.FromString("[1518-11-02 00:40] falls asleep"); - - Assert.Equal(null, guardEvent.ID); - Assert.Equal(11, guardEvent.Date.Month); - Assert.Equal(2, guardEvent.Date.Day); - Assert.Equal(0, guardEvent.Date.Hour); - Assert.Equal(40, guardEvent.Date.Minute); - Assert.Equal(GuardEventType.FallSleep, guardEvent.Type); - } - - [Fact] - public void FromString__WakeUp() - { - GuardEvent guardEvent = GuardEvent.FromString("[1518-11-03 00:29] wakes up"); - - Assert.Equal(null, guardEvent.ID); - Assert.Equal(11, guardEvent.Date.Month); - Assert.Equal(3, guardEvent.Date.Day); - Assert.Equal(0, guardEvent.Date.Hour); - Assert.Equal(29, guardEvent.Date.Minute); - Assert.Equal(GuardEventType.WakeUp, guardEvent.Type); - } - - #endregion FromString - - #region FromStringArray - - [Fact] - public void FromStringArray__TestBase() - { - List guardEvents = GuardEvent.FromStringArray(new string[] { - "[1518-11-01 00:00] Guard #10 begins shift", - "[1518-11-01 00:05] falls asleep", - "[1518-11-01 00:25] wakes up", - "[1518-11-01 00:30] falls asleep", - "[1518-11-01 00:55] wakes up", - "[1518-11-01 23:58] Guard #99 begins shift", - "[1518-11-02 00:40] falls asleep", - "[1518-11-02 00:50] wakes up", - }); - - Assert.Equal(10, guardEvents[0].ID); - Assert.Equal(GuardEventType.ShiftBegin, guardEvents[0].Type); - - Assert.Equal(10, guardEvents[1].ID); - Assert.Equal(GuardEventType.FallSleep, guardEvents[1].Type); - - Assert.Equal(10, guardEvents[2].ID); - Assert.Equal(GuardEventType.WakeUp, guardEvents[2].Type); - - Assert.Equal(10, guardEvents[3].ID); - Assert.Equal(GuardEventType.FallSleep, guardEvents[3].Type); - - Assert.Equal(10, guardEvents[4].ID); - Assert.Equal(GuardEventType.WakeUp, guardEvents[4].Type); - - Assert.Equal(99, guardEvents[5].ID); - Assert.Equal(GuardEventType.ShiftBegin, guardEvents[5].Type); - - Assert.Equal(99, guardEvents[6].ID); - Assert.Equal(GuardEventType.FallSleep, guardEvents[6].Type); - - Assert.Equal(99, guardEvents[7].ID); - Assert.Equal(GuardEventType.WakeUp, guardEvents[7].Type); - } - - [Fact] - public void FromStringArray__TestBaseUnsorted() - { - List guardEvents = GuardEvent.FromStringArray(new string[] { - "[1518-11-01 00:00] Guard #10 begins shift", - "[1518-11-01 23:58] Guard #99 begins shift", - "[1518-11-01 00:30] falls asleep", - "[1518-11-02 00:40] falls asleep", - "[1518-11-01 00:05] falls asleep", - "[1518-11-02 00:50] wakes up", - "[1518-11-01 00:55] wakes up", - "[1518-11-01 00:25] wakes up", - }); - - Assert.Equal(10, guardEvents[0].ID); - Assert.Equal(GuardEventType.ShiftBegin, guardEvents[0].Type); - - Assert.Equal(10, guardEvents[1].ID); - Assert.Equal(GuardEventType.FallSleep, guardEvents[1].Type); - - Assert.Equal(10, guardEvents[2].ID); - Assert.Equal(GuardEventType.WakeUp, guardEvents[2].Type); - - Assert.Equal(10, guardEvents[3].ID); - Assert.Equal(GuardEventType.FallSleep, guardEvents[3].Type); - - Assert.Equal(10, guardEvents[4].ID); - Assert.Equal(GuardEventType.WakeUp, guardEvents[4].Type); - - Assert.Equal(99, guardEvents[5].ID); - Assert.Equal(GuardEventType.ShiftBegin, guardEvents[5].Type); - - Assert.Equal(99, guardEvents[6].ID); - Assert.Equal(GuardEventType.FallSleep, guardEvents[6].Type); - - Assert.Equal(99, guardEvents[7].ID); - Assert.Equal(GuardEventType.WakeUp, guardEvents[7].Type); - } - - #endregion FromStringArray + Assert.Equal(10, guardEvent.ID); + Assert.Equal(11, guardEvent.Date.Month); + Assert.Equal(1, guardEvent.Date.Day); + Assert.Equal(0, guardEvent.Date.Hour); + Assert.Equal(0, guardEvent.Date.Minute); + Assert.Equal(GuardEventType.ShiftBegin, guardEvent.Type); } + + [Fact] + public void FromString__FallSleep() + { + GuardEvent guardEvent = GuardEvent.FromString("[1518-11-02 00:40] falls asleep"); + + Assert.Null(guardEvent.ID); + Assert.Equal(11, guardEvent.Date.Month); + Assert.Equal(2, guardEvent.Date.Day); + Assert.Equal(0, guardEvent.Date.Hour); + Assert.Equal(40, guardEvent.Date.Minute); + Assert.Equal(GuardEventType.FallSleep, guardEvent.Type); + } + + [Fact] + public void FromString__WakeUp() + { + GuardEvent guardEvent = GuardEvent.FromString("[1518-11-03 00:29] wakes up"); + + Assert.Null(guardEvent.ID); + Assert.Equal(11, guardEvent.Date.Month); + Assert.Equal(3, guardEvent.Date.Day); + Assert.Equal(0, guardEvent.Date.Hour); + Assert.Equal(29, guardEvent.Date.Minute); + Assert.Equal(GuardEventType.WakeUp, guardEvent.Type); + } + + #endregion FromString + + #region FromStringArray + + [Fact] + public void FromStringArray__TestBase() + { + List guardEvents = GuardEvent.FromStringArray(new[] { + "[1518-11-01 00:00] Guard #10 begins shift", + "[1518-11-01 00:05] falls asleep", + "[1518-11-01 00:25] wakes up", + "[1518-11-01 00:30] falls asleep", + "[1518-11-01 00:55] wakes up", + "[1518-11-01 23:58] Guard #99 begins shift", + "[1518-11-02 00:40] falls asleep", + "[1518-11-02 00:50] wakes up", + }); + + Assert.Equal(10, guardEvents[0].ID); + Assert.Equal(GuardEventType.ShiftBegin, guardEvents[0].Type); + + Assert.Equal(10, guardEvents[1].ID); + Assert.Equal(GuardEventType.FallSleep, guardEvents[1].Type); + + Assert.Equal(10, guardEvents[2].ID); + Assert.Equal(GuardEventType.WakeUp, guardEvents[2].Type); + + Assert.Equal(10, guardEvents[3].ID); + Assert.Equal(GuardEventType.FallSleep, guardEvents[3].Type); + + Assert.Equal(10, guardEvents[4].ID); + Assert.Equal(GuardEventType.WakeUp, guardEvents[4].Type); + + Assert.Equal(99, guardEvents[5].ID); + Assert.Equal(GuardEventType.ShiftBegin, guardEvents[5].Type); + + Assert.Equal(99, guardEvents[6].ID); + Assert.Equal(GuardEventType.FallSleep, guardEvents[6].Type); + + Assert.Equal(99, guardEvents[7].ID); + Assert.Equal(GuardEventType.WakeUp, guardEvents[7].Type); + } + + [Fact] + public void FromStringArray__TestBaseUnsorted() + { + List guardEvents = GuardEvent.FromStringArray(new[] { + "[1518-11-01 00:00] Guard #10 begins shift", + "[1518-11-01 23:58] Guard #99 begins shift", + "[1518-11-01 00:30] falls asleep", + "[1518-11-02 00:40] falls asleep", + "[1518-11-01 00:05] falls asleep", + "[1518-11-02 00:50] wakes up", + "[1518-11-01 00:55] wakes up", + "[1518-11-01 00:25] wakes up", + }); + + Assert.Equal(10, guardEvents[0].ID); + Assert.Equal(GuardEventType.ShiftBegin, guardEvents[0].Type); + + Assert.Equal(10, guardEvents[1].ID); + Assert.Equal(GuardEventType.FallSleep, guardEvents[1].Type); + + Assert.Equal(10, guardEvents[2].ID); + Assert.Equal(GuardEventType.WakeUp, guardEvents[2].Type); + + Assert.Equal(10, guardEvents[3].ID); + Assert.Equal(GuardEventType.FallSleep, guardEvents[3].Type); + + Assert.Equal(10, guardEvents[4].ID); + Assert.Equal(GuardEventType.WakeUp, guardEvents[4].Type); + + Assert.Equal(99, guardEvents[5].ID); + Assert.Equal(GuardEventType.ShiftBegin, guardEvents[5].Type); + + Assert.Equal(99, guardEvents[6].ID); + Assert.Equal(GuardEventType.FallSleep, guardEvents[6].Type); + + Assert.Equal(99, guardEvents[7].ID); + Assert.Equal(GuardEventType.WakeUp, guardEvents[7].Type); + } + + #endregion FromStringArray } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/MarbleGame_Tests.cs b/AdventOfCode2018.Tests/MarbleGame_Tests.cs index b032810..11db309 100644 --- a/AdventOfCode2018.Tests/MarbleGame_Tests.cs +++ b/AdventOfCode2018.Tests/MarbleGame_Tests.cs @@ -1,73 +1,70 @@ -using Xunit; +namespace AdventOfCode2018.Tests; -namespace AdventOfCode2018.Tests +public class MarbleGame_Tests { - public class MarbleGame_Tests + [Fact] + public void PlayGame__Test1() { - [Fact] - public void PlayGame__Test1() - { - MarbleGame marbleGame = new MarbleGame(); + MarbleGame marbleGame = new(); - marbleGame.PlayGame(9, 25); - long highScore = marbleGame.GetHighScore(); + marbleGame.PlayGame(9, 25); + long highScore = marbleGame.GetHighScore(); - Assert.Equal(32, highScore); - } + Assert.Equal(32, highScore); + } - [Fact] - public void PlayGame__Test2() - { - MarbleGame marbleGame = new MarbleGame(); + [Fact] + public void PlayGame__Test2() + { + MarbleGame marbleGame = new(); - marbleGame.PlayGame(10, 1618); - long highScore = marbleGame.GetHighScore(); + marbleGame.PlayGame(10, 1618); + long highScore = marbleGame.GetHighScore(); - Assert.Equal(8317, highScore); - } + Assert.Equal(8317, highScore); + } - [Fact] - public void PlayGame__Test3() - { - MarbleGame marbleGame = new MarbleGame(); + [Fact] + public void PlayGame__Test3() + { + MarbleGame marbleGame = new(); - marbleGame.PlayGame(13, 7999); - long highScore = marbleGame.GetHighScore(); + marbleGame.PlayGame(13, 7999); + long highScore = marbleGame.GetHighScore(); - Assert.Equal(146373, highScore); - } + Assert.Equal(146373, highScore); + } - [Fact] - public void PlayGame__Test4() - { - MarbleGame marbleGame = new MarbleGame(); + [Fact] + public void PlayGame__Test4() + { + MarbleGame marbleGame = new(); - marbleGame.PlayGame(17, 1104); - long highScore = marbleGame.GetHighScore(); + marbleGame.PlayGame(17, 1104); + long highScore = marbleGame.GetHighScore(); - Assert.Equal(2764, highScore); - } + Assert.Equal(2764, highScore); + } - [Fact] - public void PlayGame__Test5() - { - MarbleGame marbleGame = new MarbleGame(); + [Fact] + public void PlayGame__Test5() + { + MarbleGame marbleGame = new(); - marbleGame.PlayGame(21, 6111); - long highScore = marbleGame.GetHighScore(); + marbleGame.PlayGame(21, 6111); + long highScore = marbleGame.GetHighScore(); - Assert.Equal(54718, highScore); - } + Assert.Equal(54718, highScore); + } - [Fact] - public void PlayGame__Test6() - { - MarbleGame marbleGame = new MarbleGame(); + [Fact] + public void PlayGame__Test6() + { + MarbleGame marbleGame = new(); - marbleGame.PlayGame(30, 5807); - long highScore = marbleGame.GetHighScore(); + marbleGame.PlayGame(30, 5807); + long highScore = marbleGame.GetHighScore(); - Assert.Equal(37305, highScore); - } + Assert.Equal(37305, highScore); } } \ No newline at end of file diff --git a/AdventOfCode2018.Tests/Usings.cs b/AdventOfCode2018.Tests/Usings.cs new file mode 100644 index 0000000..8c927eb --- /dev/null +++ b/AdventOfCode2018.Tests/Usings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file diff --git a/AdventOfCode2018/Day01.cs b/AdventOfCode2018/Day01.cs index a24274d..19c46c2 100644 --- a/AdventOfCode2018/Day01.cs +++ b/AdventOfCode2018/Day01.cs @@ -1,71 +1,97 @@ using System.Collections.Generic; -namespace AdventOfCode2018 +namespace AdventOfCode2018; +/* + --- Day 1: Chronal Calibration --- + +"We've detected some temporal anomalies," one of Santa's Elves at the Temporal Anomaly Research and Detection Instrument Station tells you. She sounded pretty worried when she called you down here. "At 500-year intervals into the past, someone has been changing Santa's history!" + +"The good news is that the changes won't propagate to our time stream for another 25 days, and we have a device" - she attaches something to your wrist - "that will let you fix the changes with no such propagation delay. It's configured to send you 500 years further into the past every few days; that was the best we could do on such short notice." + +"The bad news is that we are detecting roughly fifty anomalies throughout time; the device will indicate fixed anomalies with stars. The other bad news is that we only have one device and you're the best person for the job! Good lu--" She taps a button on the device and you suddenly feel like you're falling. To save Christmas, you need to get all fifty stars by December 25th. + +Collect stars by solving puzzles. Two puzzles will be made available on each day in the advent calendar; the second puzzle is unlocked when you complete the first. Each puzzle grants one star. Good luck! + +After feeling like you've been falling for a few minutes, you look at the device's tiny screen. "Error: Device must be calibrated before first use. Frequency drift detected. Cannot maintain destination lock." Below the message, the device shows a sequence of changes in frequency (your puzzle input). A value like +6 means the current frequency increases by 6; a value like -3 means the current frequency decreases by 3. + +For example, if the device displays frequency changes of +1, -2, +3, +1, then starting from a frequency of zero, the following changes would occur: + + Current frequency 0, change of +1; resulting frequency 1. + Current frequency 1, change of -2; resulting frequency -1. + Current frequency -1, change of +3; resulting frequency 2. + Current frequency 2, change of +1; resulting frequency 3. + +In this example, the resulting frequency is 3. + +Here are other example situations: + + +1, +1, +1 results in 3 + +1, +1, -2 results in 0 + -1, -2, -3 results in -6 + +Starting with a frequency of zero, what is the resulting frequency after all of the changes in frequency have been applied? + +--- Part Two --- + +You notice that the device repeats the same frequency change list over and over. To calibrate the device, you need to find the first frequency it reaches twice. + +For example, using the same list of changes above, the device would loop as follows: + + Current frequency 0, change of +1; resulting frequency 1. + Current frequency 1, change of -2; resulting frequency -1. + Current frequency -1, change of +3; resulting frequency 2. + Current frequency 2, change of +1; resulting frequency 3. + (At this point, the device continues from the start of the list.) + Current frequency 3, change of +1; resulting frequency 4. + Current frequency 4, change of -2; resulting frequency 2, which has already been seen. + +In this example, the first frequency reached twice is 2. Note that your device might need to repeat its list of frequency changes many times before a duplicate frequency is found, and that duplicates might be found while in the middle of processing the list. + +Here are other examples: + + +1, -1 first reaches 0 twice. + +3, +3, +4, -2, -4 first reaches 10 twice. + -6, +3, +8, +5, -6 first reaches 5 twice. + +7, +7, -2, -7, -4 first reaches 14 twice. + +What is the first frequency your device reaches twice? + +*/ + +public class Day01 : IDay { - /* - --- Day 1: Chronal Calibration --- - - "We've detected some temporal anomalies," one of Santa's Elves at the Temporal Anomaly Research and Detection Instrument Station tells you. She sounded pretty worried when she called you down here. "At 500-year intervals into the past, someone has been changing Santa's history!" - - "The good news is that the changes won't propagate to our time stream for another 25 days, and we have a device" - she attaches something to your wrist - "that will let you fix the changes with no such propagation delay. It's configured to send you 500 years further into the past every few days; that was the best we could do on such short notice." - - "The bad news is that we are detecting roughly fifty anomalies throughout time; the device will indicate fixed anomalies with stars. The other bad news is that we only have one device and you're the best person for the job! Good lu--" She taps a button on the device and you suddenly feel like you're falling. To save Christmas, you need to get all fifty stars by December 25th. - - Collect stars by solving puzzles. Two puzzles will be made available on each day in the advent calendar; the second puzzle is unlocked when you complete the first. Each puzzle grants one star. Good luck! - - After feeling like you've been falling for a few minutes, you look at the device's tiny screen. "Error: Device must be calibrated before first use. Frequency drift detected. Cannot maintain destination lock." Below the message, the device shows a sequence of changes in frequency (your puzzle input). A value like +6 means the current frequency increases by 6; a value like -3 means the current frequency decreases by 3. - - For example, if the device displays frequency changes of +1, -2, +3, +1, then starting from a frequency of zero, the following changes would occur: - - Current frequency 0, change of +1; resulting frequency 1. - Current frequency 1, change of -2; resulting frequency -1. - Current frequency -1, change of +3; resulting frequency 2. - Current frequency 2, change of +1; resulting frequency 3. - - In this example, the resulting frequency is 3. - - Here are other example situations: - - +1, +1, +1 results in 3 - +1, +1, -2 results in 0 - -1, -2, -3 results in -6 - - Starting with a frequency of zero, what is the resulting frequency after all of the changes in frequency have been applied? - - --- Part Two --- - - You notice that the device repeats the same frequency change list over and over. To calibrate the device, you need to find the first frequency it reaches twice. - - For example, using the same list of changes above, the device would loop as follows: - - Current frequency 0, change of +1; resulting frequency 1. - Current frequency 1, change of -2; resulting frequency -1. - Current frequency -1, change of +3; resulting frequency 2. - Current frequency 2, change of +1; resulting frequency 3. - (At this point, the device continues from the start of the list.) - Current frequency 3, change of +1; resulting frequency 4. - Current frequency 4, change of -2; resulting frequency 2, which has already been seen. - - In this example, the first frequency reached twice is 2. Note that your device might need to repeat its list of frequency changes many times before a duplicate frequency is found, and that duplicates might be found while in the middle of processing the list. - - Here are other examples: - - +1, -1 first reaches 0 twice. - +3, +3, +4, -2, -4 first reaches 10 twice. - -6, +3, +8, +5, -6 first reaches 5 twice. - +7, +7, -2, -7, -4 first reaches 14 twice. - - What is the first frequency your device reaches twice? - - */ - - public class Day01 : IDay + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) + int accumulator = 0; + foreach (string input in inputs) + { + int intInput; + if (int.TryParse(input.Substring(1), out intInput)) + { + if (input[0] == '-') + { + accumulator -= intInput; + } + if (input[0] == '+') + { + accumulator += intInput; + } + } + } + + return accumulator.ToString(); + } + + public string ResolvePart2(string[] inputs) + { + int accumulator = 0; + List accumulatorHistory = new(); + int? repeatedAccumulator = null; + while (repeatedAccumulator == null) { - int accumulator = 0; foreach (string input in inputs) { + accumulatorHistory.Add(accumulator); int intInput; if (int.TryParse(input.Substring(1), out intInput)) { @@ -77,43 +103,15 @@ namespace AdventOfCode2018 { accumulator += intInput; } - } - } - return accumulator.ToString(); - } - - public string ResolvePart2(string[] inputs) - { - int accumulator = 0; - List accumulatorHistory = new List(); - int? repeatedAccumulator = null; - while (repeatedAccumulator == null) - { - foreach (string input in inputs) - { - accumulatorHistory.Add(accumulator); - int intInput; - if (int.TryParse(input.Substring(1), out intInput)) + if (accumulatorHistory.Contains(accumulator)) { - if (input[0] == '-') - { - accumulator -= intInput; - } - if (input[0] == '+') - { - accumulator += intInput; - } - - if (accumulatorHistory.Contains(accumulator)) - { - repeatedAccumulator = accumulator; - break; - } + repeatedAccumulator = accumulator; + break; } } } - return repeatedAccumulator.ToString(); } + return repeatedAccumulator.ToString(); } -} +} \ No newline at end of file diff --git a/AdventOfCode2018/Day02.cs b/AdventOfCode2018/Day02.cs index d53afab..1134e9d 100644 --- a/AdventOfCode2018/Day02.cs +++ b/AdventOfCode2018/Day02.cs @@ -2,117 +2,115 @@ using System.Linq; using System.Text; -namespace AdventOfCode2018 +namespace AdventOfCode2018; +/* +--- Day 2: Inventory Management System --- + +You stop falling through time, catch your breath, and check the screen on the device. "Destination reached. Current Year: 1518. Current Location: North Pole Utility Closet 83N10." You made it! Now, to find those anomalies. + +Outside the utility closet, you hear footsteps and a voice. "...I'm not sure either. But now that so many people have chimneys, maybe he could sneak in that way?" Another voice responds, "Actually, we've been working on a new kind of suit that would let him fit through tight spaces like that. But, I heard that a few days ago, they lost the prototype fabric, the design plans, everything! Nobody on the team can even seem to remember important details of the project!" + +"Wouldn't they have had enough fabric to fill several boxes in the warehouse? They'd be stored together, so the box IDs should be similar. Too bad it would take forever to search the warehouse for two similar box IDs..." They walk too far away to hear any more. + +Late at night, you sneak to the warehouse - who knows what kinds of paradoxes you could cause if you were discovered - and use your fancy wrist device to quickly scan every box and produce a list of the likely candidates (your puzzle input). + +To make sure you didn't miss any, you scan the likely candidate boxes again, counting the number that have an ID containing exactly two of any letter and then separately counting those with exactly three of any letter. You can multiply those two counts together to get a rudimentary checksum and compare it to what your device predicts. + +For example, if you see the following box IDs: + + abcdef contains no letters that appear exactly two or three times. + bababc contains two a and three b, so it counts for both. + abbcde contains two b, but no letter appears exactly three times. + abcccd contains three c, but no letter appears exactly two times. + aabcdd contains two a and two d, but it only counts once. + abcdee contains two e. + ababab contains three a and three b, but it only counts once. + +Of these box IDs, four of them contain a letter which appears exactly twice, and three of them contain a letter which appears exactly three times. Multiplying these together produces a checksum of 4 * 3 = 12. + +What is the checksum for your list of box IDs? + +--- Part Two --- + +Confident that your list of box IDs is complete, you're ready to find the boxes full of prototype fabric. + +The boxes will have IDs which differ by exactly one character at the same position in both strings. For example, given the following box IDs: + +abcde +fghij +klmno +pqrst +fguij +axcye +wvxyz + +The IDs abcde and axcye are close, but they differ by two characters (the second and fourth). However, the IDs fghij and fguij differ by exactly one character, the third (h and u). Those must be the correct boxes. + +What letters are common between the two correct box IDs? (In the example above, this is found by removing the differing character from either ID, producing fgij.) + +*/ + +public class Day02 : IDay { - /* - --- Day 2: Inventory Management System --- - - You stop falling through time, catch your breath, and check the screen on the device. "Destination reached. Current Year: 1518. Current Location: North Pole Utility Closet 83N10." You made it! Now, to find those anomalies. - - Outside the utility closet, you hear footsteps and a voice. "...I'm not sure either. But now that so many people have chimneys, maybe he could sneak in that way?" Another voice responds, "Actually, we've been working on a new kind of suit that would let him fit through tight spaces like that. But, I heard that a few days ago, they lost the prototype fabric, the design plans, everything! Nobody on the team can even seem to remember important details of the project!" - - "Wouldn't they have had enough fabric to fill several boxes in the warehouse? They'd be stored together, so the box IDs should be similar. Too bad it would take forever to search the warehouse for two similar box IDs..." They walk too far away to hear any more. - - Late at night, you sneak to the warehouse - who knows what kinds of paradoxes you could cause if you were discovered - and use your fancy wrist device to quickly scan every box and produce a list of the likely candidates (your puzzle input). - - To make sure you didn't miss any, you scan the likely candidate boxes again, counting the number that have an ID containing exactly two of any letter and then separately counting those with exactly three of any letter. You can multiply those two counts together to get a rudimentary checksum and compare it to what your device predicts. - - For example, if you see the following box IDs: - - abcdef contains no letters that appear exactly two or three times. - bababc contains two a and three b, so it counts for both. - abbcde contains two b, but no letter appears exactly three times. - abcccd contains three c, but no letter appears exactly two times. - aabcdd contains two a and two d, but it only counts once. - abcdee contains two e. - ababab contains three a and three b, but it only counts once. - - Of these box IDs, four of them contain a letter which appears exactly twice, and three of them contain a letter which appears exactly three times. Multiplying these together produces a checksum of 4 * 3 = 12. - - What is the checksum for your list of box IDs? - - --- Part Two --- - - Confident that your list of box IDs is complete, you're ready to find the boxes full of prototype fabric. - - The boxes will have IDs which differ by exactly one character at the same position in both strings. For example, given the following box IDs: - - abcde - fghij - klmno - pqrst - fguij - axcye - wvxyz - - The IDs abcde and axcye are close, but they differ by two characters (the second and fourth). However, the IDs fghij and fguij differ by exactly one character, the third (h and u). Those must be the correct boxes. - - What letters are common between the two correct box IDs? (In the example above, this is found by removing the differing character from either ID, producing fgij.) - - */ - - public class Day02 : IDay + private int CountOccurrencesOfLetter(string text, char letter) { - private int CountOccurrencesOfLetter(string text, char letter) - { - return text.Count(c => (c == letter)); - } - - private Tuple HasPairsAndTriplets(string text) - { - bool hasPair = false; - bool hasTriplet = false; - foreach (char c in text) - { - int count = CountOccurrencesOfLetter(text, c); - if (count == 2) { hasPair = true; } - if (count == 3) { hasTriplet = true; } - if (hasPair && hasTriplet) { break; } - } - return new Tuple(hasPair, hasTriplet); - } - - public string ResolvePart1(string[] inputs) - { - int pairsCount = 0; - int tripletsCount = 0; - foreach (string input in inputs) - { - var hasPairsAndTriplets = HasPairsAndTriplets(input); - if (hasPairsAndTriplets.Item1) { pairsCount++; } - if (hasPairsAndTriplets.Item2) { tripletsCount++; } - } - - long result = pairsCount * tripletsCount; - - return result.ToString(); - } - - private Tuple CompareIDPair(string id1, string id2) - { - if (id1.Length != id2.Length) { throw new ArgumentException("id1 and id2 parameters must be of same length"); } - int diffCount = 0; - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < id1.Length; i++) - { - if (id1[i] != id2[i]) { diffCount++; } - else { sb.Append(id1[i]); } - } - return new Tuple(diffCount, sb.ToString()); - } - - public string ResolvePart2(string[] inputs) - { - for (int i = 0; i < (inputs.Length - 1); i++) - { - for (int j = (i + 1); j < inputs.Length; j++) - { - var result = CompareIDPair(inputs[i], inputs[j]); - if (result.Item1 == 1) { return result.Item2; } - } - } - return string.Empty; - } - + return text.Count(c => (c == letter)); } -} + + private Tuple HasPairsAndTriplets(string text) + { + bool hasPair = false; + bool hasTriplet = false; + foreach (char c in text) + { + int count = CountOccurrencesOfLetter(text, c); + if (count == 2) { hasPair = true; } + if (count == 3) { hasTriplet = true; } + if (hasPair && hasTriplet) { break; } + } + return new Tuple(hasPair, hasTriplet); + } + + public string ResolvePart1(string[] inputs) + { + int pairsCount = 0; + int tripletsCount = 0; + foreach (string input in inputs) + { + var hasPairsAndTriplets = HasPairsAndTriplets(input); + if (hasPairsAndTriplets.Item1) { pairsCount++; } + if (hasPairsAndTriplets.Item2) { tripletsCount++; } + } + + long result = pairsCount * tripletsCount; + + return result.ToString(); + } + + private Tuple CompareIDPair(string id1, string id2) + { + if (id1.Length != id2.Length) { throw new ArgumentException("id1 and id2 parameters must be of same length"); } + int diffCount = 0; + StringBuilder sb = new(); + for (int i = 0; i < id1.Length; i++) + { + if (id1[i] != id2[i]) { diffCount++; } + else { sb.Append(id1[i]); } + } + return new Tuple(diffCount, sb.ToString()); + } + + public string ResolvePart2(string[] inputs) + { + for (int i = 0; i < (inputs.Length - 1); i++) + { + for (int j = (i + 1); j < inputs.Length; j++) + { + var result = CompareIDPair(inputs[i], inputs[j]); + if (result.Item1 == 1) { return result.Item2; } + } + } + return string.Empty; + } + +} \ No newline at end of file diff --git a/AdventOfCode2018/Day03.cs b/AdventOfCode2018/Day03.cs index 09e35dc..61999b4 100644 --- a/AdventOfCode2018/Day03.cs +++ b/AdventOfCode2018/Day03.cs @@ -2,180 +2,176 @@ using System.Collections.Generic; using System.Linq; -namespace AdventOfCode2018 +namespace AdventOfCode2018; +/* +--- Day 3: No Matter How You Slice It --- + +The Elves managed to locate the chimney-squeeze prototype fabric for Santa's suit (thanks to someone who helpfully wrote its box IDs on the wall of the warehouse in the middle of the night). Unfortunately, anomalies are still affecting them - nobody can even agree on how to cut the fabric. + +The whole piece of fabric they're working on is a very large square - at least 1000 inches on each side. + +Each Elf has made a claim about which area of fabric would be ideal for Santa's suit. All claims have an ID and consist of a single rectangle with edges parallel to the edges of the fabric. Each claim's rectangle is defined as follows: + + The number of inches between the left edge of the fabric and the left edge of the rectangle. + The number of inches between the top edge of the fabric and the top edge of the rectangle. + The width of the rectangle in inches. + The height of the rectangle in inches. + +A claim like #123 @ 3,2: 5x4 means that claim ID 123 specifies a rectangle 3 inches from the left edge, 2 inches from the top edge, 5 inches wide, and 4 inches tall. Visually, it claims the square inches of fabric represented by # (and ignores the square inches of fabric represented by .) in the diagram below: + +........... +........... +...#####... +...#####... +...#####... +...#####... +........... +........... +........... + +The problem is that many of the claims overlap, causing two or more claims to cover part of the same areas. For example, consider the following claims: + +#1 @ 1,3: 4x4 +#2 @ 3,1: 4x4 +#3 @ 5,5: 2x2 + +Visually, these claim the following areas: + +........ +...2222. +...2222. +.11XX22. +.11XX22. +.111133. +.111133. +........ + +The four square inches marked with X are claimed by both 1 and 2. (Claim 3, while adjacent to the others, does not overlap either of them.) + +If the Elves all proceed with their own plans, none of them will have enough fabric. How many square inches of fabric are within two or more claims? + +--- Part Two --- + +Amidst the chaos, you notice that exactly one claim doesn't overlap by even a single square inch of fabric with any other claim. If you can somehow draw attention to it, maybe the Elves will be able to make Santa's suit after all! + +For example, in the claims above, only claim 3 is intact after all claims are made. + +What is the ID of the only claim that doesn't overlap? + +*/ + +public class Day03 : IDay { - /* - --- Day 3: No Matter How You Slice It --- - - The Elves managed to locate the chimney-squeeze prototype fabric for Santa's suit (thanks to someone who helpfully wrote its box IDs on the wall of the warehouse in the middle of the night). Unfortunately, anomalies are still affecting them - nobody can even agree on how to cut the fabric. - - The whole piece of fabric they're working on is a very large square - at least 1000 inches on each side. - - Each Elf has made a claim about which area of fabric would be ideal for Santa's suit. All claims have an ID and consist of a single rectangle with edges parallel to the edges of the fabric. Each claim's rectangle is defined as follows: - - The number of inches between the left edge of the fabric and the left edge of the rectangle. - The number of inches between the top edge of the fabric and the top edge of the rectangle. - The width of the rectangle in inches. - The height of the rectangle in inches. - - A claim like #123 @ 3,2: 5x4 means that claim ID 123 specifies a rectangle 3 inches from the left edge, 2 inches from the top edge, 5 inches wide, and 4 inches tall. Visually, it claims the square inches of fabric represented by # (and ignores the square inches of fabric represented by .) in the diagram below: - - ........... - ........... - ...#####... - ...#####... - ...#####... - ...#####... - ........... - ........... - ........... - - The problem is that many of the claims overlap, causing two or more claims to cover part of the same areas. For example, consider the following claims: - - #1 @ 1,3: 4x4 - #2 @ 3,1: 4x4 - #3 @ 5,5: 2x2 - - Visually, these claim the following areas: - - ........ - ...2222. - ...2222. - .11XX22. - .11XX22. - .111133. - .111133. - ........ - - The four square inches marked with X are claimed by both 1 and 2. (Claim 3, while adjacent to the others, does not overlap either of them.) - - If the Elves all proceed with their own plans, none of them will have enough fabric. How many square inches of fabric are within two or more claims? - - --- Part Two --- - - Amidst the chaos, you notice that exactly one claim doesn't overlap by even a single square inch of fabric with any other claim. If you can somehow draw attention to it, maybe the Elves will be able to make Santa's suit after all! - - For example, in the claims above, only claim 3 is intact after all claims are made. - - What is the ID of the only claim that doesn't overlap? - - */ - - public class Day03 : IDay + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) + List claims = inputs.Select(i => Claim.FromString(i)).ToList(); + + const int edgeSize = 1000; + int[,] cells = new int[edgeSize, edgeSize]; + + foreach (Claim claim in claims) { - List claims = inputs.Select(i => Claim.FromString(i)).ToList(); - - const int edgeSize = 1000; - int[,] cells = new int[edgeSize, edgeSize]; - - foreach (Claim claim in claims) + for (int j = 0; j < claim.Height; j++) { - for (int j = 0; j < claim.Height; j++) + for (int i = 0; i < claim.Width; i++) { - for (int i = 0; i < claim.Width; i++) - { - cells[claim.Left + i, claim.Top + j]++; - } + cells[claim.Left + i, claim.Top + j]++; } } - - int overlappedArea = 0; - for (int j = 0; j < edgeSize; j++) - { - for (int i = 0; i < edgeSize; i++) - { - if (cells[i, j] > 1) - { - overlappedArea++; - } - } - } - return overlappedArea.ToString(); } - public string ResolvePart2(string[] inputs) + int overlappedArea = 0; + for (int j = 0; j < edgeSize; j++) { - List claims = inputs.Select(i => Claim.FromString(i)).ToList(); - - Claim unoverlappingClaim = null; - for (int i = 0; i < claims.Count; i++) + for (int i = 0; i < edgeSize; i++) { - bool overlaps = false; - for (int j = 0; j < claims.Count; j++) + if (cells[i, j] > 1) { - if (i == j) { continue; } - if (Claim.Overlaps(claims[i], claims[j])) - { - overlaps = true; - break; - } + overlappedArea++; } - if (overlaps == false) + } + } + return overlappedArea.ToString(); + } + + public string ResolvePart2(string[] inputs) + { + List claims = inputs.Select(i => Claim.FromString(i)).ToList(); + + Claim unoverlappingClaim = null; + for (int i = 0; i < claims.Count; i++) + { + bool overlaps = false; + for (int j = 0; j < claims.Count; j++) + { + if (i == j) { continue; } + if (Claim.Overlaps(claims[i], claims[j])) { - unoverlappingClaim = claims[i]; + overlaps = true; break; } } - return unoverlappingClaim.ID.ToString(); - - } - - public class Claim - { - public int ID { get; set; } - - public int Left { get; set; } - public int Top { get; set; } - - public int Width { get; set; } - public int Height { get; set; } - - public int MinX { get { return Left; } } - public int MaxX { get { return Left + Width; } } - - public int MinY { get { return Top; } } - public int MaxY { get { return Top + Height; } } - - public int GetArea() + if (overlaps == false) { - return Width * Height; - } - - public static Claim FromString(string strClaim) - { - Claim claim = new Claim(); - string[] parts = strClaim.Split(new string[] { " @ ", ",", ": ", "x", }, StringSplitOptions.None); - claim.ID = Convert.ToInt32(parts[0].Substring(1)); - claim.Left = Convert.ToInt32(parts[1]); - claim.Top = Convert.ToInt32(parts[2]); - claim.Width = Convert.ToInt32(parts[3]); - claim.Height = Convert.ToInt32(parts[4]); - return claim; - } - - public static bool Overlaps(Claim claim1, Claim claim2) - { - if (claim1.MinX <= claim2.MaxX && - claim2.MinX <= claim1.MaxX && - claim1.MinY <= claim2.MaxY && - claim2.MinY <= claim1.MaxY) - { - int minX = Math.Max(claim1.MinX, claim2.MinX); - int maxX = Math.Min(claim1.MaxX, claim2.MaxX); - int minY = Math.Max(claim1.MinY, claim2.MinY); - int maxY = Math.Min(claim1.MaxY, claim2.MaxY); - int width = maxX - minX; - int height = maxY - minY; - if (width <= 0 || height <= 0) { return false; } - return true; - } - - return false; + unoverlappingClaim = claims[i]; + break; } } + return unoverlappingClaim.ID.ToString(); + } + public class Claim + { + public int ID { get; set; } -} + public int Left { get; set; } + public int Top { get; set; } + + public int Width { get; set; } + public int Height { get; set; } + + public int MinX { get { return Left; } } + public int MaxX { get { return Left + Width; } } + + public int MinY { get { return Top; } } + public int MaxY { get { return Top + Height; } } + + public int GetArea() + { + return Width * Height; + } + + public static Claim FromString(string strClaim) + { + Claim claim = new(); + string[] parts = strClaim.Split(new[] { " @ ", ",", ": ", "x", }, StringSplitOptions.None); + claim.ID = Convert.ToInt32(parts[0].Substring(1)); + claim.Left = Convert.ToInt32(parts[1]); + claim.Top = Convert.ToInt32(parts[2]); + claim.Width = Convert.ToInt32(parts[3]); + claim.Height = Convert.ToInt32(parts[4]); + return claim; + } + + public static bool Overlaps(Claim claim1, Claim claim2) + { + if (claim1.MinX <= claim2.MaxX && + claim2.MinX <= claim1.MaxX && + claim1.MinY <= claim2.MaxY && + claim2.MinY <= claim1.MaxY) + { + int minX = Math.Max(claim1.MinX, claim2.MinX); + int maxX = Math.Min(claim1.MaxX, claim2.MaxX); + int minY = Math.Max(claim1.MinY, claim2.MinY); + int maxY = Math.Min(claim1.MaxY, claim2.MaxY); + int width = maxX - minX; + int height = maxY - minY; + if (width <= 0 || height <= 0) { return false; } + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/AdventOfCode2018/Day04.cs b/AdventOfCode2018/Day04.cs index cd005f6..59a339f 100644 --- a/AdventOfCode2018/Day04.cs +++ b/AdventOfCode2018/Day04.cs @@ -2,274 +2,273 @@ using System.Collections.Generic; using System.Linq; -namespace AdventOfCode2018 +namespace AdventOfCode2018; + +/* +--- Day 4: Repose Record --- + +You've sneaked into another supply closet - this time, it's across from the prototype suit manufacturing lab. You need to sneak inside and fix the issues with the suit, but there's a guard stationed outside the lab, so this is as close as you can safely get. + +As you search the closet for anything that might help, you discover that you're not the first person to want to sneak in. Covering the walls, someone has spent an hour starting every midnight for the past few months secretly observing this guard post! They've been writing down the ID of the one guard on duty that night - the Elves seem to have decided that one guard was enough for the overnight shift - as well as when they fall asleep or wake up while at their post (your puzzle input). + +For example, consider the following records, which have already been organized into chronological order: + +[1518-11-01 00:00] Guard #10 begins shift +[1518-11-01 00:05] falls asleep +[1518-11-01 00:25] wakes up +[1518-11-01 00:30] falls asleep +[1518-11-01 00:55] wakes up +[1518-11-01 23:58] Guard #99 begins shift +[1518-11-02 00:40] falls asleep +[1518-11-02 00:50] wakes up +[1518-11-03 00:05] Guard #10 begins shift +[1518-11-03 00:24] falls asleep +[1518-11-03 00:29] wakes up +[1518-11-04 00:02] Guard #99 begins shift +[1518-11-04 00:36] falls asleep +[1518-11-04 00:46] wakes up +[1518-11-05 00:03] Guard #99 begins shift +[1518-11-05 00:45] falls asleep +[1518-11-05 00:55] wakes up + +Timestamps are written using year-month-day hour:minute format. The guard falling asleep or waking up is always the one whose shift most recently started. Because all asleep/awake times are during the midnight hour (00:00 - 00:59), only the minute portion (00 - 59) is relevant for those events. + +Visually, these records show that the guards are asleep at these times: + +Date ID Minute + 000000000011111111112222222222333333333344444444445555555555 + 012345678901234567890123456789012345678901234567890123456789 +11-01 #10 .....####################.....#########################..... +11-02 #99 ........................................##########.......... +11-03 #10 ........................#####............................... +11-04 #99 ....................................##########.............. +11-05 #99 .............................................##########..... + +The columns are Date, which shows the month-day portion of the relevant day; ID, which shows the guard on duty that day; and Minute, which shows the minutes during which the guard was asleep within the midnight hour. (The Minute column's header shows the minute's ten's digit in the first row and the one's digit in the second row.) Awake is shown as ., and asleep is shown as #. + +Note that guards count as asleep on the minute they fall asleep, and they count as awake on the minute they wake up. For example, because Guard #10 wakes up at 00:25 on 1518-11-01, minute 25 is marked as awake. + +If you can figure out the guard most likely to be asleep at a specific time, you might be able to trick that guard into working tonight so you can have the best chance of sneaking in. You have two strategies for choosing the best guard/minute combination. + +Strategy 1: Find the guard that has the most minutes asleep. What minute does that guard spend asleep the most? + +In the example above, Guard #10 spent the most minutes asleep, a total of 50 minutes (20+25+5), while Guard #99 only slept for a total of 30 minutes (10+10+10). Guard #10 was asleep most during minute 24 (on two days, whereas any other minute the guard was asleep was only seen on one day). + +While this example listed the entries in chronological order, your entries are in the order you found them. You'll need to organize them before they can be analyzed. + +What is the ID of the guard you chose multiplied by the minute you chose? (In the above example, the answer would be 10 * 24 = 240.) + +--- Part Two --- + +Strategy 2: Of all guards, which guard is most frequently asleep on the same minute? + +In the example above, Guard #99 spent minute 45 asleep more than any other guard or minute - three times in total. (In all other cases, any guard spent any minute asleep at most twice.) + +What is the ID of the guard you chose multiplied by the minute you chose? (In the above example, the answer would be 99 * 45 = 4455.) + +*/ +public class Day04 : IDay { - /* - --- Day 4: Repose Record --- - - You've sneaked into another supply closet - this time, it's across from the prototype suit manufacturing lab. You need to sneak inside and fix the issues with the suit, but there's a guard stationed outside the lab, so this is as close as you can safely get. - - As you search the closet for anything that might help, you discover that you're not the first person to want to sneak in. Covering the walls, someone has spent an hour starting every midnight for the past few months secretly observing this guard post! They've been writing down the ID of the one guard on duty that night - the Elves seem to have decided that one guard was enough for the overnight shift - as well as when they fall asleep or wake up while at their post (your puzzle input). - - For example, consider the following records, which have already been organized into chronological order: - - [1518-11-01 00:00] Guard #10 begins shift - [1518-11-01 00:05] falls asleep - [1518-11-01 00:25] wakes up - [1518-11-01 00:30] falls asleep - [1518-11-01 00:55] wakes up - [1518-11-01 23:58] Guard #99 begins shift - [1518-11-02 00:40] falls asleep - [1518-11-02 00:50] wakes up - [1518-11-03 00:05] Guard #10 begins shift - [1518-11-03 00:24] falls asleep - [1518-11-03 00:29] wakes up - [1518-11-04 00:02] Guard #99 begins shift - [1518-11-04 00:36] falls asleep - [1518-11-04 00:46] wakes up - [1518-11-05 00:03] Guard #99 begins shift - [1518-11-05 00:45] falls asleep - [1518-11-05 00:55] wakes up - - Timestamps are written using year-month-day hour:minute format. The guard falling asleep or waking up is always the one whose shift most recently started. Because all asleep/awake times are during the midnight hour (00:00 - 00:59), only the minute portion (00 - 59) is relevant for those events. - - Visually, these records show that the guards are asleep at these times: - - Date ID Minute - 000000000011111111112222222222333333333344444444445555555555 - 012345678901234567890123456789012345678901234567890123456789 - 11-01 #10 .....####################.....#########################..... - 11-02 #99 ........................................##########.......... - 11-03 #10 ........................#####............................... - 11-04 #99 ....................................##########.............. - 11-05 #99 .............................................##########..... - - The columns are Date, which shows the month-day portion of the relevant day; ID, which shows the guard on duty that day; and Minute, which shows the minutes during which the guard was asleep within the midnight hour. (The Minute column's header shows the minute's ten's digit in the first row and the one's digit in the second row.) Awake is shown as ., and asleep is shown as #. - - Note that guards count as asleep on the minute they fall asleep, and they count as awake on the minute they wake up. For example, because Guard #10 wakes up at 00:25 on 1518-11-01, minute 25 is marked as awake. - - If you can figure out the guard most likely to be asleep at a specific time, you might be able to trick that guard into working tonight so you can have the best chance of sneaking in. You have two strategies for choosing the best guard/minute combination. - - Strategy 1: Find the guard that has the most minutes asleep. What minute does that guard spend asleep the most? - - In the example above, Guard #10 spent the most minutes asleep, a total of 50 minutes (20+25+5), while Guard #99 only slept for a total of 30 minutes (10+10+10). Guard #10 was asleep most during minute 24 (on two days, whereas any other minute the guard was asleep was only seen on one day). - - While this example listed the entries in chronological order, your entries are in the order you found them. You'll need to organize them before they can be analyzed. - - What is the ID of the guard you chose multiplied by the minute you chose? (In the above example, the answer would be 10 * 24 = 240.) - - --- Part Two --- - - Strategy 2: Of all guards, which guard is most frequently asleep on the same minute? - - In the example above, Guard #99 spent minute 45 asleep more than any other guard or minute - three times in total. (In all other cases, any guard spent any minute asleep at most twice.) - - What is the ID of the guard you chose multiplied by the minute you chose? (In the above example, the answer would be 99 * 45 = 4455.) - - */ - public class Day04 : IDay + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) - { - List guardEvents = GuardEvent.FromStringArray(inputs); - Dictionary dictFullHistogram = BuildFullHistorgram(guardEvents); + List guardEvents = GuardEvent.FromStringArray(inputs); + Dictionary dictFullHistogram = BuildFullHistorgram(guardEvents); - // Find sleepier guard - GuardSleepHistogram highestSleeperHistogram = null; - long highestTotalSleep = long.MinValue; + // Find sleepier guard + GuardSleepHistogram highestSleeperHistogram = null; + long highestTotalSleep = long.MinValue; + foreach (GuardSleepHistogram guardHistogram in dictFullHistogram.Values) + { + int totalSleep = guardHistogram.SleepOnMunute.Sum(); + + if (totalSleep > highestTotalSleep) + { + highestSleeperHistogram = guardHistogram; + highestTotalSleep = totalSleep; + } + } + + // Find sleepier minute + int maxSleepMinute = int.MinValue; + int maxSleepMinuteValue = int.MinValue; + for (int i = 0; i < GuardSleepHistogram.MinutesOnHour; i++) + { + if (highestSleeperHistogram.SleepOnMunute[i] > maxSleepMinuteValue) + { + maxSleepMinute = i; + maxSleepMinuteValue = highestSleeperHistogram.SleepOnMunute[i]; + } + } + + int result = highestSleeperHistogram.ID * maxSleepMinute; + return result.ToString(); + } + + public string ResolvePart2(string[] inputs) + { + List guardEvents = GuardEvent.FromStringArray(inputs); + Dictionary dictFullHistogram = BuildFullHistorgram(guardEvents); + + int selectedGuardID = int.MinValue; + int selectedMinute = int.MinValue; + int maxSleepMinuteValue = int.MinValue; + for (int i = 0; i < GuardSleepHistogram.MinutesOnHour; i++) + { foreach (GuardSleepHistogram guardHistogram in dictFullHistogram.Values) { - int totalSleep = guardHistogram.SleepOnMunute.Sum(); - - if (totalSleep > highestTotalSleep) + if (guardHistogram.SleepOnMunute[i] > maxSleepMinuteValue) { - highestSleeperHistogram = guardHistogram; - highestTotalSleep = totalSleep; + maxSleepMinuteValue = guardHistogram.SleepOnMunute[i]; + selectedGuardID = guardHistogram.ID; + selectedMinute = i; } } - - // Find sleepier minute - int maxSleepMinute = int.MinValue; - int maxSleepMinuteValue = int.MinValue; - for (int i = 0; i < GuardSleepHistogram.MinutesOnHour; i++) - { - if (highestSleeperHistogram.SleepOnMunute[i] > maxSleepMinuteValue) - { - maxSleepMinute = i; - maxSleepMinuteValue = highestSleeperHistogram.SleepOnMunute[i]; - } - } - - int result = highestSleeperHistogram.ID * maxSleepMinute; - return result.ToString(); } - public string ResolvePart2(string[] inputs) - { - List guardEvents = GuardEvent.FromStringArray(inputs); - Dictionary dictFullHistogram = BuildFullHistorgram(guardEvents); - - int selectedGuardID = int.MinValue; - int selectedMinute = int.MinValue; - int maxSleepMinuteValue = int.MinValue; - for (int i = 0; i < GuardSleepHistogram.MinutesOnHour; i++) - { - foreach (GuardSleepHistogram guardHistogram in dictFullHistogram.Values) - { - if (guardHistogram.SleepOnMunute[i] > maxSleepMinuteValue) - { - maxSleepMinuteValue = guardHistogram.SleepOnMunute[i]; - selectedGuardID = guardHistogram.ID; - selectedMinute = i; - } - } - } - - int result = selectedGuardID * selectedMinute; - return result.ToString(); - } - - private static Dictionary BuildFullHistorgram(List guardEvents) - { - Dictionary dictFullHistogram = new Dictionary(); - foreach (IGrouping group in guardEvents.GroupBy(guardEvent => guardEvent.Date.DayOfYear)) - { - Dictionary dictDayHistogram = new Dictionary(); - foreach (GuardEvent guardEvent in group) - { - if (guardEvent.ID == null) { continue; } - GuardSleepHistogram dayGuardHistogram = null; - if (dictDayHistogram.ContainsKey((int)guardEvent.ID)) - { - dayGuardHistogram = dictDayHistogram[(int)guardEvent.ID]; - } - else - { - dayGuardHistogram = new GuardSleepHistogram { ID = (int)guardEvent.ID }; - dictDayHistogram.Add(dayGuardHistogram.ID, dayGuardHistogram); - } - if (guardEvent.Type == GuardEventType.FallSleep) - { - dayGuardHistogram.FallSleep(guardEvent.Date.Minute); - } - if (guardEvent.Type == GuardEventType.WakeUp) - { - dayGuardHistogram.WakeUp(guardEvent.Date.Minute); - } - } - - foreach (GuardSleepHistogram dayGuardHistogram in dictDayHistogram.Values) - { - GuardSleepHistogram guardHistogram = null; - if (dictFullHistogram.ContainsKey(dayGuardHistogram.ID)) - { - guardHistogram = dictFullHistogram[dayGuardHistogram.ID]; - guardHistogram.AddHistogram(dayGuardHistogram); - } - else - { - dictFullHistogram.Add(dayGuardHistogram.ID, dayGuardHistogram); - } - } - } - - return dictFullHistogram; - } + int result = selectedGuardID * selectedMinute; + return result.ToString(); } - public enum GuardEventType + private static Dictionary BuildFullHistorgram(List guardEvents) { - ShiftBegin, - FallSleep, - WakeUp, - } - - public class GuardEvent - { - public DateTime Date { get; set; } - public int? ID { get; set; } - public GuardEventType Type { get; set; } - - public static GuardEvent FromString(string strEvent) + Dictionary dictFullHistogram = new(); + foreach (IGrouping group in guardEvents.GroupBy(guardEvent => guardEvent.Date.DayOfYear)) { - GuardEvent guardEvent = new GuardEvent(); - string[] parts = strEvent.Split(new string[] { "[", "-", " ", ":", "]", "#", }, StringSplitOptions.RemoveEmptyEntries); - guardEvent.Date = new DateTime( - Convert.ToInt32(parts[0]), - Convert.ToInt32(parts[1]), - Convert.ToInt32(parts[2]), - Convert.ToInt32(parts[3]), - Convert.ToInt32(parts[4]), - 0 - ); - if (parts[5] == "Guard") + Dictionary dictDayHistogram = new(); + foreach (GuardEvent guardEvent in group) { - guardEvent.ID = Convert.ToInt32(parts[6]); - guardEvent.Type = GuardEventType.ShiftBegin; - } - if (parts[5] == "falls") - { - guardEvent.Type = GuardEventType.FallSleep; - } - if (parts[5] == "wakes") - { - guardEvent.Type = GuardEventType.WakeUp; - } - return guardEvent; - } - - public static List FromStringArray(string[] strEvents) - { - List guardEvents = strEvents - .Select(strEvent => FromString(strEvent)) - .OrderBy(guardEvent => guardEvent.Date) - .ToList(); - - int? guardID = null; - foreach (GuardEvent guardEvent in guardEvents) - { - if (guardEvent.Type == GuardEventType.ShiftBegin) + if (guardEvent.ID == null) { continue; } + GuardSleepHistogram dayGuardHistogram; + if (dictDayHistogram.ContainsKey((int)guardEvent.ID)) { - guardID = guardEvent.ID; + dayGuardHistogram = dictDayHistogram[(int)guardEvent.ID]; } else { - guardEvent.ID = guardID; + dayGuardHistogram = new GuardSleepHistogram { ID = (int)guardEvent.ID }; + dictDayHistogram.Add(dayGuardHistogram.ID, dayGuardHistogram); + } + if (guardEvent.Type == GuardEventType.FallSleep) + { + dayGuardHistogram.FallSleep(guardEvent.Date.Minute); + } + if (guardEvent.Type == GuardEventType.WakeUp) + { + dayGuardHistogram.WakeUp(guardEvent.Date.Minute); } } - return guardEvents; - } - } - - public class GuardSleepHistogram - { - public const int MinutesOnHour = 60; - public int ID { get; set; } - public int[] SleepOnMunute { get; } = new int[MinutesOnHour]; - - public void FallSleep(int minute) - { - for (int i = minute; i < MinutesOnHour; i++) + foreach (GuardSleepHistogram dayGuardHistogram in dictDayHistogram.Values) { - SleepOnMunute[i] = 1; + GuardSleepHistogram guardHistogram; + if (dictFullHistogram.ContainsKey(dayGuardHistogram.ID)) + { + guardHistogram = dictFullHistogram[dayGuardHistogram.ID]; + guardHistogram.AddHistogram(dayGuardHistogram); + } + else + { + dictFullHistogram.Add(dayGuardHistogram.ID, dayGuardHistogram); + } } } - public void WakeUp(int minute) - { - for (int i = minute; i < MinutesOnHour; i++) - { - SleepOnMunute[i] = 0; - } - } - - public void AddHistogram(GuardSleepHistogram histogram) - { - for (int i = 0; i < MinutesOnHour; i++) - { - SleepOnMunute[i] += histogram.SleepOnMunute[i]; - } - } + return dictFullHistogram; } } + +public enum GuardEventType +{ + ShiftBegin, + FallSleep, + WakeUp, +} + +public class GuardEvent +{ + public DateTime Date { get; set; } + public int? ID { get; set; } + public GuardEventType Type { get; set; } + + public static GuardEvent FromString(string strEvent) + { + GuardEvent guardEvent = new(); + string[] parts = strEvent.Split(new[] { "[", "-", " ", ":", "]", "#", }, StringSplitOptions.RemoveEmptyEntries); + guardEvent.Date = new DateTime( + Convert.ToInt32(parts[0]), + Convert.ToInt32(parts[1]), + Convert.ToInt32(parts[2]), + Convert.ToInt32(parts[3]), + Convert.ToInt32(parts[4]), + 0 + ); + if (parts[5] == "Guard") + { + guardEvent.ID = Convert.ToInt32(parts[6]); + guardEvent.Type = GuardEventType.ShiftBegin; + } + if (parts[5] == "falls") + { + guardEvent.Type = GuardEventType.FallSleep; + } + if (parts[5] == "wakes") + { + guardEvent.Type = GuardEventType.WakeUp; + } + return guardEvent; + } + + public static List FromStringArray(string[] strEvents) + { + List guardEvents = strEvents + .Select(strEvent => FromString(strEvent)) + .OrderBy(guardEvent => guardEvent.Date) + .ToList(); + + int? guardID = null; + foreach (GuardEvent guardEvent in guardEvents) + { + if (guardEvent.Type == GuardEventType.ShiftBegin) + { + guardID = guardEvent.ID; + } + else + { + guardEvent.ID = guardID; + } + } + + return guardEvents; + } +} + +public class GuardSleepHistogram +{ + public const int MinutesOnHour = 60; + public int ID { get; set; } + public int[] SleepOnMunute { get; } = new int[MinutesOnHour]; + + public void FallSleep(int minute) + { + for (int i = minute; i < MinutesOnHour; i++) + { + SleepOnMunute[i] = 1; + } + } + + public void WakeUp(int minute) + { + for (int i = minute; i < MinutesOnHour; i++) + { + SleepOnMunute[i] = 0; + } + } + + public void AddHistogram(GuardSleepHistogram histogram) + { + for (int i = 0; i < MinutesOnHour; i++) + { + SleepOnMunute[i] += histogram.SleepOnMunute[i]; + } + } +} \ No newline at end of file diff --git a/AdventOfCode2018/Day05.cs b/AdventOfCode2018/Day05.cs index 26b70fa..53b78fe 100644 --- a/AdventOfCode2018/Day05.cs +++ b/AdventOfCode2018/Day05.cs @@ -2,130 +2,128 @@ using System.Linq; using System.Text; -namespace AdventOfCode2018 +namespace AdventOfCode2018; +/* +--- Day 5: Alchemical Reduction --- + +You've managed to sneak in to the prototype suit manufacturing lab. The Elves are making decent progress, but are still struggling with the suit's size reduction capabilities. + +While the very latest in 1518 alchemical technology might have solved their problem eventually, you can do better. You scan the chemical composition of the suit's material and discover that it is formed by extremely long polymers (one of which is available as your puzzle input). + +The polymer is formed by smaller units which, when triggered, react with each other such that two adjacent units of the same type and opposite polarity are destroyed. Units' types are represented by letters; units' polarity is represented by capitalization. For instance, r and R are units with the same type but opposite polarity, whereas r and s are entirely different types and do not react. + +For example: + + In aA, a and A react, leaving nothing behind. + In abBA, bB destroys itself, leaving aA. As above, this then destroys itself, leaving nothing. + In abAB, no two adjacent units are of the same type, and so nothing happens. + In aabAAB, even though aa and AA are of the same type, their polarities match, and so nothing happens. + +Now, consider a larger example, dabAcCaCBAcCcaDA: + +dabAcCaCBAcCcaDA The first 'cC' is removed. +dabAaCBAcCcaDA This creates 'Aa', which is removed. +dabCBAcCcaDA Either 'cC' or 'Cc' are removed (the result is the same). +dabCBAcaDA No further actions can be taken. + +After all possible reactions, the resulting polymer contains 10 units. + +How many units remain after fully reacting the polymer you scanned? (Note: in this puzzle and others, the input is large; if you copy/paste your input, make sure you get the whole thing.) + +--- Part Two --- + +Time to improve the polymer. + +One of the unit types is causing problems; it's preventing the polymer from collapsing as much as it should. Your goal is to figure out which unit type is causing the most problems, remove all instances of it (regardless of polarity), fully react the remaining polymer, and measure its length. + +For example, again using the polymer dabAcCaCBAcCcaDA from above: + + Removing all A/a units produces dbcCCBcCcD. Fully reacting this polymer produces dbCBcD, which has length 6. + Removing all B/b units produces daAcCaCAcCcaDA. Fully reacting this polymer produces daCAcaDA, which has length 8. + Removing all C/c units produces dabAaBAaDA. Fully reacting this polymer produces daDA, which has length 4. + Removing all D/d units produces abAcCaCBAcCcaA. Fully reacting this polymer produces abCBAc, which has length 6. + +In this example, removing all C/c units was best, producing the answer 4. + +What is the length of the shortest polymer you can produce by removing all units of exactly one type and fully reacting the result? + +*/ + +public class Day05 : IDay { - /* - --- Day 5: Alchemical Reduction --- - - You've managed to sneak in to the prototype suit manufacturing lab. The Elves are making decent progress, but are still struggling with the suit's size reduction capabilities. - - While the very latest in 1518 alchemical technology might have solved their problem eventually, you can do better. You scan the chemical composition of the suit's material and discover that it is formed by extremely long polymers (one of which is available as your puzzle input). - - The polymer is formed by smaller units which, when triggered, react with each other such that two adjacent units of the same type and opposite polarity are destroyed. Units' types are represented by letters; units' polarity is represented by capitalization. For instance, r and R are units with the same type but opposite polarity, whereas r and s are entirely different types and do not react. - - For example: - - In aA, a and A react, leaving nothing behind. - In abBA, bB destroys itself, leaving aA. As above, this then destroys itself, leaving nothing. - In abAB, no two adjacent units are of the same type, and so nothing happens. - In aabAAB, even though aa and AA are of the same type, their polarities match, and so nothing happens. - - Now, consider a larger example, dabAcCaCBAcCcaDA: - - dabAcCaCBAcCcaDA The first 'cC' is removed. - dabAaCBAcCcaDA This creates 'Aa', which is removed. - dabCBAcCcaDA Either 'cC' or 'Cc' are removed (the result is the same). - dabCBAcaDA No further actions can be taken. - - After all possible reactions, the resulting polymer contains 10 units. - - How many units remain after fully reacting the polymer you scanned? (Note: in this puzzle and others, the input is large; if you copy/paste your input, make sure you get the whole thing.) - - --- Part Two --- - - Time to improve the polymer. - - One of the unit types is causing problems; it's preventing the polymer from collapsing as much as it should. Your goal is to figure out which unit type is causing the most problems, remove all instances of it (regardless of polarity), fully react the remaining polymer, and measure its length. - - For example, again using the polymer dabAcCaCBAcCcaDA from above: - - Removing all A/a units produces dbcCCBcCcD. Fully reacting this polymer produces dbCBcD, which has length 6. - Removing all B/b units produces daAcCaCAcCcaDA. Fully reacting this polymer produces daCAcaDA, which has length 8. - Removing all C/c units produces dabAaBAaDA. Fully reacting this polymer produces daDA, which has length 4. - Removing all D/d units produces abAcCaCBAcCcaA. Fully reacting this polymer produces abCBAc, which has length 6. - - In this example, removing all C/c units was best, producing the answer 4. - - What is the length of the shortest polymer you can produce by removing all units of exactly one type and fully reacting the result? - - */ - - public class Day05 : IDay + public string ReducePolymer(string polymer) { - public string ReducePolymer(string polymer) - { - if (polymer.Length <= 1) { return polymer; } - StringBuilder sb = new StringBuilder(); + if (polymer.Length <= 1) { return polymer; } + StringBuilder sb = new(); - int i; - for (i = 1; i < polymer.Length; i++) + int i; + for (i = 1; i < polymer.Length; i++) + { + char previousCharacter = polymer[i - 1]; + char character = polymer[i]; + if (previousCharacter != character && char.ToLower(previousCharacter) == char.ToLower(character)) { - char previousCharacter = polymer[i - 1]; - char character = polymer[i]; - if (previousCharacter != character && char.ToLower(previousCharacter) == char.ToLower(character)) - { - i++; - } - else - { - sb.Append(previousCharacter); - } + i++; } - if (i == polymer.Length) { sb.Append(polymer[i - 1]); } - - return sb.ToString(); - } - - public string FullyReducePolymer(string input) - { - string previousPolymer = null; - string polymer = input; - do + else { - previousPolymer = polymer; - polymer = ReducePolymer(polymer); - } while (previousPolymer.Length > polymer.Length); - return polymer; - } - - public string ResolvePart1(string[] inputs) - { - string reducedPolymer = FullyReducePolymer(inputs[0]); - return reducedPolymer.Length.ToString(); - } - - public string RemoveUnitTypeFromPolymer(string polymer, char unitType) - { - StringBuilder sb = new StringBuilder(); - unitType = char.ToLower(unitType); - foreach (char c in polymer) - { - if (char.ToLower(c) != unitType) - { - sb.Append(c); - } + sb.Append(previousCharacter); } - return sb.ToString(); } + if (i == polymer.Length) { sb.Append(polymer[i - 1]); } - public string ResolvePart2(string[] inputs) - { - string input = inputs[0]; - List allUnitTypes = input.Select(c => char.ToLower(c)).Distinct().ToList(); - - int minPolymerLenght = int.MaxValue; - foreach (char unitType in allUnitTypes) - { - string fixedPolymer = RemoveUnitTypeFromPolymer(input, unitType); - string fixedReducedPolymer = FullyReducePolymer(fixedPolymer); - int fixedReducedPolymerLenght = fixedReducedPolymer.Length; - if (minPolymerLenght > fixedReducedPolymerLenght) - { - minPolymerLenght = fixedReducedPolymerLenght; - } - } - - return minPolymerLenght.ToString(); - } + return sb.ToString(); } -} + + public string FullyReducePolymer(string input) + { + string previousPolymer; + string polymer = input; + do + { + previousPolymer = polymer; + polymer = ReducePolymer(polymer); + } while (previousPolymer.Length > polymer.Length); + return polymer; + } + + public string ResolvePart1(string[] inputs) + { + string reducedPolymer = FullyReducePolymer(inputs[0]); + return reducedPolymer.Length.ToString(); + } + + public string RemoveUnitTypeFromPolymer(string polymer, char unitType) + { + StringBuilder sb = new(); + unitType = char.ToLower(unitType); + foreach (char c in polymer) + { + if (char.ToLower(c) != unitType) + { + sb.Append(c); + } + } + return sb.ToString(); + } + + public string ResolvePart2(string[] inputs) + { + string input = inputs[0]; + List allUnitTypes = input.Select(c => char.ToLower(c)).Distinct().ToList(); + + int minPolymerLenght = int.MaxValue; + foreach (char unitType in allUnitTypes) + { + string fixedPolymer = RemoveUnitTypeFromPolymer(input, unitType); + string fixedReducedPolymer = FullyReducePolymer(fixedPolymer); + int fixedReducedPolymerLenght = fixedReducedPolymer.Length; + if (minPolymerLenght > fixedReducedPolymerLenght) + { + minPolymerLenght = fixedReducedPolymerLenght; + } + } + + return minPolymerLenght.ToString(); + } +} \ No newline at end of file diff --git a/AdventOfCode2018/Day06.cs b/AdventOfCode2018/Day06.cs index 7885024..cda1aeb 100644 --- a/AdventOfCode2018/Day06.cs +++ b/AdventOfCode2018/Day06.cs @@ -2,224 +2,221 @@ using System.Collections.Generic; using System.Linq; -namespace AdventOfCode2018 +namespace AdventOfCode2018; +/* +--- Day 6: Chronal Coordinates --- + +The device on your wrist beeps several times, and once again you feel like you're falling. + +"Situation critical," the device announces. "Destination indeterminate. Chronal interference detected. Please specify new target coordinates." + +The device then produces a list of coordinates (your puzzle input). Are they places it thinks are safe or dangerous? It recommends you check manual page 729. The Elves did not give you a manual. + +If they're dangerous, maybe you can minimize the danger by finding the coordinate that gives the largest distance from the other points. + +Using only the Manhattan distance, determine the area around each coordinate by counting the number of integer X,Y locations that are closest to that coordinate (and aren't tied in distance to any other coordinate). + +Your goal is to find the size of the largest area that isn't infinite. For example, consider the following list of coordinates: + +1, 1 +1, 6 +8, 3 +3, 4 +5, 5 +8, 9 + +If we name these coordinates A through F, we can draw them on a grid, putting 0,0 at the top left: + +.......... +.A........ +.......... +........C. +...D...... +.....E.... +.B........ +.......... +.......... +........F. + +This view is partial - the actual grid extends infinitely in all directions. Using the Manhattan distance, each location's closest coordinate can be determined, shown here in lowercase: + +aaaaa.cccc +aAaaa.cccc +aaaddecccc +aadddeccCc +..dDdeeccc +bb.deEeecc +bBb.eeee.. +bbb.eeefff +bbb.eeffff +bbb.ffffFf + +Locations shown as . are equally far from two or more coordinates, and so they don't count as being closest to any. + +In this example, the areas of coordinates A, B, C, and F are infinite - while not shown here, their areas extend forever outside the visible grid. However, the areas of coordinates D and E are finite: D is closest to 9 locations, and E is closest to 17 (both including the coordinate's location itself). Therefore, in this example, the size of the largest area is 17. + +What is the size of the largest area that isn't infinite? + +--- Part Two --- + +On the other hand, if the coordinates are safe, maybe the best you can do is try to find a region near as many coordinates as possible. + +For example, suppose you want the sum of the Manhattan distance to all of the coordinates to be less than 32. For each location, add up the distances to all of the given coordinates; if the total of those distances is less than 32, that location is within the desired region. Using the same coordinates as above, the resulting region looks like this: + +.......... +.A........ +.......... +...###..C. +..#D###... +..###E#... +.B.###.... +.......... +.......... +........F. + +In particular, consider the highlighted location 4,3 located at the top middle of the region. Its calculation is as follows, where abs() is the absolute value function: + + Distance to coordinate A: abs(4-1) + abs(3-1) = 5 + Distance to coordinate B: abs(4-1) + abs(3-6) = 6 + Distance to coordinate C: abs(4-8) + abs(3-3) = 4 + Distance to coordinate D: abs(4-3) + abs(3-4) = 2 + Distance to coordinate E: abs(4-5) + abs(3-5) = 3 + Distance to coordinate F: abs(4-8) + abs(3-9) = 10 + Total distance: 5 + 6 + 4 + 2 + 3 + 10 = 30 + +Because the total distance to all coordinates (30) is less than 32, the location is within the region. + +This region, which also includes coordinates D and E, has a total size of 16. + +Your actual region will need to be much larger than this example, though, instead including all locations with a total distance of less than 10000. + +What is the size of the region containing all locations which have a total distance to all given coordinates of less than 10000? + +*/ + +public class Day06 : IDay { - /* - --- Day 6: Chronal Coordinates --- - - The device on your wrist beeps several times, and once again you feel like you're falling. - - "Situation critical," the device announces. "Destination indeterminate. Chronal interference detected. Please specify new target coordinates." - - The device then produces a list of coordinates (your puzzle input). Are they places it thinks are safe or dangerous? It recommends you check manual page 729. The Elves did not give you a manual. - - If they're dangerous, maybe you can minimize the danger by finding the coordinate that gives the largest distance from the other points. - - Using only the Manhattan distance, determine the area around each coordinate by counting the number of integer X,Y locations that are closest to that coordinate (and aren't tied in distance to any other coordinate). - - Your goal is to find the size of the largest area that isn't infinite. For example, consider the following list of coordinates: - - 1, 1 - 1, 6 - 8, 3 - 3, 4 - 5, 5 - 8, 9 - - If we name these coordinates A through F, we can draw them on a grid, putting 0,0 at the top left: - - .......... - .A........ - .......... - ........C. - ...D...... - .....E.... - .B........ - .......... - .......... - ........F. - - This view is partial - the actual grid extends infinitely in all directions. Using the Manhattan distance, each location's closest coordinate can be determined, shown here in lowercase: - - aaaaa.cccc - aAaaa.cccc - aaaddecccc - aadddeccCc - ..dDdeeccc - bb.deEeecc - bBb.eeee.. - bbb.eeefff - bbb.eeffff - bbb.ffffFf - - Locations shown as . are equally far from two or more coordinates, and so they don't count as being closest to any. - - In this example, the areas of coordinates A, B, C, and F are infinite - while not shown here, their areas extend forever outside the visible grid. However, the areas of coordinates D and E are finite: D is closest to 9 locations, and E is closest to 17 (both including the coordinate's location itself). Therefore, in this example, the size of the largest area is 17. - - What is the size of the largest area that isn't infinite? - - --- Part Two --- - - On the other hand, if the coordinates are safe, maybe the best you can do is try to find a region near as many coordinates as possible. - - For example, suppose you want the sum of the Manhattan distance to all of the coordinates to be less than 32. For each location, add up the distances to all of the given coordinates; if the total of those distances is less than 32, that location is within the desired region. Using the same coordinates as above, the resulting region looks like this: - - .......... - .A........ - .......... - ...###..C. - ..#D###... - ..###E#... - .B.###.... - .......... - .......... - ........F. - - In particular, consider the highlighted location 4,3 located at the top middle of the region. Its calculation is as follows, where abs() is the absolute value function: - - Distance to coordinate A: abs(4-1) + abs(3-1) = 5 - Distance to coordinate B: abs(4-1) + abs(3-6) = 6 - Distance to coordinate C: abs(4-8) + abs(3-3) = 4 - Distance to coordinate D: abs(4-3) + abs(3-4) = 2 - Distance to coordinate E: abs(4-5) + abs(3-5) = 3 - Distance to coordinate F: abs(4-8) + abs(3-9) = 10 - Total distance: 5 + 6 + 4 + 2 + 3 + 10 = 30 - - Because the total distance to all coordinates (30) is less than 32, the location is within the region. - - This region, which also includes coordinates D and E, has a total size of 16. - - Your actual region will need to be much larger than this example, though, instead including all locations with a total distance of less than 10000. - - What is the size of the region containing all locations which have a total distance to all given coordinates of less than 10000? - - */ - - public class Day06 : IDay + private List InputsToPoints(string[] inputs) { - private List InputsToPoints(string[] inputs) - { - return inputs - .Where(input => string.IsNullOrEmpty(input) == false) - .Select(input => ChronoPoint.FromString(input)) - .ToList(); - } - - public string ResolvePart1(string[] inputs) - { - List points = InputsToPoints(inputs); - Dictionary pointsAreas = new Dictionary(); - for (int i = 0; i < points.Count; i++) - { - pointsAreas.Add(i, 0); - } - - int minX = points.Min(p => p.X) - 1; - int maxX = points.Max(p => p.X) + 1; - int minY = points.Min(p => p.Y) - 1; - int maxY = points.Max(p => p.Y) + 1; - - ChronoPoint samplingPoint = new ChronoPoint(); - for(int i=minX; i <= maxX; i++) - { - for(int j = minY; j <= maxY; j++) - { - samplingPoint.X = i; - samplingPoint.Y = j; - bool isEdge = i == minX || i == maxX || j == minY || j == maxY; - - int idxMin = -1; - int distanceMin = int.MaxValue; - for (int idx = 0; idx < points.Count; idx++) - { - int distance = ChronoPoint.ManhattanDistance(samplingPoint, points[idx]); - if (distance == distanceMin) - { - idxMin = -1; - } - else if (distance < distanceMin) - { - distanceMin = distance; - idxMin = idx; - } - } - if (idxMin < 0) { continue; } - - if (isEdge) - { - pointsAreas[idxMin] = -1; - } - else - { - int previousArea = pointsAreas[idxMin]; - if (previousArea >= 0) - { - pointsAreas[idxMin] = previousArea + 1; - } - } - } - } - - int maxArea = pointsAreas.Max(p => p.Value); - return maxArea.ToString(); - } - - private int AreaInThresold(List points, int distanceThresold) - { - int minX = points.Min(p => p.X) - 1; - int maxX = points.Max(p => p.X) + 1; - int minY = points.Min(p => p.Y) - 1; - int maxY = points.Max(p => p.Y) + 1; - - int areaInRange = 0; - ChronoPoint samplingPoint = new ChronoPoint(); - for (int i = minX; i <= maxX; i++) - { - for (int j = minY; j <= maxY; j++) - { - samplingPoint.X = i; - samplingPoint.Y = j; - - int distanceSum = points.Sum(p => ChronoPoint.ManhattanDistance(samplingPoint, p)); - if (distanceSum < distanceThresold) { areaInRange++; } - } - } - - return areaInRange; - } - - public int DistanceThresold { get; set; } = 10000; - - public string ResolvePart2(string[] inputs) - { - List points = InputsToPoints(inputs); - int areaInRange = AreaInThresold(points, DistanceThresold); - return areaInRange.ToString(); - } + return inputs + .Where(input => string.IsNullOrEmpty(input) == false) + .Select(input => ChronoPoint.FromString(input)) + .ToList(); } - public class ChronoPoint + public string ResolvePart1(string[] inputs) { - public int X { get; set; } - public int Y { get; set; } - - public static ChronoPoint FromString(string strPoint) + List points = InputsToPoints(inputs); + Dictionary pointsAreas = new(); + for (int i = 0; i < points.Count; i++) { - if (string.IsNullOrEmpty(strPoint)) { return null; } - string[] parts = strPoint.Split(new string[] { ", ", }, StringSplitOptions.RemoveEmptyEntries); - if (parts.Length < 2) { return null; } - ChronoPoint point = new ChronoPoint + pointsAreas.Add(i, 0); + } + + int minX = points.Min(p => p.X) - 1; + int maxX = points.Max(p => p.X) + 1; + int minY = points.Min(p => p.Y) - 1; + int maxY = points.Max(p => p.Y) + 1; + + ChronoPoint samplingPoint = new(); + for(int i=minX; i <= maxX; i++) + { + for(int j = minY; j <= maxY; j++) { - X = Convert.ToInt32(parts[0]), - Y = Convert.ToInt32(parts[1]), - }; - return point; + samplingPoint.X = i; + samplingPoint.Y = j; + bool isEdge = i == minX || i == maxX || j == minY || j == maxY; + + int idxMin = -1; + int distanceMin = int.MaxValue; + for (int idx = 0; idx < points.Count; idx++) + { + int distance = ChronoPoint.ManhattanDistance(samplingPoint, points[idx]); + if (distance == distanceMin) + { + idxMin = -1; + } + else if (distance < distanceMin) + { + distanceMin = distance; + idxMin = idx; + } + } + if (idxMin < 0) { continue; } + + if (isEdge) + { + pointsAreas[idxMin] = -1; + } + else + { + int previousArea = pointsAreas[idxMin]; + if (previousArea >= 0) + { + pointsAreas[idxMin] = previousArea + 1; + } + } + } } - public static int ManhattanDistance(ChronoPoint p0, ChronoPoint p1) + int maxArea = pointsAreas.Max(p => p.Value); + return maxArea.ToString(); + } + + private int AreaInThresold(List points, int distanceThresold) + { + int minX = points.Min(p => p.X) - 1; + int maxX = points.Max(p => p.X) + 1; + int minY = points.Min(p => p.Y) - 1; + int maxY = points.Max(p => p.Y) + 1; + + int areaInRange = 0; + ChronoPoint samplingPoint = new(); + for (int i = minX; i <= maxX; i++) { - int distance = Math.Abs(p1.X - p0.X) + Math.Abs(p1.Y - p0.Y); - return distance; + for (int j = minY; j <= maxY; j++) + { + samplingPoint.X = i; + samplingPoint.Y = j; + + int distanceSum = points.Sum(p => ChronoPoint.ManhattanDistance(samplingPoint, p)); + if (distanceSum < distanceThresold) { areaInRange++; } + } } + + return areaInRange; + } + + public int DistanceThresold { get; set; } = 10000; + + public string ResolvePart2(string[] inputs) + { + List points = InputsToPoints(inputs); + int areaInRange = AreaInThresold(points, DistanceThresold); + return areaInRange.ToString(); } } + +public class ChronoPoint +{ + public int X { get; set; } + public int Y { get; set; } + + public static ChronoPoint FromString(string strPoint) + { + if (string.IsNullOrEmpty(strPoint)) { return null; } + string[] parts = strPoint.Split(new[] { ", ", }, StringSplitOptions.RemoveEmptyEntries); + if (parts.Length < 2) { return null; } + ChronoPoint point = new() { + X = Convert.ToInt32(parts[0]), + Y = Convert.ToInt32(parts[1]), + }; + return point; + } + + public static int ManhattanDistance(ChronoPoint p0, ChronoPoint p1) + { + int distance = Math.Abs(p1.X - p0.X) + Math.Abs(p1.Y - p0.Y); + return distance; + } +} \ No newline at end of file diff --git a/AdventOfCode2018/Day07.cs b/AdventOfCode2018/Day07.cs index 30d172e..d6bbc0c 100644 --- a/AdventOfCode2018/Day07.cs +++ b/AdventOfCode2018/Day07.cs @@ -3,283 +3,281 @@ using System.Collections.Generic; using System.Linq; using System.Text; -namespace AdventOfCode2018 +namespace AdventOfCode2018; +/* + +--- Day 7: The Sum of Its Parts --- + +You find yourself standing on a snow-covered coastline; apparently, you landed a little off course. The region is too hilly to see the North Pole from here, but you do spot some Elves that seem to be trying to unpack something that washed ashore. It's quite cold out, so you decide to risk creating a paradox by asking them for directions. + +"Oh, are you the search party?" Somehow, you can understand whatever Elves from the year 1018 speak; you assume it's Ancient Nordic Elvish. Could the device on your wrist also be a translator? "Those clothes don't look very warm; take this." They hand you a heavy coat. + +"We do need to find our way back to the North Pole, but we have higher priorities at the moment. You see, believe it or not, this box contains something that will solve all of Santa's transportation problems - at least, that's what it looks like from the pictures in the instructions." It doesn't seem like they can read whatever language it's in, but you can: "Sleigh kit. Some assembly required." + +"'Sleigh'? What a wonderful name! You must help us assemble this 'sleigh' at once!" They start excitedly pulling more parts out of the box. + +The instructions specify a series of steps and requirements about which steps must be finished before others can begin (your puzzle input). Each step is designated by a single letter. For example, suppose you have the following instructions: + +Step C must be finished before step A can begin. +Step C must be finished before step F can begin. +Step A must be finished before step B can begin. +Step A must be finished before step D can begin. +Step B must be finished before step E can begin. +Step D must be finished before step E can begin. +Step F must be finished before step E can begin. + +Visually, these requirements look like this: + + + -->A--->B-- + / \ \ +C -->D----->E + \ / + ---->F----- + +Your first goal is to determine the order in which the steps should be completed. If more than one step is ready, choose the step which is first alphabetically. In this example, the steps would be completed as follows: + + Only C is available, and so it is done first. + Next, both A and F are available. A is first alphabetically, so it is done next. + Then, even though F was available earlier, steps B and D are now also available, and B is the first alphabetically of the three. + After that, only D and F are available. E is not available because only some of its prerequisites are complete. Therefore, D is completed next. + F is the only choice, so it is done next. + Finally, E is completed. + +So, in this example, the correct order is CABDFE. + +In what order should the steps in your instructions be completed? + +--- Part Two --- + +As you're about to begin construction, four of the Elves offer to help. "The sun will set soon; it'll go faster if we work together." Now, you need to account for multiple people working on steps simultaneously. If multiple steps are available, workers should still begin them in alphabetical order. + +Each step takes 60 seconds plus an amount corresponding to its letter: A=1, B=2, C=3, and so on. So, step A takes 60+1=61 seconds, while step Z takes 60+26=86 seconds. No time is required between steps. + +To simplify things for the example, however, suppose you only have help from one Elf (a total of two workers) and that each step takes 60 fewer seconds (so that step A takes 1 second and step Z takes 26 seconds). Then, using the same instructions as above, this is how each second would be spent: + +Second Worker 1 Worker 2 Done + 0 C . + 1 C . + 2 C . + 3 A F C + 4 B F CA + 5 B F CA + 6 D F CAB + 7 D F CAB + 8 D F CAB + 9 D . CABF + 10 E . CABFD + 11 E . CABFD + 12 E . CABFD + 13 E . CABFD + 14 E . CABFD + 15 . . CABFDE + +Each row represents one second of time. The Second column identifies how many seconds have passed as of the beginning of that second. Each worker column shows the step that worker is currently doing (or . if they are idle). The Done column shows completed steps. + +Note that the order of the steps has changed; this is because steps now take time to finish and multiple workers can begin multiple steps simultaneously. + +In this example, it would take 15 seconds for two workers to complete these steps. + +With 5 workers and the 60+ second step durations described above, how long will it take to complete all of the steps? + +*/ + +public class Day07 : IDay { - /* - - --- Day 7: The Sum of Its Parts --- - - You find yourself standing on a snow-covered coastline; apparently, you landed a little off course. The region is too hilly to see the North Pole from here, but you do spot some Elves that seem to be trying to unpack something that washed ashore. It's quite cold out, so you decide to risk creating a paradox by asking them for directions. - - "Oh, are you the search party?" Somehow, you can understand whatever Elves from the year 1018 speak; you assume it's Ancient Nordic Elvish. Could the device on your wrist also be a translator? "Those clothes don't look very warm; take this." They hand you a heavy coat. - - "We do need to find our way back to the North Pole, but we have higher priorities at the moment. You see, believe it or not, this box contains something that will solve all of Santa's transportation problems - at least, that's what it looks like from the pictures in the instructions." It doesn't seem like they can read whatever language it's in, but you can: "Sleigh kit. Some assembly required." - - "'Sleigh'? What a wonderful name! You must help us assemble this 'sleigh' at once!" They start excitedly pulling more parts out of the box. - - The instructions specify a series of steps and requirements about which steps must be finished before others can begin (your puzzle input). Each step is designated by a single letter. For example, suppose you have the following instructions: - - Step C must be finished before step A can begin. - Step C must be finished before step F can begin. - Step A must be finished before step B can begin. - Step A must be finished before step D can begin. - Step B must be finished before step E can begin. - Step D must be finished before step E can begin. - Step F must be finished before step E can begin. - - Visually, these requirements look like this: - - - -->A--->B-- - / \ \ - C -->D----->E - \ / - ---->F----- - - Your first goal is to determine the order in which the steps should be completed. If more than one step is ready, choose the step which is first alphabetically. In this example, the steps would be completed as follows: - - Only C is available, and so it is done first. - Next, both A and F are available. A is first alphabetically, so it is done next. - Then, even though F was available earlier, steps B and D are now also available, and B is the first alphabetically of the three. - After that, only D and F are available. E is not available because only some of its prerequisites are complete. Therefore, D is completed next. - F is the only choice, so it is done next. - Finally, E is completed. - - So, in this example, the correct order is CABDFE. - - In what order should the steps in your instructions be completed? - - --- Part Two --- - - As you're about to begin construction, four of the Elves offer to help. "The sun will set soon; it'll go faster if we work together." Now, you need to account for multiple people working on steps simultaneously. If multiple steps are available, workers should still begin them in alphabetical order. - - Each step takes 60 seconds plus an amount corresponding to its letter: A=1, B=2, C=3, and so on. So, step A takes 60+1=61 seconds, while step Z takes 60+26=86 seconds. No time is required between steps. - - To simplify things for the example, however, suppose you only have help from one Elf (a total of two workers) and that each step takes 60 fewer seconds (so that step A takes 1 second and step Z takes 26 seconds). Then, using the same instructions as above, this is how each second would be spent: - - Second Worker 1 Worker 2 Done - 0 C . - 1 C . - 2 C . - 3 A F C - 4 B F CA - 5 B F CA - 6 D F CAB - 7 D F CAB - 8 D F CAB - 9 D . CABF - 10 E . CABFD - 11 E . CABFD - 12 E . CABFD - 13 E . CABFD - 14 E . CABFD - 15 . . CABFDE - - Each row represents one second of time. The Second column identifies how many seconds have passed as of the beginning of that second. Each worker column shows the step that worker is currently doing (or . if they are idle). The Done column shows completed steps. - - Note that the order of the steps has changed; this is because steps now take time to finish and multiple workers can begin multiple steps simultaneously. - - In this example, it would take 15 seconds for two workers to complete these steps. - - With 5 workers and the 60+ second step durations described above, how long will it take to complete all of the steps? - - */ - - public class Day07 : IDay + private static Instructions BuildInstructions(string[] inputs, int baseCost) { - private static Instructions BuildInstructions(string[] inputs, int baseCost) + Instructions instructions = new(); + foreach (string input in inputs) { - Instructions instructions = new Instructions(); - foreach (string input in inputs) - { - if (string.IsNullOrEmpty(input)) { continue; } - string[] parts = input.Split(new string[] { - "Step ", - " must be finished before step ", - " can begin.", - }, StringSplitOptions.RemoveEmptyEntries); - instructions.AddNodeRelation(parts[1].ToUpper(), parts[0].ToUpper()); - } - foreach (InstructionNode node in instructions.Nodes.Values) - { - char nodeID = node.NodeID[0]; - int nodeCost = baseCost + (nodeID - 'A') + 1; - node.Cost = nodeCost; - } - - return instructions; + if (string.IsNullOrEmpty(input)) { continue; } + string[] parts = input.Split(new[] { + "Step ", + " must be finished before step ", + " can begin.", + }, StringSplitOptions.RemoveEmptyEntries); + instructions.AddNodeRelation(parts[1].ToUpper(), parts[0].ToUpper()); + } + foreach (InstructionNode node in instructions.Nodes.Values) + { + char nodeID = node.NodeID[0]; + int nodeCost = baseCost + (nodeID - 'A') + 1; + node.Cost = nodeCost; } - public string ResolvePart1(string[] inputs) + return instructions; + } + + public string ResolvePart1(string[] inputs) + { + Instructions instructions = BuildInstructions(inputs, 0); + List finalInstructions = instructions.SortInstructions(); + StringBuilder sbInstructions = new(); + foreach (InstructionNode node in finalInstructions) { - Instructions instructions = BuildInstructions(inputs, 0); - List finalInstructions = instructions.SortInstructions(); - StringBuilder sbInstructions = new StringBuilder(); - foreach (InstructionNode node in finalInstructions) - { - sbInstructions.Append(node.NodeID); - } - return sbInstructions.ToString(); + sbInstructions.Append(node.NodeID); + } + return sbInstructions.ToString(); + } + + public int BaseCost { get; set; } = 60; + public int NumberOfWorkers { get; set; } = 5; + + public string ResolvePart2(string[] inputs) + { + Instructions instructions = BuildInstructions(inputs, BaseCost); + int totalElapsedTime = instructions.SimulateInstructionsUsage(NumberOfWorkers); + return totalElapsedTime.ToString(); + } +} + +public class InstructionNode +{ + public string NodeID { get; set; } + + public List PreviousNodeIDs { get; } = new(); + + public int Cost { get; set; } + + public bool Running { get; set; } + + public bool Used { get; set; } + + public bool CanBeUsed(Dictionary allNodes) + { + if (PreviousNodeIDs.Count == 0) { return true; } + bool allPreviousUsed = PreviousNodeIDs.All(nodeID => allNodes[nodeID].Used); + return allPreviousUsed; + } +} + +public class Instructions +{ + public Dictionary Nodes { get; } = new(); + + public InstructionNode GetNode(string nodeID) + { + InstructionNode node = null; + if (Nodes.ContainsKey(nodeID)) + { + node = Nodes[nodeID]; + } + else + { + node = new InstructionNode { NodeID = nodeID, }; + Nodes.Add(nodeID, node); + } + return node; + } + + public void AddNodeRelation(string nodeID, string previousNodeID) + { + InstructionNode node = GetNode(nodeID); + InstructionNode previousNode = GetNode(previousNodeID); + node.PreviousNodeIDs.Add(previousNode.NodeID); + } + + public List SortInstructions() + { + List finalNodes = new(); + + foreach (InstructionNode node in Nodes.Values) + { + node.Used = false; } - public int BaseCost { get; set; } = 60; - public int NumberOfWorkers { get; set; } = 5; - - public string ResolvePart2(string[] inputs) + List unusedNodes; + do { - Instructions instructions = BuildInstructions(inputs, BaseCost); - int totalElapsedTime = instructions.SimulateInstructionsUsage(NumberOfWorkers); - return totalElapsedTime.ToString(); + unusedNodes = Nodes.Values + .Where(n => + n.Used == false && + n.CanBeUsed(Nodes)) + .OrderBy(n => n.NodeID) + .ToList(); + if (unusedNodes.Count > 0) + { + InstructionNode node = unusedNodes.FirstOrDefault(); + finalNodes.Add(node); + node.Used = true; + } + } while (unusedNodes.Count > 0); + return finalNodes; + } + + private class SimulatedWorker + { + public InstructionNode CurrentInstruction { get; set; } + public int ElapsedTime { get; set; } + + public void SetInstruction(InstructionNode instruction) + { + CurrentInstruction = instruction; + ElapsedTime = 0; + instruction.Running = true; + } + + public bool Work() + { + if (CurrentInstruction == null) { return false; } + ElapsedTime++; + if (CurrentInstruction.Cost <= ElapsedTime) + { + CurrentInstruction.Running = false; + CurrentInstruction.Used = true; + CurrentInstruction = null; + } + return true; } } - public class InstructionNode + public int SimulateInstructionsUsage(int numberOfWorkers) { - public string NodeID { get; set; } - - public List PreviousNodeIDs { get; } = new List(); - - public int Cost { get; set; } - - public bool Running { get; set; } = false; - - public bool Used { get; set; } = false; - - public bool CanBeUsed(Dictionary allNodes) + int totalElapsedTime = 0; + foreach (InstructionNode node in Nodes.Values) { - if (PreviousNodeIDs.Count == 0) { return true; } - bool allPreviousUsed = PreviousNodeIDs.All(nodeID => allNodes[nodeID].Used); - return allPreviousUsed; + node.Used = false; + node.Running = false; } - } - - public class Instructions - { - public Dictionary Nodes { get; } = new Dictionary(); - - public InstructionNode GetNode(string nodeID) + List workers = new(numberOfWorkers); + for (int i = 0; i < numberOfWorkers; i++) { - InstructionNode node = null; - if (Nodes.ContainsKey(nodeID)) - { - node = Nodes[nodeID]; - } - else - { - node = new InstructionNode { NodeID = nodeID, }; - Nodes.Add(nodeID, node); - } - return node; + workers.Add(new SimulatedWorker()); } - public void AddNodeRelation(string nodeID, string previousNodeID) + bool anyWorkerWitoutWork; + do { - InstructionNode node = GetNode(nodeID); - InstructionNode previousNode = GetNode(previousNodeID); - node.PreviousNodeIDs.Add(previousNode.NodeID); - } - - public List SortInstructions() - { - List finalNodes = new List(); - - foreach (InstructionNode node in Nodes.Values) + bool anyWorkDone = false; + foreach (SimulatedWorker worker in workers) { - node.Used = false; + if (worker.Work()) + { + anyWorkDone = true; + } } + if (anyWorkDone) { totalElapsedTime++; } - List unusedNodes = null; - do + anyWorkerWitoutWork = workers.Any(w => w.CurrentInstruction == null); + if (anyWorkerWitoutWork) { - unusedNodes = Nodes.Values + List unusedNodes = Nodes.Values .Where(n => - n.Used == false && + n.Used == false && n.Running == false && n.CanBeUsed(Nodes)) .OrderBy(n => n.NodeID) .ToList(); if (unusedNodes.Count > 0) { - InstructionNode node = unusedNodes.FirstOrDefault(); - finalNodes.Add(node); - node.Used = true; - } - } while (unusedNodes.Count > 0); - return finalNodes; - } - - private class SimulatedWorker - { - public InstructionNode CurrentInstruction { get; set; } - public int ElapsedTime { get; set; } - - public void SetInstruction(InstructionNode instruction) - { - CurrentInstruction = instruction; - ElapsedTime = 0; - instruction.Running = true; - } - - public bool Work() - { - if (CurrentInstruction == null) { return false; } - ElapsedTime++; - if (CurrentInstruction.Cost <= ElapsedTime) - { - CurrentInstruction.Running = false; - CurrentInstruction.Used = true; - CurrentInstruction = null; - } - return true; - } - } - - public int SimulateInstructionsUsage(int numberOfWorkers) - { - int totalElapsedTime = 0; - foreach (InstructionNode node in Nodes.Values) - { - node.Used = false; - node.Running = false; - } - List workers = new List(numberOfWorkers); - for (int i = 0; i < numberOfWorkers; i++) - { - workers.Add(new SimulatedWorker()); - } - - bool anyWorkerWitoutWork; - do - { - bool anyWorkDone = false; - foreach (SimulatedWorker worker in workers) - { - if (worker.Work()) + List workersWithoutWork = workers.Where(w => w.CurrentInstruction == null).ToList(); + for (int i = 0; i < workersWithoutWork.Count && i < unusedNodes.Count; i++) { - anyWorkDone = true; + workersWithoutWork[i].SetInstruction(unusedNodes[i]); } } - if (anyWorkDone) { totalElapsedTime++; } - - anyWorkerWitoutWork = workers.Any(w => w.CurrentInstruction == null); - if (anyWorkerWitoutWork) - { - List unusedNodes = Nodes.Values - .Where(n => - n.Used == false && n.Running == false && - n.CanBeUsed(Nodes)) - .OrderBy(n => n.NodeID) - .ToList(); - if (unusedNodes.Count > 0) - { - List workersWithoutWork = workers.Where(w => w.CurrentInstruction == null).ToList(); - for (int i = 0; i < workersWithoutWork.Count && i < unusedNodes.Count; i++) - { - workersWithoutWork[i].SetInstruction(unusedNodes[i]); - } - } - } - } while (workers.Any(w => w.CurrentInstruction != null)); - return totalElapsedTime; - } + } + } while (workers.Any(w => w.CurrentInstruction != null)); + return totalElapsedTime; } -} +} \ No newline at end of file diff --git a/AdventOfCode2018/Day08.cs b/AdventOfCode2018/Day08.cs index 110f387..fdb8a66 100644 --- a/AdventOfCode2018/Day08.cs +++ b/AdventOfCode2018/Day08.cs @@ -2,160 +2,158 @@ using System.Collections.Generic; using System.Linq; -namespace AdventOfCode2018 +namespace AdventOfCode2018; +/* +--- Day 8: Memory Maneuver --- + +The sleigh is much easier to pull than you'd expect for something its weight. Unfortunately, neither you nor the Elves know which way the North Pole is from here. + +You check your wrist device for anything that might help. It seems to have some kind of navigation system! Activating the navigation system produces more bad news: "Failed to start navigation system. Could not read software license file." + +The navigation system's license file consists of a list of numbers (your puzzle input). The numbers define a data structure which, when processed, produces some kind of tree that can be used to calculate the license number. + +The tree is made up of nodes; a single, outermost node forms the tree's root, and it contains all other nodes in the tree (or contains nodes that contain nodes, and so on). + +Specifically, a node consists of: + + A header, which is always exactly two numbers: + The quantity of child nodes. + The quantity of metadata entries. + Zero or more child nodes (as specified in the header). + One or more metadata entries (as specified in the header). + +Each child node is itself a node that has its own header, child nodes, and metadata. For example: + +2 3 0 3 10 11 12 1 1 0 1 99 2 1 1 2 +A---------------------------------- + B----------- C----------- + D----- + +In this example, each node of the tree is also marked with an underline starting with a letter for easier identification. In it, there are four nodes: + + A, which has 2 child nodes (B, C) and 3 metadata entries (1, 1, 2). + B, which has 0 child nodes and 3 metadata entries (10, 11, 12). + C, which has 1 child node (D) and 1 metadata entry (2). + D, which has 0 child nodes and 1 metadata entry (99). + +The first check done on the license file is to simply add up all of the metadata entries. In this example, that sum is 1+1+2+10+11+12+2+99=138. + +What is the sum of all metadata entries? + +--- Part Two --- + +The second check is slightly more complicated: you need to find the value of the root node (A in the example above). + +The value of a node depends on whether it has child nodes. + +If a node has no child nodes, its value is the sum of its metadata entries. So, the value of node B is 10+11+12=33, and the value of node D is 99. + +However, if a node does have child nodes, the metadata entries become indexes which refer to those child nodes. A metadata entry of 1 refers to the first child node, 2 to the second, 3 to the third, and so on. The value of this node is the sum of the values of the child nodes referenced by the metadata entries. If a referenced child node does not exist, that reference is skipped. A child node can be referenced multiple time and counts each time it is referenced. A metadata entry of 0 does not refer to any child node. + +For example, again using the above nodes: + + Node C has one metadata entry, 2. Because node C has only one child node, 2 references a child node which does not exist, and so the value of node C is 0. + Node A has three metadata entries: 1, 1, and 2. The 1 references node A's first child node, B, and the 2 references node A's second child node, C. Because node B has a value of 33 and node C has a value of 0, the value of node A is 33+33+0=66. + +So, in this example, the value of the root node is 66. + +What is the value of the root node? + +*/ + +public class Day08 : IDay { - /* - --- Day 8: Memory Maneuver --- - - The sleigh is much easier to pull than you'd expect for something its weight. Unfortunately, neither you nor the Elves know which way the North Pole is from here. - - You check your wrist device for anything that might help. It seems to have some kind of navigation system! Activating the navigation system produces more bad news: "Failed to start navigation system. Could not read software license file." - - The navigation system's license file consists of a list of numbers (your puzzle input). The numbers define a data structure which, when processed, produces some kind of tree that can be used to calculate the license number. - - The tree is made up of nodes; a single, outermost node forms the tree's root, and it contains all other nodes in the tree (or contains nodes that contain nodes, and so on). - - Specifically, a node consists of: - - A header, which is always exactly two numbers: - The quantity of child nodes. - The quantity of metadata entries. - Zero or more child nodes (as specified in the header). - One or more metadata entries (as specified in the header). - - Each child node is itself a node that has its own header, child nodes, and metadata. For example: - - 2 3 0 3 10 11 12 1 1 0 1 99 2 1 1 2 - A---------------------------------- - B----------- C----------- - D----- - - In this example, each node of the tree is also marked with an underline starting with a letter for easier identification. In it, there are four nodes: - - A, which has 2 child nodes (B, C) and 3 metadata entries (1, 1, 2). - B, which has 0 child nodes and 3 metadata entries (10, 11, 12). - C, which has 1 child node (D) and 1 metadata entry (2). - D, which has 0 child nodes and 1 metadata entry (99). - - The first check done on the license file is to simply add up all of the metadata entries. In this example, that sum is 1+1+2+10+11+12+2+99=138. - - What is the sum of all metadata entries? - - --- Part Two --- - - The second check is slightly more complicated: you need to find the value of the root node (A in the example above). - - The value of a node depends on whether it has child nodes. - - If a node has no child nodes, its value is the sum of its metadata entries. So, the value of node B is 10+11+12=33, and the value of node D is 99. - - However, if a node does have child nodes, the metadata entries become indexes which refer to those child nodes. A metadata entry of 1 refers to the first child node, 2 to the second, 3 to the third, and so on. The value of this node is the sum of the values of the child nodes referenced by the metadata entries. If a referenced child node does not exist, that reference is skipped. A child node can be referenced multiple time and counts each time it is referenced. A metadata entry of 0 does not refer to any child node. - - For example, again using the above nodes: - - Node C has one metadata entry, 2. Because node C has only one child node, 2 references a child node which does not exist, and so the value of node C is 0. - Node A has three metadata entries: 1, 1, and 2. The 1 references node A's first child node, B, and the 2 references node A's second child node, C. Because node B has a value of 33 and node C has a value of 0, the value of node A is 33+33+0=66. - - So, in this example, the value of the root node is 66. - - What is the value of the root node? - - */ - - public class Day08 : IDay + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) - { - IntStream values = new IntStream(inputs[0]); - ChronoLicenceNode licenceTree = ChronoLicenceNode.BuildFromIntStream(values); - int result = licenceTree.GetChecksum(); - return result.ToString(); - } - - public string ResolvePart2(string[] inputs) - { - IntStream values = new IntStream(inputs[0]); - ChronoLicenceNode licenceTree = ChronoLicenceNode.BuildFromIntStream(values); - int result = licenceTree.GetValue(); - return result.ToString(); - } + IntStream values = new(inputs[0]); + ChronoLicenceNode licenceTree = ChronoLicenceNode.BuildFromIntStream(values); + int result = licenceTree.GetChecksum(); + return result.ToString(); } - public class IntStream + public string ResolvePart2(string[] inputs) { - private int[] values; - private int index; - - public IntStream(string strValues) - { - values = strValues - .Split(new string[] { " ", }, StringSplitOptions.RemoveEmptyEntries) - .Select(strVal => Convert.ToInt32(strVal)) - .ToArray(); - index = 0; - } - - public int Get() - { - int value = values[index]; - index++; - return value; - } - } - - public class ChronoLicenceNode - { - public List Childs { get; } = new List(); - - public List Metadata { get; } = new List(); - - public static ChronoLicenceNode BuildFromIntStream(IntStream stream) - { - ChronoLicenceNode node = new ChronoLicenceNode(); - int numChilds = stream.Get(); - int numMetadata = stream.Get(); - - for (int i = 0; i < numChilds; i++) - { - ChronoLicenceNode childNode = BuildFromIntStream(stream); - node.Childs.Add(childNode); - } - - for (int i = 0; i < numMetadata; i++) - { - node.Metadata.Add(stream.Get()); - } - - return node; - } - - public int GetChecksum() - { - int checksum = Metadata.Sum(); - foreach (ChronoLicenceNode child in Childs) - { - checksum += child.GetChecksum(); - } - return checksum; - } - - public int GetValue() - { - int value = 0; - if (Childs.Count == 0) - { - value = Metadata.Sum(); - } - else - { - foreach (int metadata in Metadata) - { - int index = metadata - 1; - if (index < 0 || index >= Childs.Count) { continue; } - value += Childs[index].GetValue(); - } - } - return value; - } + IntStream values = new(inputs[0]); + ChronoLicenceNode licenceTree = ChronoLicenceNode.BuildFromIntStream(values); + int result = licenceTree.GetValue(); + return result.ToString(); } } + +public class IntStream +{ + private int[] _values; + private int _index; + + public IntStream(string strValues) + { + _values = strValues + .Split(new[] { " ", }, StringSplitOptions.RemoveEmptyEntries) + .Select(strVal => Convert.ToInt32(strVal)) + .ToArray(); + _index = 0; + } + + public int Get() + { + int value = _values[_index]; + _index++; + return value; + } +} + +public class ChronoLicenceNode +{ + public List Childs { get; } = new(); + + public List Metadata { get; } = new(); + + public static ChronoLicenceNode BuildFromIntStream(IntStream stream) + { + ChronoLicenceNode node = new(); + int numChilds = stream.Get(); + int numMetadata = stream.Get(); + + for (int i = 0; i < numChilds; i++) + { + ChronoLicenceNode childNode = BuildFromIntStream(stream); + node.Childs.Add(childNode); + } + + for (int i = 0; i < numMetadata; i++) + { + node.Metadata.Add(stream.Get()); + } + + return node; + } + + public int GetChecksum() + { + int checksum = Metadata.Sum(); + foreach (ChronoLicenceNode child in Childs) + { + checksum += child.GetChecksum(); + } + return checksum; + } + + public int GetValue() + { + int value = 0; + if (Childs.Count == 0) + { + value = Metadata.Sum(); + } + else + { + foreach (int metadata in Metadata) + { + int index = metadata - 1; + if (index < 0 || index >= Childs.Count) { continue; } + value += Childs[index].GetValue(); + } + } + return value; + } +} \ No newline at end of file diff --git a/AdventOfCode2018/Day09.cs b/AdventOfCode2018/Day09.cs index 8f34532..e8851a7 100644 --- a/AdventOfCode2018/Day09.cs +++ b/AdventOfCode2018/Day09.cs @@ -2,173 +2,171 @@ using System.Collections.Generic; using System.Linq; -namespace AdventOfCode2018 +namespace AdventOfCode2018; +/* +--- Day 9: Marble Mania --- + +You talk to the Elves while you wait for your navigation system to initialize. To pass the time, they introduce you to their favorite marble game. + +The Elves play this game by taking turns arranging the marbles in a circle according to very particular rules. The marbles are numbered starting with 0 and increasing by 1 until every marble has a number. + +First, the marble numbered 0 is placed in the circle. At this point, while it contains only a single marble, it is still a circle: the marble is both clockwise from itself and counter-clockwise from itself. This marble is designated the current marble. + +Then, each Elf takes a turn placing the lowest-numbered remaining marble into the circle between the marbles that are 1 and 2 marbles clockwise of the current marble. (When the circle is large enough, this means that there is one marble between the marble that was just placed and the current marble.) The marble that was just placed then becomes the current marble. + +However, if the marble that is about to be placed has a number which is a multiple of 23, something entirely different happens. First, the current player keeps the marble they would have placed, adding it to their score. In addition, the marble 7 marbles counter-clockwise from the current marble is removed from the circle and also added to the current player's score. The marble located immediately clockwise of the marble that was removed becomes the new current marble. + +For example, suppose there are 9 players. After the marble with value 0 is placed in the middle, each player (shown in square brackets) takes a turn. The result of each of those turns would produce circles of marbles like this, where clockwise is to the right and the resulting current marble is in parentheses: + +[-] (0) +[1] 0 (1) +[2] 0 (2) 1 +[3] 0 2 1 (3) +[4] 0 (4) 2 1 3 +[5] 0 4 2 (5) 1 3 +[6] 0 4 2 5 1 (6) 3 +[7] 0 4 2 5 1 6 3 (7) +[8] 0 (8) 4 2 5 1 6 3 7 +[9] 0 8 4 (9) 2 5 1 6 3 7 +[1] 0 8 4 9 2(10) 5 1 6 3 7 +[2] 0 8 4 9 2 10 5(11) 1 6 3 7 +[3] 0 8 4 9 2 10 5 11 1(12) 6 3 7 +[4] 0 8 4 9 2 10 5 11 1 12 6(13) 3 7 +[5] 0 8 4 9 2 10 5 11 1 12 6 13 3(14) 7 +[6] 0 8 4 9 2 10 5 11 1 12 6 13 3 14 7(15) +[7] 0(16) 8 4 9 2 10 5 11 1 12 6 13 3 14 7 15 +[8] 0 16 8(17) 4 9 2 10 5 11 1 12 6 13 3 14 7 15 +[9] 0 16 8 17 4(18) 9 2 10 5 11 1 12 6 13 3 14 7 15 +[1] 0 16 8 17 4 18 9(19) 2 10 5 11 1 12 6 13 3 14 7 15 +[2] 0 16 8 17 4 18 9 19 2(20)10 5 11 1 12 6 13 3 14 7 15 +[3] 0 16 8 17 4 18 9 19 2 20 10(21) 5 11 1 12 6 13 3 14 7 15 +[4] 0 16 8 17 4 18 9 19 2 20 10 21 5(22)11 1 12 6 13 3 14 7 15 +[5] 0 16 8 17 4 18(19) 2 20 10 21 5 22 11 1 12 6 13 3 14 7 15 +[6] 0 16 8 17 4 18 19 2(24)20 10 21 5 22 11 1 12 6 13 3 14 7 15 +[7] 0 16 8 17 4 18 19 2 24 20(25)10 21 5 22 11 1 12 6 13 3 14 7 15 + +The goal is to be the player with the highest score after the last marble is used up. Assuming the example above ends after the marble numbered 25, the winning score is 23+9=32 (because player 5 kept marble 23 and removed marble 9, while no other player got any points in this very short example game). + +Here are a few more examples: + + 10 players; last marble is worth 1618 points: high score is 8317 + 13 players; last marble is worth 7999 points: high score is 146373 + 17 players; last marble is worth 1104 points: high score is 2764 + 21 players; last marble is worth 6111 points: high score is 54718 + 30 players; last marble is worth 5807 points: high score is 37305 + +What is the winning Elf's score? + +--- Part Two --- + +Amused by the speed of your answer, the Elves are curious: + +What would the new winning Elf's score be if the number of the last marble were 100 times larger? + +*/ + +public class Day09 : IDay { - /* - --- Day 9: Marble Mania --- - - You talk to the Elves while you wait for your navigation system to initialize. To pass the time, they introduce you to their favorite marble game. - - The Elves play this game by taking turns arranging the marbles in a circle according to very particular rules. The marbles are numbered starting with 0 and increasing by 1 until every marble has a number. - - First, the marble numbered 0 is placed in the circle. At this point, while it contains only a single marble, it is still a circle: the marble is both clockwise from itself and counter-clockwise from itself. This marble is designated the current marble. - - Then, each Elf takes a turn placing the lowest-numbered remaining marble into the circle between the marbles that are 1 and 2 marbles clockwise of the current marble. (When the circle is large enough, this means that there is one marble between the marble that was just placed and the current marble.) The marble that was just placed then becomes the current marble. - - However, if the marble that is about to be placed has a number which is a multiple of 23, something entirely different happens. First, the current player keeps the marble they would have placed, adding it to their score. In addition, the marble 7 marbles counter-clockwise from the current marble is removed from the circle and also added to the current player's score. The marble located immediately clockwise of the marble that was removed becomes the new current marble. - - For example, suppose there are 9 players. After the marble with value 0 is placed in the middle, each player (shown in square brackets) takes a turn. The result of each of those turns would produce circles of marbles like this, where clockwise is to the right and the resulting current marble is in parentheses: - - [-] (0) - [1] 0 (1) - [2] 0 (2) 1 - [3] 0 2 1 (3) - [4] 0 (4) 2 1 3 - [5] 0 4 2 (5) 1 3 - [6] 0 4 2 5 1 (6) 3 - [7] 0 4 2 5 1 6 3 (7) - [8] 0 (8) 4 2 5 1 6 3 7 - [9] 0 8 4 (9) 2 5 1 6 3 7 - [1] 0 8 4 9 2(10) 5 1 6 3 7 - [2] 0 8 4 9 2 10 5(11) 1 6 3 7 - [3] 0 8 4 9 2 10 5 11 1(12) 6 3 7 - [4] 0 8 4 9 2 10 5 11 1 12 6(13) 3 7 - [5] 0 8 4 9 2 10 5 11 1 12 6 13 3(14) 7 - [6] 0 8 4 9 2 10 5 11 1 12 6 13 3 14 7(15) - [7] 0(16) 8 4 9 2 10 5 11 1 12 6 13 3 14 7 15 - [8] 0 16 8(17) 4 9 2 10 5 11 1 12 6 13 3 14 7 15 - [9] 0 16 8 17 4(18) 9 2 10 5 11 1 12 6 13 3 14 7 15 - [1] 0 16 8 17 4 18 9(19) 2 10 5 11 1 12 6 13 3 14 7 15 - [2] 0 16 8 17 4 18 9 19 2(20)10 5 11 1 12 6 13 3 14 7 15 - [3] 0 16 8 17 4 18 9 19 2 20 10(21) 5 11 1 12 6 13 3 14 7 15 - [4] 0 16 8 17 4 18 9 19 2 20 10 21 5(22)11 1 12 6 13 3 14 7 15 - [5] 0 16 8 17 4 18(19) 2 20 10 21 5 22 11 1 12 6 13 3 14 7 15 - [6] 0 16 8 17 4 18 19 2(24)20 10 21 5 22 11 1 12 6 13 3 14 7 15 - [7] 0 16 8 17 4 18 19 2 24 20(25)10 21 5 22 11 1 12 6 13 3 14 7 15 - - The goal is to be the player with the highest score after the last marble is used up. Assuming the example above ends after the marble numbered 25, the winning score is 23+9=32 (because player 5 kept marble 23 and removed marble 9, while no other player got any points in this very short example game). - - Here are a few more examples: - - 10 players; last marble is worth 1618 points: high score is 8317 - 13 players; last marble is worth 7999 points: high score is 146373 - 17 players; last marble is worth 1104 points: high score is 2764 - 21 players; last marble is worth 6111 points: high score is 54718 - 30 players; last marble is worth 5807 points: high score is 37305 - - What is the winning Elf's score? - - --- Part Two --- - - Amused by the speed of your answer, the Elves are curious: - - What would the new winning Elf's score be if the number of the last marble were 100 times larger? - - */ - - public class Day09 : IDay + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) - { - return CalculateHighScore(inputs[0], 1); - } - - public string ResolvePart2(string[] inputs) - { - return CalculateHighScore(inputs[0], 100); - } - - private static string CalculateHighScore(string input, long factor) - { - string[] parts = input.Split(new string[] { " players; last marble is worth ", " points" }, StringSplitOptions.RemoveEmptyEntries); - long numberOfPlayers = Convert.ToInt32(parts[0]); - long lastMarble = Convert.ToInt32(parts[1]) * factor; - MarbleGame marbleGame = new MarbleGame(); - marbleGame.PlayGame(numberOfPlayers, lastMarble); - long result = marbleGame.GetHighScore(); - return result.ToString(); - } + return CalculateHighScore(inputs[0], 1); } - public class Marble + public string ResolvePart2(string[] inputs) { - public long Value { get; set; } - public Marble Previous { get; set; } - public Marble Next { get; set; } + return CalculateHighScore(inputs[0], 100); } - public class MarbleGame + private static string CalculateHighScore(string input, long factor) { - public Dictionary Scores { get; } = new Dictionary(); - - private Marble firstMarble; - private Marble currentMarble; - private long currentPlayer = 0; - - private const long PointValueMultiple = 23; - - public void PlayGame(long numPlayers, long lastMarble, bool showStatus = false) - { - Scores.Clear(); - firstMarble = new Marble { Value = 0 }; - firstMarble.Previous = firstMarble; - firstMarble.Next = firstMarble; - currentMarble = firstMarble; - - for (long i = 1; i <= numPlayers; i++) { Scores.Add(i, 0); } - - for (long i = 0; i <= lastMarble; i++) - { - if (showStatus) { PrintStatus(); } - - currentPlayer = (i % numPlayers) + 1; - Marble newMarble = new Marble { Value = i + 1 }; - if ((newMarble.Value % PointValueMultiple) > 0) - { - Marble previousMarble = currentMarble.Next; - Marble nextMarble = previousMarble.Next; - newMarble.Previous = previousMarble; - newMarble.Next = nextMarble; - previousMarble.Next = newMarble; - nextMarble.Previous = newMarble; - currentMarble = newMarble; - } - else - { - Marble marbleToRemove = currentMarble.Previous.Previous.Previous.Previous.Previous.Previous.Previous; - currentMarble = marbleToRemove.Next; - marbleToRemove.Previous.Next = marbleToRemove.Next; - marbleToRemove.Next.Previous = marbleToRemove.Previous; - - long currentPlayerScore = Scores[currentPlayer] + (newMarble.Value + marbleToRemove.Value); - Scores[currentPlayer] = currentPlayerScore; - } - - } - } - - public void PrintStatus() - { - Console.Write("[{0}] ", currentPlayer); - Marble marble = firstMarble; - do - { - if (currentMarble.Value == marble.Value) - { - Console.Write("({0}) ", marble.Value); - } - else - { - Console.Write("{0} ", marble.Value); - } - marble = marble.Next; - } while (marble.Value != 0); - Console.WriteLine(); - } - - public long GetHighScore() - { - return Scores.Values.Max(); - } + string[] parts = input.Split(new[] { " players; last marble is worth ", " points" }, StringSplitOptions.RemoveEmptyEntries); + long numberOfPlayers = Convert.ToInt32(parts[0]); + long lastMarble = Convert.ToInt32(parts[1]) * factor; + MarbleGame marbleGame = new(); + marbleGame.PlayGame(numberOfPlayers, lastMarble); + long result = marbleGame.GetHighScore(); + return result.ToString(); } } + +public class Marble +{ + public long Value { get; set; } + public Marble Previous { get; set; } + public Marble Next { get; set; } +} + +public class MarbleGame +{ + public Dictionary Scores { get; } = new(); + + private Marble _firstMarble; + private Marble _currentMarble; + private long _currentPlayer; + + private const long PointValueMultiple = 23; + + public void PlayGame(long numPlayers, long lastMarble, bool showStatus = false) + { + Scores.Clear(); + _firstMarble = new Marble { Value = 0 }; + _firstMarble.Previous = _firstMarble; + _firstMarble.Next = _firstMarble; + _currentMarble = _firstMarble; + + for (long i = 1; i <= numPlayers; i++) { Scores.Add(i, 0); } + + for (long i = 0; i <= lastMarble; i++) + { + if (showStatus) { PrintStatus(); } + + _currentPlayer = (i % numPlayers) + 1; + Marble newMarble = new() { Value = i + 1 }; + if ((newMarble.Value % PointValueMultiple) > 0) + { + Marble previousMarble = _currentMarble.Next; + Marble nextMarble = previousMarble.Next; + newMarble.Previous = previousMarble; + newMarble.Next = nextMarble; + previousMarble.Next = newMarble; + nextMarble.Previous = newMarble; + _currentMarble = newMarble; + } + else + { + Marble marbleToRemove = _currentMarble.Previous.Previous.Previous.Previous.Previous.Previous.Previous; + _currentMarble = marbleToRemove.Next; + marbleToRemove.Previous.Next = marbleToRemove.Next; + marbleToRemove.Next.Previous = marbleToRemove.Previous; + + long currentPlayerScore = Scores[_currentPlayer] + (newMarble.Value + marbleToRemove.Value); + Scores[_currentPlayer] = currentPlayerScore; + } + + } + } + + public void PrintStatus() + { + Console.Write("[{0}] ", _currentPlayer); + Marble marble = _firstMarble; + do + { + if (_currentMarble.Value == marble.Value) + { + Console.Write("({0}) ", marble.Value); + } + else + { + Console.Write("{0} ", marble.Value); + } + marble = marble.Next; + } while (marble.Value != 0); + Console.WriteLine(); + } + + public long GetHighScore() + { + return Scores.Values.Max(); + } +} \ No newline at end of file diff --git a/AdventOfCode2018/Day10.cs b/AdventOfCode2018/Day10.cs index 8c3fbe5..36ebf2d 100644 --- a/AdventOfCode2018/Day10.cs +++ b/AdventOfCode2018/Day10.cs @@ -3,308 +3,305 @@ using System.Collections.Generic; using System.Linq; using System.Text; -namespace AdventOfCode2018 +namespace AdventOfCode2018; +/* +--- Day 10: The Stars Align --- + +It's no use; your navigation system simply isn't capable of providing walking directions in the arctic circle, and certainly not in 1018. + +The Elves suggest an alternative. In times like these, North Pole rescue operations will arrange points of light in the sky to guide missing Elves back to base. Unfortunately, the message is easy to miss: the points move slowly enough that it takes hours to align them, but have so much momentum that they only stay aligned for a second. If you blink at the wrong time, it might be hours before another message appears. + +You can see these points of light floating in the distance, and record their position in the sky and their velocity, the relative change in position per second (your puzzle input). The coordinates are all given from your perspective; given enough time, those positions and velocities will move the points into a cohesive message! + +Rather than wait, you decide to fast-forward the process and calculate what the points will eventually spell. + +For example, suppose you note the following points: + +position=< 9, 1> velocity=< 0, 2> +position=< 7, 0> velocity=<-1, 0> +position=< 3, -2> velocity=<-1, 1> +position=< 6, 10> velocity=<-2, -1> +position=< 2, -4> velocity=< 2, 2> +position=<-6, 10> velocity=< 2, -2> +position=< 1, 8> velocity=< 1, -1> +position=< 1, 7> velocity=< 1, 0> +position=<-3, 11> velocity=< 1, -2> +position=< 7, 6> velocity=<-1, -1> +position=<-2, 3> velocity=< 1, 0> +position=<-4, 3> velocity=< 2, 0> +position=<10, -3> velocity=<-1, 1> +position=< 5, 11> velocity=< 1, -2> +position=< 4, 7> velocity=< 0, -1> +position=< 8, -2> velocity=< 0, 1> +position=<15, 0> velocity=<-2, 0> +position=< 1, 6> velocity=< 1, 0> +position=< 8, 9> velocity=< 0, -1> +position=< 3, 3> velocity=<-1, 1> +position=< 0, 5> velocity=< 0, -1> +position=<-2, 2> velocity=< 2, 0> +position=< 5, -2> velocity=< 1, 2> +position=< 1, 4> velocity=< 2, 1> +position=<-2, 7> velocity=< 2, -2> +position=< 3, 6> velocity=<-1, -1> +position=< 5, 0> velocity=< 1, 0> +position=<-6, 0> velocity=< 2, 0> +position=< 5, 9> velocity=< 1, -2> +position=<14, 7> velocity=<-2, 0> +position=<-3, 6> velocity=< 2, -1> + +Each line represents one point. Positions are given as pairs: X represents how far left (negative) or right (positive) the point appears, while Y represents how far up (negative) or down (positive) the point appears. + +At 0 seconds, each point has the position given. Each second, each point's velocity is added to its position. So, a point with velocity <1, -2> is moving to the right, but is moving upward twice as quickly. If this point's initial position were <3, 9>, after 3 seconds, its position would become <6, 3>. + +Over time, the points listed above would move like this: + +Initially: +........#............. +................#..... +.........#.#..#....... +...................... +#..........#.#.......# +...............#...... +....#................. +..#.#....#............ +.......#.............. +......#............... +...#...#.#...#........ +....#..#..#.........#. +.......#.............. +...........#..#....... +#...........#......... +...#.......#.......... + +After 1 second: +...................... +...................... +..........#....#...... +........#.....#....... +..#.........#......#.. +...................... +......#............... +....##.........#...... +......#.#............. +.....##.##..#......... +........#.#........... +........#...#.....#... +..#...........#....... +....#.....#.#......... +...................... +...................... + +After 2 seconds: +...................... +...................... +...................... +..............#....... +....#..#...####..#.... +...................... +........#....#........ +......#.#............. +.......#...#.......... +.......#..#..#.#...... +....#....#.#.......... +.....#...#...##.#..... +........#............. +...................... +...................... +...................... + +After 3 seconds: +...................... +...................... +...................... +...................... +......#...#..###...... +......#...#...#....... +......#...#...#....... +......#####...#....... +......#...#...#....... +......#...#...#....... +......#...#...#....... +......#...#..###...... +...................... +...................... +...................... +...................... + +After 4 seconds: +...................... +...................... +...................... +............#......... +........##...#.#...... +......#.....#..#...... +.....#..##.##.#....... +.......##.#....#...... +...........#....#..... +..............#....... +....#......#...#...... +.....#.....##......... +...............#...... +...............#...... +...................... +...................... + +After 3 seconds, the message appeared briefly: HI. Of course, your message will be much longer and will take many more seconds to appear. + +What message will eventually appear in the sky? + +--- Part Two --- + +Good thing you didn't have to wait, because that would have taken a long time - much longer than the 3 seconds in the example above. + +Impressed by your sub-hour communication capabilities, the Elves are curious: exactly how many seconds would they have needed to wait for that message to appear? + +*/ + +public class Day10 : IDay { - /* - --- Day 10: The Stars Align --- + public int Width { get; set; } = 65; + public int Height { get; set; } = 12; - It's no use; your navigation system simply isn't capable of providing walking directions in the arctic circle, and certainly not in 1018. - - The Elves suggest an alternative. In times like these, North Pole rescue operations will arrange points of light in the sky to guide missing Elves back to base. Unfortunately, the message is easy to miss: the points move slowly enough that it takes hours to align them, but have so much momentum that they only stay aligned for a second. If you blink at the wrong time, it might be hours before another message appears. - - You can see these points of light floating in the distance, and record their position in the sky and their velocity, the relative change in position per second (your puzzle input). The coordinates are all given from your perspective; given enough time, those positions and velocities will move the points into a cohesive message! - - Rather than wait, you decide to fast-forward the process and calculate what the points will eventually spell. - - For example, suppose you note the following points: - - position=< 9, 1> velocity=< 0, 2> - position=< 7, 0> velocity=<-1, 0> - position=< 3, -2> velocity=<-1, 1> - position=< 6, 10> velocity=<-2, -1> - position=< 2, -4> velocity=< 2, 2> - position=<-6, 10> velocity=< 2, -2> - position=< 1, 8> velocity=< 1, -1> - position=< 1, 7> velocity=< 1, 0> - position=<-3, 11> velocity=< 1, -2> - position=< 7, 6> velocity=<-1, -1> - position=<-2, 3> velocity=< 1, 0> - position=<-4, 3> velocity=< 2, 0> - position=<10, -3> velocity=<-1, 1> - position=< 5, 11> velocity=< 1, -2> - position=< 4, 7> velocity=< 0, -1> - position=< 8, -2> velocity=< 0, 1> - position=<15, 0> velocity=<-2, 0> - position=< 1, 6> velocity=< 1, 0> - position=< 8, 9> velocity=< 0, -1> - position=< 3, 3> velocity=<-1, 1> - position=< 0, 5> velocity=< 0, -1> - position=<-2, 2> velocity=< 2, 0> - position=< 5, -2> velocity=< 1, 2> - position=< 1, 4> velocity=< 2, 1> - position=<-2, 7> velocity=< 2, -2> - position=< 3, 6> velocity=<-1, -1> - position=< 5, 0> velocity=< 1, 0> - position=<-6, 0> velocity=< 2, 0> - position=< 5, 9> velocity=< 1, -2> - position=<14, 7> velocity=<-2, 0> - position=<-3, 6> velocity=< 2, -1> - - Each line represents one point. Positions are given as pairs: X represents how far left (negative) or right (positive) the point appears, while Y represents how far up (negative) or down (positive) the point appears. - - At 0 seconds, each point has the position given. Each second, each point's velocity is added to its position. So, a point with velocity <1, -2> is moving to the right, but is moving upward twice as quickly. If this point's initial position were <3, 9>, after 3 seconds, its position would become <6, 3>. - - Over time, the points listed above would move like this: - - Initially: - ........#............. - ................#..... - .........#.#..#....... - ...................... - #..........#.#.......# - ...............#...... - ....#................. - ..#.#....#............ - .......#.............. - ......#............... - ...#...#.#...#........ - ....#..#..#.........#. - .......#.............. - ...........#..#....... - #...........#......... - ...#.......#.......... - - After 1 second: - ...................... - ...................... - ..........#....#...... - ........#.....#....... - ..#.........#......#.. - ...................... - ......#............... - ....##.........#...... - ......#.#............. - .....##.##..#......... - ........#.#........... - ........#...#.....#... - ..#...........#....... - ....#.....#.#......... - ...................... - ...................... - - After 2 seconds: - ...................... - ...................... - ...................... - ..............#....... - ....#..#...####..#.... - ...................... - ........#....#........ - ......#.#............. - .......#...#.......... - .......#..#..#.#...... - ....#....#.#.......... - .....#...#...##.#..... - ........#............. - ...................... - ...................... - ...................... - - After 3 seconds: - ...................... - ...................... - ...................... - ...................... - ......#...#..###...... - ......#...#...#....... - ......#...#...#....... - ......#####...#....... - ......#...#...#....... - ......#...#...#....... - ......#...#...#....... - ......#...#..###...... - ...................... - ...................... - ...................... - ...................... - - After 4 seconds: - ...................... - ...................... - ...................... - ............#......... - ........##...#.#...... - ......#.....#..#...... - .....#..##.##.#....... - .......##.#....#...... - ...........#....#..... - ..............#....... - ....#......#...#...... - .....#.....##......... - ...............#...... - ...............#...... - ...................... - ...................... - - After 3 seconds, the message appeared briefly: HI. Of course, your message will be much longer and will take many more seconds to appear. - - What message will eventually appear in the sky? - - --- Part Two --- - - Good thing you didn't have to wait, because that would have taken a long time - much longer than the 3 seconds in the example above. - - Impressed by your sub-hour communication capabilities, the Elves are curious: exactly how many seconds would they have needed to wait for that message to appear? - - */ - - public class Day10 : IDay + public string ResolvePart1(string[] inputs) { - public int Width { get; set; } = 65; - public int Height { get; set; } = 12; - - public string ResolvePart1(string[] inputs) - { - LightField lightField = new LightField(inputs); - int t = lightField.SearchSmallerBoundindBox(); - string result = lightField.Render(t, Width, Height); - return result; - } - - public string ResolvePart2(string[] inputs) - { - LightField lightField = new LightField(inputs); - int t = lightField.SearchSmallerBoundindBox(); - return t.ToString(); - } + LightField lightField = new(inputs); + int t = lightField.SearchSmallerBoundindBox(); + string result = lightField.Render(t, Width, Height); + return result; } - public class LightPoint + public string ResolvePart2(string[] inputs) { - public int X { get; set; } - public int Y { get; set; } - public int VX { get; set; } - public int VY { get; set; } + LightField lightField = new(inputs); + int t = lightField.SearchSmallerBoundindBox(); + return t.ToString(); + } +} - public static LightPoint FromString(string strPoint) - { - string[] parts = strPoint.Split(new string[] { "position=<", " ", ",", "> velocity=<", ">" }, StringSplitOptions.RemoveEmptyEntries); - LightPoint point = new LightPoint - { - X = Convert.ToInt32(parts[0]), - Y = Convert.ToInt32(parts[1]), - VX = Convert.ToInt32(parts[2]), - VY = Convert.ToInt32(parts[3]), - }; - return point; - } +public class LightPoint +{ + public int X { get; set; } + public int Y { get; set; } + public int VX { get; set; } + public int VY { get; set; } - public int GetX(int t) - { - return X + (VX * t); - } - - public int GetY(int t) - { - return Y + (VY * t); - } + public static LightPoint FromString(string strPoint) + { + string[] parts = strPoint.Split(new[] { "position=<", " ", ",", "> velocity=<", ">" }, StringSplitOptions.RemoveEmptyEntries); + LightPoint point = new() { + X = Convert.ToInt32(parts[0]), + Y = Convert.ToInt32(parts[1]), + VX = Convert.ToInt32(parts[2]), + VY = Convert.ToInt32(parts[3]), + }; + return point; } - public class LightField + public int GetX(int t) { - private List points; + return X + (VX * t); + } - public LightField(string[] strPoints) + public int GetY(int t) + { + return Y + (VY * t); + } +} + +public class LightField +{ + private readonly List _points; + + public LightField(string[] strPoints) + { + _points = strPoints.Select(strPoint => LightPoint.FromString(strPoint)).ToList(); + } + + public int SearchSmallerBoundindBox() + { + int minHeight = int.MaxValue; + int minT = 0; + int missCount = 0; + int t = 0; + do { - points = strPoints.Select(strPoint => LightPoint.FromString(strPoint)).ToList(); + int minY = int.MaxValue; + int maxY = int.MinValue; + foreach (LightPoint point in _points) + { + int y = point.GetY(t); + if (y < minY) { minY = y; } + if (y > maxY) { maxY = y; } + } + int height = (maxY - minY); + if (height < minHeight) + { + minHeight = height; + minT = t; + missCount = 0; + } + else + { + missCount++; + } + + t++; + } while (missCount < 1000); + return minT; + } + + public string Render(int t, int width, int height) + { + int minX = int.MaxValue; + int minY = int.MaxValue; + int maxX = int.MinValue; + int maxY = int.MinValue; + + foreach (LightPoint point in _points) + { + int x = point.GetX(t); + int y = point.GetY(t); + if (x < minX) { minX = x; } + if (y < minY) { minY = y; } + if (x > maxX) { maxX = x; } + if (y > maxY) { maxY = y; } + } + minX--; + minY--; + maxX += 2; + maxY += 2; + + double scaleX = (maxX - minX) / (double)width; + double scaleY = (maxY - minY) / (double)height; + + int[,] field = new int[width, height]; + foreach (LightPoint point in _points) + { + int x = point.GetX(t); + int y = point.GetY(t); + x = (int)(((x - minX) / scaleX) + 0.5); + y = (int)(((y - minY) / scaleY) + 0.5); + if (x < 0 || x >= width) { continue; } + if (y < 0 || y >= height) { continue; } + field[x, y]++; } - public int SearchSmallerBoundindBox() + StringBuilder sb = new(); + for (int j = 0; j < height; j++) { - int minHeight = int.MaxValue; - int minT = 0; - int missCount = 0; - int t = 0; - do + sb.AppendLine(); + for (int i = 0; i < width; i++) { - int minY = int.MaxValue; - int maxY = int.MinValue; - foreach (LightPoint point in points) + if (field[i, j] > 0) { - int y = point.GetY(t); - if (y < minY) { minY = y; } - if (y > maxY) { maxY = y; } - } - int height = (maxY - minY); - if (height < minHeight) - { - minHeight = height; - minT = t; - missCount = 0; + sb.Append("#"); } else { - missCount++; - } - - t++; - } while (missCount < 1000); - return minT; - } - - public string Render(int t, int width, int height) - { - int minX = int.MaxValue; - int minY = int.MaxValue; - int maxX = int.MinValue; - int maxY = int.MinValue; - - foreach (LightPoint point in points) - { - int x = point.GetX(t); - int y = point.GetY(t); - if (x < minX) { minX = x; } - if (y < minY) { minY = y; } - if (x > maxX) { maxX = x; } - if (y > maxY) { maxY = y; } - } - minX--; - minY--; - maxX += 2; - maxY += 2; - - double scaleX = (maxX - minX) / (double)width; - double scaleY = (maxY - minY) / (double)height; - - int[,] field = new int[width, height]; - foreach (LightPoint point in points) - { - int x = point.GetX(t); - int y = point.GetY(t); - x = (int)(((x - minX) / scaleX) + 0.5); - y = (int)(((y - minY) / scaleY) + 0.5); - if (x < 0 || x >= width) { continue; } - if (y < 0 || y >= height) { continue; } - field[x, y]++; - } - - StringBuilder sb = new StringBuilder(); - for (int j = 0; j < height; j++) - { - sb.AppendLine(); - for (int i = 0; i < width; i++) - { - if (field[i, j] > 0) - { - sb.Append("#"); - } - else - { - sb.Append("."); - } + sb.Append("."); } } - return sb.ToString(); } + return sb.ToString(); } -} +} \ No newline at end of file diff --git a/AdventOfCode2018/Day11.cs b/AdventOfCode2018/Day11.cs index 7dc5ed2..7a3aa20 100644 --- a/AdventOfCode2018/Day11.cs +++ b/AdventOfCode2018/Day11.cs @@ -1,226 +1,224 @@ using System; -namespace AdventOfCode2018 +namespace AdventOfCode2018; +/* + +--- Day 11: Chronal Charge --- + +You watch the Elves and their sleigh fade into the distance as they head toward the North Pole. + +Actually, you're the one fading. The falling sensation returns. + +The low fuel warning light is illuminated on your wrist-mounted device. Tapping it once causes it to project a hologram of the situation: a 300x300 grid of fuel cells and their current power levels, some negative. You're not sure what negative power means in the context of time travel, but it can't be good. + +Each fuel cell has a coordinate ranging from 1 to 300 in both the X (horizontal) and Y (vertical) direction. In X,Y notation, the top-left cell is 1,1, and the top-right cell is 300,1. + +The interface lets you select any 3x3 square of fuel cells. To increase your chances of getting to your destination, you decide to choose the 3x3 square with the largest total power. + +The power level in a given fuel cell can be found through the following process: + + Find the fuel cell's rack ID, which is its X coordinate plus 10. + Begin with a power level of the rack ID times the Y coordinate. + Increase the power level by the value of the grid serial number (your puzzle input). + Set the power level to itself multiplied by the rack ID. + Keep only the hundreds digit of the power level (so 12345 becomes 3; numbers with no hundreds digit become 0). + Subtract 5 from the power level. + +For example, to find the power level of the fuel cell at 3,5 in a grid with serial number 8: + + The rack ID is 3 + 10 = 13. + The power level starts at 13 * 5 = 65. + Adding the serial number produces 65 + 8 = 73. + Multiplying by the rack ID produces 73 * 13 = 949. + The hundreds digit of 949 is 9. + Subtracting 5 produces 9 - 5 = 4. + +So, the power level of this fuel cell is 4. + +Here are some more example power levels: + + Fuel cell at 122,79, grid serial number 57: power level -5. + Fuel cell at 217,196, grid serial number 39: power level 0. + Fuel cell at 101,153, grid serial number 71: power level 4. + +Your goal is to find the 3x3 square which has the largest total power. The square must be entirely within the 300x300 grid. Identify this square using the X,Y coordinate of its top-left fuel cell. For example: + +For grid serial number 18, the largest total 3x3 square has a top-left corner of 33,45 (with a total power of 29); these fuel cells appear in the middle of this 5x5 region: + +-2 -4 4 4 4 +-4 4 4 4 -5 + 4 3 3 4 -4 + 1 1 2 4 -3 +-1 0 2 -5 -2 + +For grid serial number 42, the largest 3x3 square's top-left is 21,61 (with a total power of 30); they are in the middle of this region: + +-3 4 2 2 2 +-4 4 3 3 4 +-5 3 3 4 -4 + 4 3 3 4 -3 + 3 3 3 -5 -1 + +What is the X,Y coordinate of the top-left fuel cell of the 3x3 square with the largest total power? + +--- Part Two --- + +You discover a dial on the side of the device; it seems to let you select a square of any size, not just 3x3. Sizes from 1x1 to 300x300 are supported. + +Realizing this, you now must find the square of any size with the largest total power. Identify this square by including its size as a third parameter after the top-left coordinate: a 9x9 square with a top-left corner of 3,5 is identified as 3,5,9. + +For example: + + For grid serial number 18, the largest total square (with a total power of 113) is 16x16 and has a top-left corner of 90,269, so its identifier is 90,269,16. + For grid serial number 42, the largest total square (with a total power of 119) is 12x12 and has a top-left corner of 232,251, so its identifier is 232,251,12. + +What is the X,Y,size identifier of the square with the largest total power? + +*/ + +public class Day11 : IDay { - /* - - --- Day 11: Chronal Charge --- - - You watch the Elves and their sleigh fade into the distance as they head toward the North Pole. - - Actually, you're the one fading. The falling sensation returns. - - The low fuel warning light is illuminated on your wrist-mounted device. Tapping it once causes it to project a hologram of the situation: a 300x300 grid of fuel cells and their current power levels, some negative. You're not sure what negative power means in the context of time travel, but it can't be good. - - Each fuel cell has a coordinate ranging from 1 to 300 in both the X (horizontal) and Y (vertical) direction. In X,Y notation, the top-left cell is 1,1, and the top-right cell is 300,1. - - The interface lets you select any 3x3 square of fuel cells. To increase your chances of getting to your destination, you decide to choose the 3x3 square with the largest total power. - - The power level in a given fuel cell can be found through the following process: - - Find the fuel cell's rack ID, which is its X coordinate plus 10. - Begin with a power level of the rack ID times the Y coordinate. - Increase the power level by the value of the grid serial number (your puzzle input). - Set the power level to itself multiplied by the rack ID. - Keep only the hundreds digit of the power level (so 12345 becomes 3; numbers with no hundreds digit become 0). - Subtract 5 from the power level. - - For example, to find the power level of the fuel cell at 3,5 in a grid with serial number 8: - - The rack ID is 3 + 10 = 13. - The power level starts at 13 * 5 = 65. - Adding the serial number produces 65 + 8 = 73. - Multiplying by the rack ID produces 73 * 13 = 949. - The hundreds digit of 949 is 9. - Subtracting 5 produces 9 - 5 = 4. - - So, the power level of this fuel cell is 4. - - Here are some more example power levels: - - Fuel cell at 122,79, grid serial number 57: power level -5. - Fuel cell at 217,196, grid serial number 39: power level 0. - Fuel cell at 101,153, grid serial number 71: power level 4. - - Your goal is to find the 3x3 square which has the largest total power. The square must be entirely within the 300x300 grid. Identify this square using the X,Y coordinate of its top-left fuel cell. For example: - - For grid serial number 18, the largest total 3x3 square has a top-left corner of 33,45 (with a total power of 29); these fuel cells appear in the middle of this 5x5 region: - - -2 -4 4 4 4 - -4 4 4 4 -5 - 4 3 3 4 -4 - 1 1 2 4 -3 - -1 0 2 -5 -2 - - For grid serial number 42, the largest 3x3 square's top-left is 21,61 (with a total power of 30); they are in the middle of this region: - - -3 4 2 2 2 - -4 4 3 3 4 - -5 3 3 4 -4 - 4 3 3 4 -3 - 3 3 3 -5 -1 - - What is the X,Y coordinate of the top-left fuel cell of the 3x3 square with the largest total power? - - --- Part Two --- - - You discover a dial on the side of the device; it seems to let you select a square of any size, not just 3x3. Sizes from 1x1 to 300x300 are supported. - - Realizing this, you now must find the square of any size with the largest total power. Identify this square by including its size as a third parameter after the top-left coordinate: a 9x9 square with a top-left corner of 3,5 is identified as 3,5,9. - - For example: - - For grid serial number 18, the largest total square (with a total power of 113) is 16x16 and has a top-left corner of 90,269, so its identifier is 90,269,16. - For grid serial number 42, the largest total square (with a total power of 119) is 12x12 and has a top-left corner of 232,251, so its identifier is 232,251,12. - - What is the X,Y,size identifier of the square with the largest total power? - - */ - - public class Day11 : IDay + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) - { - int serial = Convert.ToInt32(inputs[0]); - SearchBestRegionOfOneSize(300, 300, 3, serial, out int x, out int y); - return string.Format("{0},{1}", x, y); - } + int serial = Convert.ToInt32(inputs[0]); + SearchBestRegionOfOneSize(300, 300, 3, serial, out int x, out int y); + return $"{x},{y}"; + } - public string ResolvePart2(string[] inputs) - { - int serial = Convert.ToInt32(inputs[0]); - SearchBestRegion(300, 300, serial, out int x, out int y, out int size); - return string.Format("{0},{1},{2}", x, y, size); - } + public string ResolvePart2(string[] inputs) + { + int serial = Convert.ToInt32(inputs[0]); + SearchBestRegion(300, 300, serial, out int x, out int y, out int size); + return $"{x},{y},{size}"; + } - public static int CalculatePowerLevelOfCell(int x, int y, int serial) - { - int powerLevel = 0; - int rackID = x + 10; - powerLevel += rackID * y; - powerLevel += serial; - powerLevel = powerLevel * rackID; - powerLevel = (powerLevel / 100) % 10; - powerLevel -= 5; - return powerLevel; - } + public static int CalculatePowerLevelOfCell(int x, int y, int serial) + { + int powerLevel = 0; + int rackID = x + 10; + powerLevel += rackID * y; + powerLevel += serial; + powerLevel = powerLevel * rackID; + powerLevel = (powerLevel / 100) % 10; + powerLevel -= 5; + return powerLevel; + } - public static int CalculatePowerLevelOfRegion(int x, int y, int size, int serial) + public static int CalculatePowerLevelOfRegion(int x, int y, int size, int serial) + { + int powerLevel = 0; + for (int i = 0; i < size; i++) { - int powerLevel = 0; - for (int i = 0; i < size; i++) + for (int j = 0; j < size; j++) { - for (int j = 0; j < size; j++) + powerLevel += CalculatePowerLevelOfCell(x + i, y + j, serial); + } + } + return powerLevel; + } + + public static void SearchBestRegionOfOneSize(int width, int height, int size, int serial, out int x, out int y) + { + int bestPowerLevel = int.MinValue; + int bestX = 0; + int bestY = 0; + for (int i = 0; i <= width - size; i++) + { + for (int j = 0; j <= height - size; j++) + { + int powerLevel = CalculatePowerLevelOfRegion(i, j, size, serial); + if (powerLevel > bestPowerLevel) { - powerLevel += CalculatePowerLevelOfCell(x + i, y + j, serial); + bestPowerLevel = powerLevel; + bestX = i; + bestY = j; } } - return powerLevel; } + x = bestX; + y = bestY; + } - public static void SearchBestRegionOfOneSize(int width, int height, int size, int serial, out int x, out int y) + public static int[,] GenerateSumationField(int width, int height, int serial) + { + int[,] field = new int[width, height]; + for (int j = 0; j < height; j++) { - int bestPowerLevel = int.MinValue; - int bestX = 0; - int bestY = 0; - for (int i = 0; i <= width - size; i++) + for (int i = 0; i < width; i++) { - for (int j = 0; j <= height - size; j++) + int powerLevel = CalculatePowerLevelOfCell(i, j, serial); + field[i, j] = powerLevel; + } + } + int[,] summationFiled = new int[width, height]; + for (int j = 0; j < height; j++) + { + for (int i = 0; i < width; i++) + { + int sum = field[i, j]; + if (j > 0) { - int powerLevel = CalculatePowerLevelOfRegion(i, j, size, serial); + sum += summationFiled[i, j - 1]; + } + if (i > 0) + { + sum += summationFiled[i - 1, j]; + } + if (i > 0 && j > 0) + { + sum -= summationFiled[i - 1, j - 1]; + } + summationFiled[i, j] = sum; + } + } + return summationFiled; + } + + public static int CalculatePowerLevelOfRegion(int x, int y, int size, int[,] summationFiled) + { + int powerLevel = summationFiled[x + (size - 1), y + (size - 1)]; + if (x > 0 && y > 0) + { + powerLevel += summationFiled[x - 1, y - 1]; + } + if (x > 0) + { + powerLevel -= summationFiled[x - 1, y + (size - 1)]; + } + if (y > 0) + { + powerLevel -= summationFiled[x + (size - 1), y - 1]; + } + return powerLevel; + } + + public static void SearchBestRegion(int width, int height, int serial, out int x, out int y, out int size) + { + int[,] summationFiled = GenerateSumationField(width, height, serial); + int bestPowerLevel = int.MinValue; + int bestX = 0; + int bestY = 0; + int bestSize = 0; + int maxSize = Math.Min(width, height); + for (int k = 1; k <= maxSize; k++) + { + for (int i = 0; i <= width - k; i++) + { + for (int j = 0; j <= height - k; j++) + { + int powerLevel = CalculatePowerLevelOfRegion(i, j, k, summationFiled); if (powerLevel > bestPowerLevel) { bestPowerLevel = powerLevel; bestX = i; bestY = j; + bestSize = k; } } } - x = bestX; - y = bestY; - } - - public static int[,] GenerateSumationField(int width, int height, int serial) - { - int[,] field = new int[width, height]; - for (int j = 0; j < height; j++) - { - for (int i = 0; i < width; i++) - { - int powerLevel = CalculatePowerLevelOfCell(i, j, serial); - field[i, j] = powerLevel; - } - } - int[,] summationFiled = new int[width, height]; - for (int j = 0; j < height; j++) - { - for (int i = 0; i < width; i++) - { - int sum = field[i, j]; - if (j > 0) - { - sum += summationFiled[i, j - 1]; - } - if (i > 0) - { - sum += summationFiled[i - 1, j]; - } - if (i > 0 && j > 0) - { - sum -= summationFiled[i - 1, j - 1]; - } - summationFiled[i, j] = sum; - } - } - return summationFiled; - } - - public static int CalculatePowerLevelOfRegion(int x, int y, int size, int[,] summationFiled) - { - int powerLevel = summationFiled[x + (size - 1), y + (size - 1)]; - if (x > 0 && y > 0) - { - powerLevel += summationFiled[x - 1, y - 1]; - } - if (x > 0) - { - powerLevel -= summationFiled[x - 1, y + (size - 1)]; - } - if (y > 0) - { - powerLevel -= summationFiled[x + (size - 1), y - 1]; - } - return powerLevel; - } - - public static void SearchBestRegion(int width, int height, int serial, out int x, out int y, out int size) - { - int[,] summationFiled = GenerateSumationField(width, height, serial); - int bestPowerLevel = int.MinValue; - int bestX = 0; - int bestY = 0; - int bestSize = 0; - int maxSize = Math.Min(width, height); - for (int k = 1; k <= maxSize; k++) - { - for (int i = 0; i <= width - k; i++) - { - for (int j = 0; j <= height - k; j++) - { - int powerLevel = CalculatePowerLevelOfRegion(i, j, k, summationFiled); - if (powerLevel > bestPowerLevel) - { - bestPowerLevel = powerLevel; - bestX = i; - bestY = j; - bestSize = k; - } - } - } - } - x = bestX; - y = bestY; - size = bestSize; } + x = bestX; + y = bestY; + size = bestSize; } -} +} \ No newline at end of file diff --git a/AdventOfCode2018/Day12.cs b/AdventOfCode2018/Day12.cs index 606c707..4b1e32b 100644 --- a/AdventOfCode2018/Day12.cs +++ b/AdventOfCode2018/Day12.cs @@ -1,283 +1,281 @@ using System; using System.Collections.Generic; -namespace AdventOfCode2018 +namespace AdventOfCode2018; +/* +--- Day 12: Subterranean Sustainability --- + +The year 518 is significantly more underground than your history books implied. Either that, or you've arrived in a vast cavern network under the North Pole. + +After exploring a little, you discover a long tunnel that contains a row of small pots as far as you can see to your left and right. A few of them contain plants - someone is trying to grow things in these geothermally-heated caves. + +The pots are numbered, with 0 in front of you. To the left, the pots are numbered -1, -2, -3, and so on; to the right, 1, 2, 3.... Your puzzle input contains a list of pots from 0 to the right and whether they do (#) or do not (.) currently contain a plant, the initial state. (No other pots currently contain plants.) For example, an initial state of #..##.... indicates that pots 0, 3, and 4 currently contain plants. + +Your puzzle input also contains some notes you find on a nearby table: someone has been trying to figure out how these plants spread to nearby pots. Based on the notes, for each generation of plants, a given pot has or does not have a plant based on whether that pot (and the two pots on either side of it) had a plant in the last generation. These are written as LLCRR => N, where L are pots to the left, C is the current pot being considered, R are the pots to the right, and N is whether the current pot will have a plant in the next generation. For example: + + A note like ..#.. => . means that a pot that contains a plant but with no plants within two pots of it will not have a plant in it during the next generation. + A note like ##.## => . means that an empty pot with two plants on each side of it will remain empty in the next generation. + A note like .##.# => # means that a pot has a plant in a given generation if, in the previous generation, there were plants in that pot, the one immediately to the left, and the one two pots to the right, but not in the ones immediately to the right and two to the left. + +It's not clear what these plants are for, but you're sure it's important, so you'd like to make sure the current configuration of plants is sustainable by determining what will happen after 20 generations. + +For example, given the following input: + +initial state: #..#.#..##......###...### + +...## => # +..#.. => # +.#... => # +.#.#. => # +.#.## => # +.##.. => # +.#### => # +#.#.# => # +#.### => # +##.#. => # +##.## => # +###.. => # +###.# => # +####. => # + +For brevity, in this example, only the combinations which do produce a plant are listed. (Your input includes all possible combinations.) Then, the next 20 generations will look like this: + + 1 2 3 + 0 0 0 0 + 0: ...#..#.#..##......###...###........... + 1: ...#...#....#.....#..#..#..#........... + 2: ...##..##...##....#..#..#..##.......... + 3: ..#.#...#..#.#....#..#..#...#.......... + 4: ...#.#..#...#.#...#..#..##..##......... + 5: ....#...##...#.#..#..#...#...#......... + 6: ....##.#.#....#...#..##..##..##........ + 7: ...#..###.#...##..#...#...#...#........ + 8: ...#....##.#.#.#..##..##..##..##....... + 9: ...##..#..#####....#...#...#...#....... +10: ..#.#..#...#.##....##..##..##..##...... +11: ...#...##...#.#...#.#...#...#...#...... +12: ...##.#.#....#.#...#.#..##..##..##..... +13: ..#..###.#....#.#...#....#...#...#..... +14: ..#....##.#....#.#..##...##..##..##.... +15: ..##..#..#.#....#....#..#.#...#...#.... +16: .#.#..#...#.#...##...#...#.#..##..##... +17: ..#...##...#.#.#.#...##...#....#...#... +18: ..##.#.#....#####.#.#.#...##...##..##.. +19: .#..###.#..#.#.#######.#.#.#..#.#...#.. +20: .#....##....#####...#######....#.#..##. + +The generation is shown along the left, where 0 is the initial state. The pot numbers are shown along the top, where 0 labels the center pot, negative-numbered pots extend to the left, and positive pots extend toward the right. Remember, the initial state begins at pot 0, which is not the leftmost pot used in this example. + +After one generation, only seven plants remain. The one in pot 0 matched the rule looking for ..#.., the one in pot 4 matched the rule looking for .#.#., pot 9 matched .##.., and so on. + +In this example, after 20 generations, the pots shown as # contain plants, the furthest left of which is pot -2, and the furthest right of which is pot 34. Adding up all the numbers of plant-containing pots after the 20th generation produces 325. + +After 20 generations, what is the sum of the numbers of all pots which contain a plant? + +--- Part Two --- + +You realize that 20 generations aren't enough. After all, these plants will need to last another 1500 years to even reach your timeline, not to mention your future. + +After fifty billion (50000000000) generations, what is the sum of the numbers of all pots which contain a plant? + +*/ + +public class Day12 : IDay { - /* - --- Day 12: Subterranean Sustainability --- - - The year 518 is significantly more underground than your history books implied. Either that, or you've arrived in a vast cavern network under the North Pole. - - After exploring a little, you discover a long tunnel that contains a row of small pots as far as you can see to your left and right. A few of them contain plants - someone is trying to grow things in these geothermally-heated caves. - - The pots are numbered, with 0 in front of you. To the left, the pots are numbered -1, -2, -3, and so on; to the right, 1, 2, 3.... Your puzzle input contains a list of pots from 0 to the right and whether they do (#) or do not (.) currently contain a plant, the initial state. (No other pots currently contain plants.) For example, an initial state of #..##.... indicates that pots 0, 3, and 4 currently contain plants. - - Your puzzle input also contains some notes you find on a nearby table: someone has been trying to figure out how these plants spread to nearby pots. Based on the notes, for each generation of plants, a given pot has or does not have a plant based on whether that pot (and the two pots on either side of it) had a plant in the last generation. These are written as LLCRR => N, where L are pots to the left, C is the current pot being considered, R are the pots to the right, and N is whether the current pot will have a plant in the next generation. For example: - - A note like ..#.. => . means that a pot that contains a plant but with no plants within two pots of it will not have a plant in it during the next generation. - A note like ##.## => . means that an empty pot with two plants on each side of it will remain empty in the next generation. - A note like .##.# => # means that a pot has a plant in a given generation if, in the previous generation, there were plants in that pot, the one immediately to the left, and the one two pots to the right, but not in the ones immediately to the right and two to the left. - - It's not clear what these plants are for, but you're sure it's important, so you'd like to make sure the current configuration of plants is sustainable by determining what will happen after 20 generations. - - For example, given the following input: - - initial state: #..#.#..##......###...### - - ...## => # - ..#.. => # - .#... => # - .#.#. => # - .#.## => # - .##.. => # - .#### => # - #.#.# => # - #.### => # - ##.#. => # - ##.## => # - ###.. => # - ###.# => # - ####. => # - - For brevity, in this example, only the combinations which do produce a plant are listed. (Your input includes all possible combinations.) Then, the next 20 generations will look like this: - - 1 2 3 - 0 0 0 0 - 0: ...#..#.#..##......###...###........... - 1: ...#...#....#.....#..#..#..#........... - 2: ...##..##...##....#..#..#..##.......... - 3: ..#.#...#..#.#....#..#..#...#.......... - 4: ...#.#..#...#.#...#..#..##..##......... - 5: ....#...##...#.#..#..#...#...#......... - 6: ....##.#.#....#...#..##..##..##........ - 7: ...#..###.#...##..#...#...#...#........ - 8: ...#....##.#.#.#..##..##..##..##....... - 9: ...##..#..#####....#...#...#...#....... - 10: ..#.#..#...#.##....##..##..##..##...... - 11: ...#...##...#.#...#.#...#...#...#...... - 12: ...##.#.#....#.#...#.#..##..##..##..... - 13: ..#..###.#....#.#...#....#...#...#..... - 14: ..#....##.#....#.#..##...##..##..##.... - 15: ..##..#..#.#....#....#..#.#...#...#.... - 16: .#.#..#...#.#...##...#...#.#..##..##... - 17: ..#...##...#.#.#.#...##...#....#...#... - 18: ..##.#.#....#####.#.#.#...##...##..##.. - 19: .#..###.#..#.#.#######.#.#.#..#.#...#.. - 20: .#....##....#####...#######....#.#..##. - - The generation is shown along the left, where 0 is the initial state. The pot numbers are shown along the top, where 0 labels the center pot, negative-numbered pots extend to the left, and positive pots extend toward the right. Remember, the initial state begins at pot 0, which is not the leftmost pot used in this example. - - After one generation, only seven plants remain. The one in pot 0 matched the rule looking for ..#.., the one in pot 4 matched the rule looking for .#.#., pot 9 matched .##.., and so on. - - In this example, after 20 generations, the pots shown as # contain plants, the furthest left of which is pot -2, and the furthest right of which is pot 34. Adding up all the numbers of plant-containing pots after the 20th generation produces 325. - - After 20 generations, what is the sum of the numbers of all pots which contain a plant? - - --- Part Two --- - - You realize that 20 generations aren't enough. After all, these plants will need to last another 1500 years to even reach your timeline, not to mention your future. - - After fifty billion (50000000000) generations, what is the sum of the numbers of all pots which contain a plant? - - */ - - public class Day12 : IDay + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) + Initialize(inputs); + Simulate(20, true); + return CalculateChecksum().ToString(); + } + + public string ResolvePart2(string[] inputs) + { + Initialize(inputs); + Simulate(500); + _offsetField -= (50000000000L - 500); + return CalculateChecksum().ToString(); + } + + private class PlantRule + { + public bool Minus2 { get; set; } + public bool Minus1 { get; set; } + public bool Current { get; set; } + public bool Plus1 { get; set; } + public bool Plus2 { get; set; } + + public bool Result { get; set; } + } + + private const int SideMargin = 5; + private const int SideProcessMargin = 2; + + private List _initialState = new(); + private List _rules = new(); + private long _offsetField; + private bool[] _field; + private bool[] _workField; + + private void Initialize(string[] inputs) + { + _initialState.Clear(); + foreach (char c in inputs[0].Substring("initial state: ".Length)) { - Initialize(inputs); - Simulate(20, true); - return CalculateChecksum().ToString(); + _initialState.Add(c == '#'); } - public string ResolvePart2(string[] inputs) + _rules.Clear(); + for (int i = 2; i < inputs.Length; i++) { - Initialize(inputs); - Simulate(500, false); - _offsetField -= (50000000000L - 500); - return CalculateChecksum().ToString(); + if (string.IsNullOrEmpty(inputs[i])) { continue; } + string[] parts = inputs[i].Split(new[] { " => " }, StringSplitOptions.RemoveEmptyEntries); + _rules.Add(new PlantRule + { + Minus2 = (parts[0][0] == '#'), + Minus1 = (parts[0][1] == '#'), + Current = (parts[0][2] == '#'), + Plus1 = (parts[0][3] == '#'), + Plus2 = (parts[0][4] == '#'), + + Result = (parts[1][0] == '#'), + }); } - private class PlantRule + int maxSize = (SideMargin * 2) + _initialState.Count; + _offsetField = SideMargin; + _field = new bool[maxSize]; + _workField = new bool[maxSize]; + for (int i = 0; i < _initialState.Count; i++) { - public bool Minus2 { get; set; } - public bool Minus1 { get; set; } - public bool Current { get; set; } - public bool Plus1 { get; set; } - public bool Plus2 { get; set; } - - public bool Result { get; set; } + _field[i + _offsetField] = _initialState[i]; } + } - private const int SideMargin = 5; - private const int SideProcessMargin = 2; + private void SwapFields() + { + bool[] aux = _field; + _field = _workField; + _workField = aux; + } - private List _initialState = new List(); - private List _rules = new List(); - private long _offsetField = 0; - private bool[] _field; - private bool[] _workField; - - private void Initialize(string[] inputs) + private void RecenterField() + { + long leftSpace = 0; + long rightSpace = 0; + for (long i = 0; i < _field.Length; i++) { - _initialState.Clear(); - foreach (char c in inputs[0].Substring("initial state: ".Length)) - { - _initialState.Add(c == '#'); - } - - _rules.Clear(); - for (int i = 2; i < inputs.Length; i++) - { - if (string.IsNullOrEmpty(inputs[i])) { continue; } - string[] parts = inputs[i].Split(new string[] { " => " }, StringSplitOptions.RemoveEmptyEntries); - _rules.Add(new PlantRule - { - Minus2 = (parts[0][0] == '#'), - Minus1 = (parts[0][1] == '#'), - Current = (parts[0][2] == '#'), - Plus1 = (parts[0][3] == '#'), - Plus2 = (parts[0][4] == '#'), - - Result = (parts[1][0] == '#'), - }); - } - - int maxSize = (SideMargin * 2) + _initialState.Count; - _offsetField = SideMargin; - _field = new bool[maxSize]; - _workField = new bool[maxSize]; - for (int i = 0; i < _initialState.Count; i++) - { - _field[i + _offsetField] = _initialState[i]; - } + if (_field[i]) { break; } + leftSpace++; } - - private void SwapFields() + for (long i = _field.Length - 1; i >= 0; i--) { - bool[] aux = _field; - _field = _workField; - _workField = aux; + if (_field[i]) { break; } + rightSpace++; } + if (leftSpace == SideMargin && rightSpace == SideMargin) { return; } - private void RecenterField() + long oldSize = _field.Length; + long newSize = oldSize + (SideMargin - leftSpace) + (SideMargin - rightSpace); + long diffOffset = SideMargin - leftSpace; + if (oldSize == newSize && diffOffset != 0) { - long leftSpace = 0; - long rightSpace = 0; - for (long i = 0; i < _field.Length; i++) + if (diffOffset > 0) { - if (_field[i]) { break; } - leftSpace++; - } - for (long i = _field.Length - 1; i >= 0; i--) - { - if (_field[i]) { break; } - rightSpace++; - } - if (leftSpace == SideMargin && rightSpace == SideMargin) { return; } - - long oldSize = _field.Length; - long newSize = oldSize + (SideMargin - leftSpace) + (SideMargin - rightSpace); - long diffOffset = SideMargin - leftSpace; - if (oldSize == newSize && diffOffset != 0) - { - if (diffOffset > 0) - { - for (long i = 0; i < diffOffset; i++) { _workField[i] = false; } - } - else - { - for (long i = 0; i < Math.Abs(diffOffset); i++) { _workField[(_workField.Length - 1) - i] = false; } - } - for (long i = 0; i < newSize; i++) - { - long i2 = i - diffOffset; - if (i2 < 0 || i2 >= oldSize) { continue; } - _workField[i] = _field[i2]; - } - SwapFields(); + for (long i = 0; i < diffOffset; i++) { _workField[i] = false; } } else { - bool[] tempField = new bool[newSize]; - for (long i = 0; i < newSize; i++) - { - long i2 = i - diffOffset; - if (i2 < 0 || i2 >= oldSize) { continue; } - tempField[i] = _field[i2]; - } - _field = tempField; - _workField = new bool[newSize]; + for (long i = 0; i < Math.Abs(diffOffset); i++) { _workField[(_workField.Length - 1) - i] = false; } } - _offsetField += diffOffset; - } - - private void ShowField(long nGeneration) - { - Console.Write("({0:000}) [{1}]: ", nGeneration, _offsetField); - foreach (bool plant in _field) + for (long i = 0; i < newSize; i++) { - Console.Write(plant ? "#" : "."); + long i2 = i - diffOffset; + if (i2 < 0 || i2 >= oldSize) { continue; } + _workField[i] = _field[i2]; } - Console.WriteLine(); + SwapFields(); } - - private static void SimulateGeneration(List rules, bool[] field, bool[] finalField) + else { - for (long i = SideProcessMargin; i < (field.Length - SideProcessMargin); i++) + bool[] tempField = new bool[newSize]; + for (long i = 0; i < newSize; i++) { - bool minus2 = field[i - 2]; - bool minus1 = field[i - 1]; - bool current = field[i]; - bool plus1 = field[i + 1]; - bool plus2 = field[i + 2]; - - bool result = false; - foreach (PlantRule rule in rules) - { - if ( - rule.Minus2 == minus2 && - rule.Minus1 == minus1 && - rule.Current == current && - rule.Plus1 == plus1 && - rule.Plus2 == plus2 && - true - ) - { - result = rule.Result; - break; - } - } - finalField[i] = result; + long i2 = i - diffOffset; + if (i2 < 0 || i2 >= oldSize) { continue; } + tempField[i] = _field[i2]; } + _field = tempField; + _workField = new bool[newSize]; } + _offsetField += diffOffset; + } - private void Simulate(long nGenerations, bool showEvolution = false) + private void ShowField(long nGeneration) + { + Console.Write("({0:000}) [{1}]: ", nGeneration, _offsetField); + foreach (bool plant in _field) { - for (int i = 0; i < nGenerations; i++) - { - RecenterField(); - if (showEvolution) - { - ShowField(i); - } - SimulateGeneration(_rules, _field, _workField); - SwapFields(); - } - ShowField(nGenerations); + Console.Write(plant ? "#" : "."); } + Console.WriteLine(); + } - private long CalculateChecksum() + private static void SimulateGeneration(List rules, bool[] field, bool[] finalField) + { + for (long i = SideProcessMargin; i < (field.Length - SideProcessMargin); i++) { - long sum = 0; - for (long i = 0; i < _field.Length; i++) + bool minus2 = field[i - 2]; + bool minus1 = field[i - 1]; + bool current = field[i]; + bool plus1 = field[i + 1]; + bool plus2 = field[i + 2]; + + bool result = false; + foreach (PlantRule rule in rules) { - if (_field[i]) + if ( + rule.Minus2 == minus2 && + rule.Minus1 == minus1 && + rule.Current == current && + rule.Plus1 == plus1 && + rule.Plus2 == plus2 && + true + ) { - sum += (i - _offsetField); + result = rule.Result; + break; } } - return sum; + finalField[i] = result; } } -} + + private void Simulate(long nGenerations, bool showEvolution = false) + { + for (int i = 0; i < nGenerations; i++) + { + RecenterField(); + if (showEvolution) + { + ShowField(i); + } + SimulateGeneration(_rules, _field, _workField); + SwapFields(); + } + ShowField(nGenerations); + } + + private long CalculateChecksum() + { + long sum = 0; + for (long i = 0; i < _field.Length; i++) + { + if (_field[i]) + { + sum += (i - _offsetField); + } + } + return sum; + } +} \ No newline at end of file diff --git a/AdventOfCode2018/Day13.cs b/AdventOfCode2018/Day13.cs index 5dddd58..10507b1 100644 --- a/AdventOfCode2018/Day13.cs +++ b/AdventOfCode2018/Day13.cs @@ -2,310 +2,330 @@ using System.Collections.Generic; using System.Linq; -namespace AdventOfCode2018 +namespace AdventOfCode2018; +/* + +--- Day 13: Mine Cart Madness --- + +A crop of this size requires significant logistics to transport produce, soil, fertilizer, and so on. The Elves are very busy pushing things around in carts on some kind of rudimentary system of tracks they've come up with. + +Seeing as how cart-and-track systems don't appear in recorded history for another 1000 years, the Elves seem to be making this up as they go along. They haven't even figured out how to avoid collisions yet. + +You map out the tracks (your puzzle input) and see where you can help. + +Tracks consist of straight paths (| and -), curves (/ and \), and intersections (+). Curves connect exactly two perpendicular pieces of track; for example, this is a closed loop: + +/----\ +| | +| | +\----/ + +Intersections occur when two perpendicular paths cross. At an intersection, a cart is capable of turning left, turning right, or continuing straight. Here are two loops connected by two intersections: + +/-----\ +| | +| /--+--\ +| | | | +\--+--/ | + | | + \-----/ + +Several carts are also on the tracks. Carts always face either up (^), down (v), left (<), or right (>). (On your initial map, the track under each cart is a straight path matching the direction the cart is facing.) + +Each time a cart has the option to turn (by arriving at any intersection), it turns left the first time, goes straight the second time, turns right the third time, and then repeats those directions starting again with left the fourth time, straight the fifth time, and so on. This process is independent of the particular intersection at which the cart has arrived - that is, the cart has no per-intersection memory. + +Carts all move at the same speed; they take turns moving a single step at a time. They do this based on their current location: carts on the top row move first (acting from left to right), then carts on the second row move (again from left to right), then carts on the third row, and so on. Once each cart has moved one step, the process repeats; each of these loops is called a tick. + +For example, suppose there are two carts on a straight track: + +| | | | | +v | | | | +| v v | | +| | | v X +| | ^ ^ | +^ ^ | | | +| | | | | + +First, the top cart moves. It is facing down (v), so it moves down one square. Second, the bottom cart moves. It is facing up (^), so it moves up one square. Because all carts have moved, the first tick ends. Then, the process repeats, starting with the first cart. The first cart moves down, then the second cart moves up - right into the first cart, colliding with it! (The location of the crash is marked with an X.) This ends the second and last tick. + +Here is a longer example: + +/->-\ +| | /----\ +| /-+--+-\ | +| | | | v | +\-+-/ \-+--/ + \------/ + +/-->\ +| | /----\ +| /-+--+-\ | +| | | | | | +\-+-/ \->--/ + \------/ + +/---v +| | /----\ +| /-+--+-\ | +| | | | | | +\-+-/ \-+>-/ + \------/ + +/---\ +| v /----\ +| /-+--+-\ | +| | | | | | +\-+-/ \-+->/ + \------/ + +/---\ +| | /----\ +| /->--+-\ | +| | | | | | +\-+-/ \-+--^ + \------/ + +/---\ +| | /----\ +| /-+>-+-\ | +| | | | | ^ +\-+-/ \-+--/ + \------/ + +/---\ +| | /----\ +| /-+->+-\ ^ +| | | | | | +\-+-/ \-+--/ + \------/ + +/---\ +| | /----< +| /-+-->-\ | +| | | | | | +\-+-/ \-+--/ + \------/ + +/---\ +| | /---<\ +| /-+--+>\ | +| | | | | | +\-+-/ \-+--/ + \------/ + +/---\ +| | /--<-\ +| /-+--+-v | +| | | | | | +\-+-/ \-+--/ + \------/ + +/---\ +| | /-<--\ +| /-+--+-\ | +| | | | v | +\-+-/ \-+--/ + \------/ + +/---\ +| | /<---\ +| /-+--+-\ | +| | | | | | +\-+-/ \-<--/ + \------/ + +/---\ +| | v----\ +| /-+--+-\ | +| | | | | | +\-+-/ \<+--/ + \------/ + +/---\ +| | /----\ +| /-+--v-\ | +| | | | | | +\-+-/ ^-+--/ + \------/ + +/---\ +| | /----\ +| /-+--+-\ | +| | | X | | +\-+-/ \-+--/ + \------/ + +After following their respective paths for a while, the carts eventually crash. To help prevent crashes, you'd like to know the location of the first crash. Locations are given in X,Y coordinates, where the furthest left column is X=0 and the furthest top row is Y=0: + + 111 + 0123456789012 +0/---\ +1| | /----\ +2| /-+--+-\ | +3| | | X | | +4\-+-/ \-+--/ +5 \------/ + +In this example, the location of the first crash is 7,3. + +--- Part Two --- + +There isn't much you can do to prevent crashes in this ridiculous system. However, by predicting the crashes, the Elves know where to be in advance and instantly remove the two crashing carts the moment any crash occurs. + +They can proceed like this for a while, but eventually, they're going to run out of carts. It could be useful to figure out where the last cart that hasn't crashed will end up. + +For example: + +/>-<\ +| | +| /<+-\ +| | | v +\>+/ + +/---\ +| | +| v-+-\ +| | | | +\-+-/ | + | | + ^---^ + +/---\ +| | +| /-+-\ +| v | | +\-+-/ | + ^ ^ + \---/ + +/---\ +| | +| /-+-\ +| | | | +\-+-/ ^ + | | + \---/ + +After four very expensive crashes, a tick ends with only one cart remaining; its final location is 6,4. + +What is the location of the last cart at the end of the first tick where it is the only cart left? + +*/ + +public class Day13 : IDay { - /* + private bool ShowProgress { get; set; } = false; - --- Day 13: Mine Cart Madness --- - - A crop of this size requires significant logistics to transport produce, soil, fertilizer, and so on. The Elves are very busy pushing things around in carts on some kind of rudimentary system of tracks they've come up with. - - Seeing as how cart-and-track systems don't appear in recorded history for another 1000 years, the Elves seem to be making this up as they go along. They haven't even figured out how to avoid collisions yet. - - You map out the tracks (your puzzle input) and see where you can help. - - Tracks consist of straight paths (| and -), curves (/ and \), and intersections (+). Curves connect exactly two perpendicular pieces of track; for example, this is a closed loop: - - /----\ - | | - | | - \----/ - - Intersections occur when two perpendicular paths cross. At an intersection, a cart is capable of turning left, turning right, or continuing straight. Here are two loops connected by two intersections: - - /-----\ - | | - | /--+--\ - | | | | - \--+--/ | - | | - \-----/ - - Several carts are also on the tracks. Carts always face either up (^), down (v), left (<), or right (>). (On your initial map, the track under each cart is a straight path matching the direction the cart is facing.) - - Each time a cart has the option to turn (by arriving at any intersection), it turns left the first time, goes straight the second time, turns right the third time, and then repeats those directions starting again with left the fourth time, straight the fifth time, and so on. This process is independent of the particular intersection at which the cart has arrived - that is, the cart has no per-intersection memory. - - Carts all move at the same speed; they take turns moving a single step at a time. They do this based on their current location: carts on the top row move first (acting from left to right), then carts on the second row move (again from left to right), then carts on the third row, and so on. Once each cart has moved one step, the process repeats; each of these loops is called a tick. - - For example, suppose there are two carts on a straight track: - - | | | | | - v | | | | - | v v | | - | | | v X - | | ^ ^ | - ^ ^ | | | - | | | | | - - First, the top cart moves. It is facing down (v), so it moves down one square. Second, the bottom cart moves. It is facing up (^), so it moves up one square. Because all carts have moved, the first tick ends. Then, the process repeats, starting with the first cart. The first cart moves down, then the second cart moves up - right into the first cart, colliding with it! (The location of the crash is marked with an X.) This ends the second and last tick. - - Here is a longer example: - - /->-\ - | | /----\ - | /-+--+-\ | - | | | | v | - \-+-/ \-+--/ - \------/ - - /-->\ - | | /----\ - | /-+--+-\ | - | | | | | | - \-+-/ \->--/ - \------/ - - /---v - | | /----\ - | /-+--+-\ | - | | | | | | - \-+-/ \-+>-/ - \------/ - - /---\ - | v /----\ - | /-+--+-\ | - | | | | | | - \-+-/ \-+->/ - \------/ - - /---\ - | | /----\ - | /->--+-\ | - | | | | | | - \-+-/ \-+--^ - \------/ - - /---\ - | | /----\ - | /-+>-+-\ | - | | | | | ^ - \-+-/ \-+--/ - \------/ - - /---\ - | | /----\ - | /-+->+-\ ^ - | | | | | | - \-+-/ \-+--/ - \------/ - - /---\ - | | /----< - | /-+-->-\ | - | | | | | | - \-+-/ \-+--/ - \------/ - - /---\ - | | /---<\ - | /-+--+>\ | - | | | | | | - \-+-/ \-+--/ - \------/ - - /---\ - | | /--<-\ - | /-+--+-v | - | | | | | | - \-+-/ \-+--/ - \------/ - - /---\ - | | /-<--\ - | /-+--+-\ | - | | | | v | - \-+-/ \-+--/ - \------/ - - /---\ - | | /<---\ - | /-+--+-\ | - | | | | | | - \-+-/ \-<--/ - \------/ - - /---\ - | | v----\ - | /-+--+-\ | - | | | | | | - \-+-/ \<+--/ - \------/ - - /---\ - | | /----\ - | /-+--v-\ | - | | | | | | - \-+-/ ^-+--/ - \------/ - - /---\ - | | /----\ - | /-+--+-\ | - | | | X | | - \-+-/ \-+--/ - \------/ - - After following their respective paths for a while, the carts eventually crash. To help prevent crashes, you'd like to know the location of the first crash. Locations are given in X,Y coordinates, where the furthest left column is X=0 and the furthest top row is Y=0: - - 111 - 0123456789012 - 0/---\ - 1| | /----\ - 2| /-+--+-\ | - 3| | | X | | - 4\-+-/ \-+--/ - 5 \------/ - - In this example, the location of the first crash is 7,3. - - --- Part Two --- - - There isn't much you can do to prevent crashes in this ridiculous system. However, by predicting the crashes, the Elves know where to be in advance and instantly remove the two crashing carts the moment any crash occurs. - - They can proceed like this for a while, but eventually, they're going to run out of carts. It could be useful to figure out where the last cart that hasn't crashed will end up. - - For example: - - />-<\ - | | - | /<+-\ - | | | v - \>+/ - - /---\ - | | - | v-+-\ - | | | | - \-+-/ | - | | - ^---^ - - /---\ - | | - | /-+-\ - | v | | - \-+-/ | - ^ ^ - \---/ - - /---\ - | | - | /-+-\ - | | | | - \-+-/ ^ - | | - \---/ - - After four very expensive crashes, a tick ends with only one cart remaining; its final location is 6,4. - - What is the location of the last cart at the end of the first tick where it is the only cart left? - - */ - - public class Day13 : IDay + public string ResolvePart1(string[] inputs) { - private bool ShowProgress { get; set; } = false; - - public string ResolvePart1(string[] inputs) + Initialize(inputs); + Train collidingTrain; + do { - Initialize(inputs); - Train colidingTrain = null; - do + if (ShowProgress) { ShowGrid(); } + collidingTrain = SimulateForFirstCollision(); + } while (collidingTrain == null); + return $"{collidingTrain.X},{collidingTrain.Y}"; + } + + public string ResolvePart2(string[] inputs) + { + Initialize(inputs); + Train lastCart; + do + { + if (ShowProgress) { ShowGrid(); } + lastCart = SimulateForLastCart(); + } while (lastCart == null); + return $"{lastCart.X},{lastCart.Y}"; + } + + private enum TrainDirection + { + North, + South, + East, + West, + } + + private enum TrainTurning + { + Left, + Right, + None, + } + + private class Train + { + public int X { get; set; } + public int Y { get; set; } + + public TrainDirection Direction { get; set; } + public TrainTurning NextIntersectionTurn { get; set; } + + public void Simulate(char[,] grid) + { + if (Direction == TrainDirection.North) { - if (ShowProgress) { ShowGrid(); } - colidingTrain = SimulateForFirstCollision(); - } while (colidingTrain == null); - return string.Format("{0},{1}", colidingTrain.X, colidingTrain.Y); - } - - public string ResolvePart2(string[] inputs) - { - Initialize(inputs); - Train lastCart = null; - do + Y--; + } + if (Direction == TrainDirection.South) { - if (ShowProgress) { ShowGrid(); } - lastCart = SimulateForLastCart(); - } while (lastCart == null); - return string.Format("{0},{1}", lastCart.X, lastCart.Y); - } + Y++; + } + if (Direction == TrainDirection.East) + { + X++; + } + if (Direction == TrainDirection.West) + { + X--; + } - private enum TrainDirection - { - North, - South, - East, - West, - }; - - private enum TrainTurning - { - Left, - Right, - None, - } - - private class Train - { - public int X { get; set; } - public int Y { get; set; } - - public TrainDirection Direction { get; set; } - public TrainTurning NextIntersectionTurn { get; set; } - - public void Simulate(char[,] grid) + char cell = grid[X, Y]; + if (cell == '/') { if (Direction == TrainDirection.North) { - Y--; + Direction = TrainDirection.East; } - if (Direction == TrainDirection.South) + else if (Direction == TrainDirection.South) { - Y++; + Direction = TrainDirection.West; } - if (Direction == TrainDirection.East) + else if (Direction == TrainDirection.East) { - X++; + Direction = TrainDirection.North; } - if (Direction == TrainDirection.West) + else if (Direction == TrainDirection.West) { - X--; + Direction = TrainDirection.South; } - - char cell = grid[X, Y]; - if (cell == '/') + } + if (cell == '\\') + { + if (Direction == TrainDirection.North) { - if (Direction == TrainDirection.North) - { - Direction = TrainDirection.East; - } - else if (Direction == TrainDirection.South) - { - Direction = TrainDirection.West; - } - else if (Direction == TrainDirection.East) - { - Direction = TrainDirection.North; - } - else if (Direction == TrainDirection.West) - { - Direction = TrainDirection.South; - } + Direction = TrainDirection.West; } - if (cell == '\\') + else if (Direction == TrainDirection.South) + { + Direction = TrainDirection.East; + } + else if (Direction == TrainDirection.East) + { + Direction = TrainDirection.South; + } + else if (Direction == TrainDirection.West) + { + Direction = TrainDirection.North; + } + } + if (cell == '+') + { + if (NextIntersectionTurn == TrainTurning.Left) { if (Direction == TrainDirection.North) { @@ -316,6 +336,30 @@ namespace AdventOfCode2018 Direction = TrainDirection.East; } else if (Direction == TrainDirection.East) + { + Direction = TrainDirection.North; + } + else if (Direction == TrainDirection.West) + { + Direction = TrainDirection.South; + } + NextIntersectionTurn = TrainTurning.None; + } + else if (NextIntersectionTurn == TrainTurning.None) + { + NextIntersectionTurn = TrainTurning.Right; + } + else if (NextIntersectionTurn == TrainTurning.Right) + { + if (Direction == TrainDirection.North) + { + Direction = TrainDirection.East; + } + else if (Direction == TrainDirection.South) + { + Direction = TrainDirection.West; + } + else if (Direction == TrainDirection.East) { Direction = TrainDirection.South; } @@ -323,190 +367,144 @@ namespace AdventOfCode2018 { Direction = TrainDirection.North; } - } - if (cell == '+') - { - if (NextIntersectionTurn == TrainTurning.Left) - { - if (Direction == TrainDirection.North) - { - Direction = TrainDirection.West; - } - else if (Direction == TrainDirection.South) - { - Direction = TrainDirection.East; - } - else if (Direction == TrainDirection.East) - { - Direction = TrainDirection.North; - } - else if (Direction == TrainDirection.West) - { - Direction = TrainDirection.South; - } - NextIntersectionTurn = TrainTurning.None; - } - else if (NextIntersectionTurn == TrainTurning.None) - { - NextIntersectionTurn = TrainTurning.Right; - } - else if (NextIntersectionTurn == TrainTurning.Right) - { - if (Direction == TrainDirection.North) - { - Direction = TrainDirection.East; - } - else if (Direction == TrainDirection.South) - { - Direction = TrainDirection.West; - } - else if (Direction == TrainDirection.East) - { - Direction = TrainDirection.South; - } - else if (Direction == TrainDirection.West) - { - Direction = TrainDirection.North; - } - NextIntersectionTurn = TrainTurning.Left; - } + NextIntersectionTurn = TrainTurning.Left; } } } - - private int _width; - private int _height; - private char[,] _grid = null; - private List _trains = new List(); - - private void Initialize(string[] inputs) - { - _width = inputs.Max(s => s.Length); - _height = inputs.Length; - _grid = new char[_width, _height]; - _trains.Clear(); - for (int j = 0; j < inputs.Length; j++) - { - for (int i = 0; i < inputs[j].Length; i++) - { - char cell = inputs[j][i]; - if (cell == '^') - { - _trains.Add(new Train - { - X = i, - Y = j, - Direction = TrainDirection.North, - NextIntersectionTurn = TrainTurning.Left, - }); - cell = '|'; - } - if (cell == 'v') - { - _trains.Add(new Train - { - X = i, - Y = j, - Direction = TrainDirection.South, - NextIntersectionTurn = TrainTurning.Left, - }); - cell = '|'; - } - if (cell == '<') - { - _trains.Add(new Train - { - X = i, - Y = j, - Direction = TrainDirection.West, - NextIntersectionTurn = TrainTurning.Left, - }); - cell = '-'; - } - if (cell == '>') - { - _trains.Add(new Train - { - X = i, - Y = j, - Direction = TrainDirection.East, - NextIntersectionTurn = TrainTurning.Left, - }); - cell = '-'; - } - _grid[i, j] = cell; - } - } - } - - private Train SimulateForFirstCollision() - { - Train collidingTrain = null; - IEnumerable orderedTrains = _trains.OrderBy(t => t.X + (t.Y * _width)); - foreach (Train t in orderedTrains) - { - t.Simulate(_grid); - collidingTrain = _trains.FirstOrDefault(x => x.X == t.X && x.Y == t.Y && t != x); - if (collidingTrain != null) { break; } - } - return collidingTrain; - } - - private Train SimulateForLastCart() - { - List orderedTrains = _trains.OrderBy(t => t.X + (t.Y * _width)).ToList(); - foreach (Train t in orderedTrains) - { - t.Simulate(_grid); - Train collidingTrain = _trains.FirstOrDefault(x => x.X == t.X && x.Y == t.Y && t != x); - if (collidingTrain != null) - { - _trains.Remove(t); - _trains.Remove(collidingTrain); - } - } - if (_trains.Count == 1) - { - return _trains[0]; - } - return null; - } - - private void ShowGrid() - { - Console.WriteLine(); - for (int j = 0; j < _height; j++) - { - for (int i = 0; i < _width; i++) - { - Train t = _trains.FirstOrDefault(x => x.X == i && x.Y == j); - if (t != null) - { - if (t.Direction == TrainDirection.North) - { - Console.Write("^"); - } - if (t.Direction == TrainDirection.East) - { - Console.Write(">"); - } - if (t.Direction == TrainDirection.South) - { - Console.Write("v"); - } - if (t.Direction == TrainDirection.West) - { - Console.Write("<"); - } - } - else - { - Console.Write(_grid[i, j]); - } - } - Console.WriteLine(); - } - } - } -} + + private int _width; + private int _height; + private char[,] _grid; + private List _trains = new(); + + private void Initialize(string[] inputs) + { + _width = inputs.Max(s => s.Length); + _height = inputs.Length; + _grid = new char[_width, _height]; + _trains.Clear(); + for (int j = 0; j < inputs.Length; j++) + { + for (int i = 0; i < inputs[j].Length; i++) + { + char cell = inputs[j][i]; + if (cell == '^') + { + _trains.Add(new Train + { + X = i, + Y = j, + Direction = TrainDirection.North, + NextIntersectionTurn = TrainTurning.Left, + }); + cell = '|'; + } + if (cell == 'v') + { + _trains.Add(new Train + { + X = i, + Y = j, + Direction = TrainDirection.South, + NextIntersectionTurn = TrainTurning.Left, + }); + cell = '|'; + } + if (cell == '<') + { + _trains.Add(new Train + { + X = i, + Y = j, + Direction = TrainDirection.West, + NextIntersectionTurn = TrainTurning.Left, + }); + cell = '-'; + } + if (cell == '>') + { + _trains.Add(new Train + { + X = i, + Y = j, + Direction = TrainDirection.East, + NextIntersectionTurn = TrainTurning.Left, + }); + cell = '-'; + } + _grid[i, j] = cell; + } + } + } + + private Train SimulateForFirstCollision() + { + Train collidingTrain = null; + IEnumerable orderedTrains = _trains.OrderBy(t => t.X + (t.Y * _width)); + foreach (Train t in orderedTrains) + { + t.Simulate(_grid); + collidingTrain = _trains.FirstOrDefault(x => x.X == t.X && x.Y == t.Y && t != x); + if (collidingTrain != null) { break; } + } + return collidingTrain; + } + + private Train SimulateForLastCart() + { + List orderedTrains = _trains.OrderBy(t => t.X + (t.Y * _width)).ToList(); + foreach (Train t in orderedTrains) + { + t.Simulate(_grid); + Train collidingTrain = _trains.FirstOrDefault(x => x.X == t.X && x.Y == t.Y && t != x); + if (collidingTrain != null) + { + _trains.Remove(t); + _trains.Remove(collidingTrain); + } + } + if (_trains.Count == 1) + { + return _trains[0]; + } + return null; + } + + private void ShowGrid() + { + Console.WriteLine(); + for (int j = 0; j < _height; j++) + { + for (int i = 0; i < _width; i++) + { + Train t = _trains.FirstOrDefault(x => x.X == i && x.Y == j); + if (t != null) + { + if (t.Direction == TrainDirection.North) + { + Console.Write("^"); + } + if (t.Direction == TrainDirection.East) + { + Console.Write(">"); + } + if (t.Direction == TrainDirection.South) + { + Console.Write("v"); + } + if (t.Direction == TrainDirection.West) + { + Console.Write("<"); + } + } + else + { + Console.Write(_grid[i, j]); + } + } + Console.WriteLine(); + } + } + +} \ No newline at end of file diff --git a/AdventOfCode2018/Day14.cs b/AdventOfCode2018/Day14.cs index 5949580..27874c5 100644 --- a/AdventOfCode2018/Day14.cs +++ b/AdventOfCode2018/Day14.cs @@ -2,189 +2,187 @@ using System.Linq; using System.Text; -namespace AdventOfCode2018 +namespace AdventOfCode2018; +/* + * +--- Day 14: Chocolate Charts --- + +You finally have a chance to look at all of the produce moving around. Chocolate, cinnamon, mint, chili peppers, nutmeg, vanilla... the Elves must be growing these plants to make hot chocolate! As you realize this, you hear a conversation in the distance. When you go to investigate, you discover two Elves in what appears to be a makeshift underground kitchen/laboratory. + +The Elves are trying to come up with the ultimate hot chocolate recipe; they're even maintaining a scoreboard which tracks the quality score (0-9) of each recipe. + +Only two recipes are on the board: the first recipe got a score of 3, the second, 7. Each of the two Elves has a current recipe: the first Elf starts with the first recipe, and the second Elf starts with the second recipe. + +To create new recipes, the two Elves combine their current recipes. This creates new recipes from the digits of the sum of the current recipes' scores. With the current recipes' scores of 3 and 7, their sum is 10, and so two new recipes would be created: the first with score 1 and the second with score 0. If the current recipes' scores were 2 and 3, the sum, 5, would only create one recipe (with a score of 5) with its single digit. + +The new recipes are added to the end of the scoreboard in the order they are created. So, after the first round, the scoreboard is 3, 7, 1, 0. + +After all new recipes are added to the scoreboard, each Elf picks a new current recipe. To do this, the Elf steps forward through the scoreboard a number of recipes equal to 1 plus the score of their current recipe. So, after the first round, the first Elf moves forward 1 + 3 = 4 times, while the second Elf moves forward 1 + 7 = 8 times. If they run out of recipes, they loop back around to the beginning. After the first round, both Elves happen to loop around until they land on the same recipe that they had in the beginning; in general, they will move to different recipes. + +Drawing the first Elf as parentheses and the second Elf as square brackets, they continue this process: + +(3)[7] +(3)[7] 1 0 + 3 7 1 [0](1) 0 + 3 7 1 0 [1] 0 (1) +(3) 7 1 0 1 0 [1] 2 + 3 7 1 0 (1) 0 1 2 [4] + 3 7 1 [0] 1 0 (1) 2 4 5 + 3 7 1 0 [1] 0 1 2 (4) 5 1 + 3 (7) 1 0 1 0 [1] 2 4 5 1 5 + 3 7 1 0 1 0 1 2 [4](5) 1 5 8 + 3 (7) 1 0 1 0 1 2 4 5 1 5 8 [9] + 3 7 1 0 1 0 1 [2] 4 (5) 1 5 8 9 1 6 + 3 7 1 0 1 0 1 2 4 5 [1] 5 8 9 1 (6) 7 + 3 7 1 0 (1) 0 1 2 4 5 1 5 [8] 9 1 6 7 7 + 3 7 [1] 0 1 0 (1) 2 4 5 1 5 8 9 1 6 7 7 9 + 3 7 1 0 [1] 0 1 2 (4) 5 1 5 8 9 1 6 7 7 9 2 + +The Elves think their skill will improve after making a few recipes (your puzzle input). However, that could take ages; you can speed this up considerably by identifying the scores of the ten recipes after that. For example: + + If the Elves think their skill will improve after making 9 recipes, the scores of the ten recipes after the first nine on the scoreboard would be 5158916779 (highlighted in the last line of the diagram). + After 5 recipes, the scores of the next ten would be 0124515891. + After 18 recipes, the scores of the next ten would be 9251071085. + After 2018 recipes, the scores of the next ten would be 5941429882. + +What are the scores of the ten recipes immediately after the number of recipes in your puzzle input? + +--- Part Two --- + +As it turns out, you got the Elves' plan backwards. They actually want to know how many recipes appear on the scoreboard to the left of the first recipes whose scores are the digits from your puzzle input. + + 51589 first appears after 9 recipes. + 01245 first appears after 5 recipes. + 92510 first appears after 18 recipes. + 59414 first appears after 2018 recipes. + +How many recipes appear on the scoreboard to the left of the score sequence in your puzzle input? + +*/ + +public class Day14 : IDay { - /* - * - --- Day 14: Chocolate Charts --- + private long _numRecipes; + private long _numRecipesAllocated; + private byte[] _recipes; + private long _idxA; + private long _idxB; + private long _searchSkip; - You finally have a chance to look at all of the produce moving around. Chocolate, cinnamon, mint, chili peppers, nutmeg, vanilla... the Elves must be growing these plants to make hot chocolate! As you realize this, you hear a conversation in the distance. When you go to investigate, you discover two Elves in what appears to be a makeshift underground kitchen/laboratory. - - The Elves are trying to come up with the ultimate hot chocolate recipe; they're even maintaining a scoreboard which tracks the quality score (0-9) of each recipe. - - Only two recipes are on the board: the first recipe got a score of 3, the second, 7. Each of the two Elves has a current recipe: the first Elf starts with the first recipe, and the second Elf starts with the second recipe. - - To create new recipes, the two Elves combine their current recipes. This creates new recipes from the digits of the sum of the current recipes' scores. With the current recipes' scores of 3 and 7, their sum is 10, and so two new recipes would be created: the first with score 1 and the second with score 0. If the current recipes' scores were 2 and 3, the sum, 5, would only create one recipe (with a score of 5) with its single digit. - - The new recipes are added to the end of the scoreboard in the order they are created. So, after the first round, the scoreboard is 3, 7, 1, 0. - - After all new recipes are added to the scoreboard, each Elf picks a new current recipe. To do this, the Elf steps forward through the scoreboard a number of recipes equal to 1 plus the score of their current recipe. So, after the first round, the first Elf moves forward 1 + 3 = 4 times, while the second Elf moves forward 1 + 7 = 8 times. If they run out of recipes, they loop back around to the beginning. After the first round, both Elves happen to loop around until they land on the same recipe that they had in the beginning; in general, they will move to different recipes. - - Drawing the first Elf as parentheses and the second Elf as square brackets, they continue this process: - - (3)[7] - (3)[7] 1 0 - 3 7 1 [0](1) 0 - 3 7 1 0 [1] 0 (1) - (3) 7 1 0 1 0 [1] 2 - 3 7 1 0 (1) 0 1 2 [4] - 3 7 1 [0] 1 0 (1) 2 4 5 - 3 7 1 0 [1] 0 1 2 (4) 5 1 - 3 (7) 1 0 1 0 [1] 2 4 5 1 5 - 3 7 1 0 1 0 1 2 [4](5) 1 5 8 - 3 (7) 1 0 1 0 1 2 4 5 1 5 8 [9] - 3 7 1 0 1 0 1 [2] 4 (5) 1 5 8 9 1 6 - 3 7 1 0 1 0 1 2 4 5 [1] 5 8 9 1 (6) 7 - 3 7 1 0 (1) 0 1 2 4 5 1 5 [8] 9 1 6 7 7 - 3 7 [1] 0 1 0 (1) 2 4 5 1 5 8 9 1 6 7 7 9 - 3 7 1 0 [1] 0 1 2 (4) 5 1 5 8 9 1 6 7 7 9 2 - - The Elves think their skill will improve after making a few recipes (your puzzle input). However, that could take ages; you can speed this up considerably by identifying the scores of the ten recipes after that. For example: - - If the Elves think their skill will improve after making 9 recipes, the scores of the ten recipes after the first nine on the scoreboard would be 5158916779 (highlighted in the last line of the diagram). - After 5 recipes, the scores of the next ten would be 0124515891. - After 18 recipes, the scores of the next ten would be 9251071085. - After 2018 recipes, the scores of the next ten would be 5941429882. - - What are the scores of the ten recipes immediately after the number of recipes in your puzzle input? - - --- Part Two --- - - As it turns out, you got the Elves' plan backwards. They actually want to know how many recipes appear on the scoreboard to the left of the first recipes whose scores are the digits from your puzzle input. - - 51589 first appears after 9 recipes. - 01245 first appears after 5 recipes. - 92510 first appears after 18 recipes. - 59414 first appears after 2018 recipes. - - How many recipes appear on the scoreboard to the left of the score sequence in your puzzle input? - - */ - - public class Day14 : IDay + private void Init(long hintAllocation = 128) { - private long _numRecipes = 0; - private long _numRecipesAllocated = 0; - private byte[] _recipes = null; - private long _idxA = 0; - private long _idxB = 0; - private long _searchSkip = 0; + _numRecipes = 2; + _numRecipesAllocated = hintAllocation; + _recipes = new byte[_numRecipesAllocated]; + _recipes[0] = 3; + _recipes[1] = 7; + _idxA = 0; + _idxB = 1; + _searchSkip = 0; + } - private void Init(long hintAllocation = 128) + private void Step() + { + if (_numRecipes + 2 >= _numRecipesAllocated) { - _numRecipes = 2; - _numRecipesAllocated = hintAllocation; - _recipes = new byte[_numRecipesAllocated]; - _recipes[0] = 3; - _recipes[1] = 7; - _idxA = 0; - _idxB = 1; - _searchSkip = 0; - } - - private void Step() - { - if (_numRecipes + 2 >= _numRecipesAllocated) + _numRecipesAllocated *= 2; + byte[] newRecipes = new byte[_numRecipesAllocated]; + for (int i = 0; i < _numRecipes; i++) { - _numRecipesAllocated *= 2; - byte[] newRecipes = new byte[_numRecipesAllocated]; - for (int i = 0; i < _numRecipes; i++) - { - newRecipes[i] = _recipes[i]; - } - _recipes = newRecipes; + newRecipes[i] = _recipes[i]; } - int newRecipe = _recipes[_idxA] + _recipes[_idxB]; - if (newRecipe >= 10) + _recipes = newRecipes; + } + int newRecipe = _recipes[_idxA] + _recipes[_idxB]; + if (newRecipe >= 10) + { + _recipes[_numRecipes] = 1; + _recipes[_numRecipes + 1] = (byte)(newRecipe % 10); + _numRecipes += 2; + } + else + { + _recipes[_numRecipes] = (byte)(newRecipe % 10); + _numRecipes += 1; + } + _idxA = (_idxA + _recipes[_idxA] + 1) % _numRecipes; + _idxB = (_idxB + _recipes[_idxB] + 1) % _numRecipes; + } + + private void Print() + { + Console.WriteLine(); + for (int i = 0; i < _numRecipes; i++) + { + if (i == _idxA) { - _recipes[_numRecipes] = 1; - _recipes[_numRecipes + 1] = (byte)(newRecipe % 10); - _numRecipes += 2; + Console.Write(" ({0})", _recipes[i]); + } + else if (i == _idxB) + { + Console.Write(" [{0}]", _recipes[i]); } else { - _recipes[_numRecipes] = (byte)(newRecipe % 10); - _numRecipes += 1; + Console.Write(" {0} ", _recipes[i]); } - _idxA = (_idxA + _recipes[_idxA] + 1) % _numRecipes; - _idxB = (_idxB + _recipes[_idxB] + 1) % _numRecipes; - } - - private void Print() - { - Console.WriteLine(); - for (int i = 0; i < _numRecipes; i++) - { - if (i == _idxA) - { - Console.Write(" ({0})", _recipes[i]); - } - else if (i == _idxB) - { - Console.Write(" [{0}]", _recipes[i]); - } - else - { - Console.Write(" {0} ", _recipes[i]); - } - } - } - - private long SearchPattern(byte[] pattern) - { - long i; - for (i = _searchSkip; i < (_numRecipes - pattern.Length); i++) - { - long j; - for (j = 0; j < pattern.Length; j++) - { - if (_recipes[i + j] != pattern[j]) - { - break; - } - } - if (j == pattern.Length) - { - return i; - } - } - _searchSkip = i - 1; - if (_searchSkip < 0) { _searchSkip = 0; } - return -1; - } - - private bool Show { get; set; } = false; - - public string ResolvePart1(string[] inputs) - { - int numSkipRecipes = Convert.ToInt32(inputs[0]); - Init(numSkipRecipes + 20); - do - { - if (Show) { Print(); } - Step(); - } while (_numRecipes < (numSkipRecipes + 10)); - - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 10; i++) - { - sb.Append(_recipes[numSkipRecipes + i]); - } - return sb.ToString(); - } - - public string ResolvePart2(string[] inputs) - { - byte[] pattern = inputs[0].Select(c => (byte)(c - '0')).ToArray(); - Init(); - long position = -1; - do - { - if (Show) { Print(); } - Step(); - position = SearchPattern(pattern); - } while (position < 0); - return position.ToString(); } } -} + + private long SearchPattern(byte[] pattern) + { + long i; + for (i = _searchSkip; i < (_numRecipes - pattern.Length); i++) + { + long j; + for (j = 0; j < pattern.Length; j++) + { + if (_recipes[i + j] != pattern[j]) + { + break; + } + } + if (j == pattern.Length) + { + return i; + } + } + _searchSkip = i - 1; + if (_searchSkip < 0) { _searchSkip = 0; } + return -1; + } + + private bool Show { get; set; } = false; + + public string ResolvePart1(string[] inputs) + { + int numSkipRecipes = Convert.ToInt32(inputs[0]); + Init(numSkipRecipes + 20); + do + { + if (Show) { Print(); } + Step(); + } while (_numRecipes < (numSkipRecipes + 10)); + + StringBuilder sb = new(); + for (int i = 0; i < 10; i++) + { + sb.Append(_recipes[numSkipRecipes + i]); + } + return sb.ToString(); + } + + public string ResolvePart2(string[] inputs) + { + byte[] pattern = inputs[0].Select(c => (byte)(c - '0')).ToArray(); + Init(); + long position; + do + { + if (Show) { Print(); } + Step(); + position = SearchPattern(pattern); + } while (position < 0); + return position.ToString(); + } +} \ No newline at end of file diff --git a/AdventOfCode2018/Day15.cs b/AdventOfCode2018/Day15.cs index 1babf6f..925c49a 100644 --- a/AdventOfCode2018/Day15.cs +++ b/AdventOfCode2018/Day15.cs @@ -1,770 +1,766 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace AdventOfCode2018 +namespace AdventOfCode2018; + +/* + * +--- Day 15: Beverage Bandits --- + +Having perfected their hot chocolate, the Elves have a new problem: the Goblins that live in these caves will do anything to steal it. Looks like they're here for a fight. + +You scan the area, generating a map of the walls (#), open cavern (.), and starting position of every Goblin (G) and Elf (E) (your puzzle input). + +Combat proceeds in rounds; in each round, each unit that is still alive takes a turn, resolving all of its actions before the next unit's turn begins. On each unit's turn, it tries to move into range of an enemy (if it isn't already) and then attack (if it is in range). + +All units are very disciplined and always follow very strict combat rules. Units never move or attack diagonally, as doing so would be dishonorable. When multiple choices are equally valid, ties are broken in reading order: top-to-bottom, then left-to-right. For instance, the order in which units take their turns within a round is the reading order of their starting positions in that round, regardless of the type of unit or whether other units have moved after the round started. For example: + + would take their +These units: turns in this order: + ####### ####### + #.G.E.# #.1.2.# + #E.G.E# #3.4.5# + #.G.E.# #.6.7.# + ####### ####### + +Each unit begins its turn by identifying all possible targets (enemy units). If no targets remain, combat ends. + +Then, the unit identifies all of the open squares (.) that are in range of each target; these are the squares which are adjacent (immediately up, down, left, or right) to any target and which aren't already occupied by a wall or another unit. Alternatively, the unit might already be in range of a target. If the unit is not already in range of a target, and there are no open squares which are in range of a target, the unit ends its turn. + +If the unit is already in range of a target, it does not move, but continues its turn with an attack. Otherwise, since it is not in range of a target, it moves. + +To move, the unit first considers the squares that are in range and determines which of those squares it could reach in the fewest steps. A step is a single movement to any adjacent (immediately up, down, left, or right) open (.) square. Units cannot move into walls or other units. The unit does this while considering the current positions of units and does not do any prediction about where units will be later. If the unit cannot reach (find an open path to) any of the squares that are in range, it ends its turn. If multiple squares are in range and tied for being reachable in the fewest steps, the square which is first in reading order is chosen. For example: + +Targets: In range: Reachable: Nearest: Chosen: +####### ####### ####### ####### ####### +#E..G.# #E.?G?# #E.@G.# #E.!G.# #E.+G.# +#...#.# --> #.?.#?# --> #.@.#.# --> #.!.#.# --> #...#.# +#.G.#G# #?G?#G# #@G@#G# #!G.#G# #.G.#G# +####### ####### ####### ####### ####### + +In the above scenario, the Elf has three targets (the three Goblins): + + Each of the Goblins has open, adjacent squares which are in range (marked with a ? on the map). + Of those squares, four are reachable (marked @); the other two (on the right) would require moving through a wall or unit to reach. + Three of these reachable squares are nearest, requiring the fewest steps (only 2) to reach (marked !). + Of those, the square which is first in reading order is chosen (+). + +The unit then takes a single step toward the chosen square along the shortest path to that square. If multiple steps would put the unit equally closer to its destination, the unit chooses the step which is first in reading order. (This requires knowing when there is more than one shortest path so that you can consider the first step of each such path.) For example: + +In range: Nearest: Chosen: Distance: Step: +####### ####### ####### ####### ####### +#.E...# #.E...# #.E...# #4E212# #..E..# +#...?.# --> #...!.# --> #...+.# --> #32101# --> #.....# +#..?G?# #..!G.# #...G.# #432G2# #...G.# +####### ####### ####### ####### ####### + +The Elf sees three squares in range of a target (?), two of which are nearest (!), and so the first in reading order is chosen (+). Under "Distance", each open square is marked with its distance from the destination square; the two squares to which the Elf could move on this turn (down and to the right) are both equally good moves and would leave the Elf 2 steps from being in range of the Goblin. Because the step which is first in reading order is chosen, the Elf moves right one square. + +Here's a larger example of movement: + +Initially: +######### +#G..G..G# +#.......# +#.......# +#G..E..G# +#.......# +#.......# +#G..G..G# +######### + +After 1 round: +######### +#.G...G.# +#...G...# +#...E..G# +#.G.....# +#.......# +#G..G..G# +#.......# +######### + +After 2 rounds: +######### +#..G.G..# +#...G...# +#.G.E.G.# +#.......# +#G..G..G# +#.......# +#.......# +######### + +After 3 rounds: +######### +#.......# +#..GGG..# +#..GEG..# +#G..G...# +#......G# +#.......# +#.......# +######### + +Once the Goblins and Elf reach the positions above, they all are either in range of a target or cannot find any square in range of a target, and so none of the units can move until a unit dies. + +After moving (or if the unit began its turn in range of a target), the unit attacks. + +To attack, the unit first determines all of the targets that are in range of it by being immediately adjacent to it. If there are no such targets, the unit ends its turn. Otherwise, the adjacent target with the fewest hit points is selected; in a tie, the adjacent target with the fewest hit points which is first in reading order is selected. + +The unit deals damage equal to its attack power to the selected target, reducing its hit points by that amount. If this reduces its hit points to 0 or fewer, the selected target dies: its square becomes . and it takes no further turns. + +Each unit, either Goblin or Elf, has 3 attack power and starts with 200 hit points. + +For example, suppose the only Elf is about to attack: + + HP: HP: +G.... 9 G.... 9 +..G.. 4 ..G.. 4 +..EG. 2 --> ..E.. +..G.. 2 ..G.. 2 +...G. 1 ...G. 1 + +The "HP" column shows the hit points of the Goblin to the left in the corresponding row. The Elf is in range of three targets: the Goblin above it (with 4 hit points), the Goblin to its right (with 2 hit points), and the Goblin below it (also with 2 hit points). Because three targets are in range, the ones with the lowest hit points are selected: the two Goblins with 2 hit points each (one to the right of the Elf and one below the Elf). Of those, the Goblin first in reading order (the one to the right of the Elf) is selected. The selected Goblin's hit points (2) are reduced by the Elf's attack power (3), reducing its hit points to -1, killing it. + +After attacking, the unit's turn ends. Regardless of how the unit's turn ends, the next unit in the round takes its turn. If all units have taken turns in this round, the round ends, and a new round begins. + +The Elves look quite outnumbered. You need to determine the outcome of the battle: the number of full rounds that were completed (not counting the round in which combat ends) multiplied by the sum of the hit points of all remaining units at the moment combat ends. (Combat only ends when a unit finds no targets during its turn.) + +Below is an entire sample combat. Next to each map, each row's units' hit points are listed from left to right. + +Initially: +####### +#.G...# G(200) +#...EG# E(200), G(200) +#.#.#G# G(200) +#..G#E# G(200), E(200) +#.....# +####### + +After 1 round: +####### +#..G..# G(200) +#...EG# E(197), G(197) +#.#G#G# G(200), G(197) +#...#E# E(197) +#.....# +####### + +After 2 rounds: +####### +#...G.# G(200) +#..GEG# G(200), E(188), G(194) +#.#.#G# G(194) +#...#E# E(194) +#.....# +####### + +Combat ensues; eventually, the top Elf dies: + +After 23 rounds: +####### +#...G.# G(200) +#..G.G# G(200), G(131) +#.#.#G# G(131) +#...#E# E(131) +#.....# +####### + +After 24 rounds: +####### +#..G..# G(200) +#...G.# G(131) +#.#G#G# G(200), G(128) +#...#E# E(128) +#.....# +####### + +After 25 rounds: +####### +#.G...# G(200) +#..G..# G(131) +#.#.#G# G(125) +#..G#E# G(200), E(125) +#.....# +####### + +After 26 rounds: +####### +#G....# G(200) +#.G...# G(131) +#.#.#G# G(122) +#...#E# E(122) +#..G..# G(200) +####### + +After 27 rounds: +####### +#G....# G(200) +#.G...# G(131) +#.#.#G# G(119) +#...#E# E(119) +#...G.# G(200) +####### + +After 28 rounds: +####### +#G....# G(200) +#.G...# G(131) +#.#.#G# G(116) +#...#E# E(113) +#....G# G(200) +####### + +More combat ensues; eventually, the bottom Elf dies: + +After 47 rounds: +####### +#G....# G(200) +#.G...# G(131) +#.#.#G# G(59) +#...#.# +#....G# G(200) +####### + +Before the 48th round can finish, the top-left Goblin finds that there are no targets remaining, and so combat ends. So, the number of full rounds that were completed is 47, and the sum of the hit points of all remaining units is 200+131+59+200 = 590. From these, the outcome of the battle is 47 * 590 = 27730. + +Here are a few example summarized combats: + +####### ####### +#G..#E# #...#E# E(200) +#E#E.E# #E#...# E(197) +#G.##.# --> #.E##.# E(185) +#...#E# #E..#E# E(200), E(200) +#...E.# #.....# +####### ####### + +Combat ends after 37 full rounds +Elves win with 982 total hit points left +Outcome: 37 * 982 = 36334 + +####### ####### +#E..EG# #.E.E.# E(164), E(197) +#.#G.E# #.#E..# E(200) +#E.##E# --> #E.##.# E(98) +#G..#.# #.E.#.# E(200) +#..E#.# #...#.# +####### ####### + +Combat ends after 46 full rounds +Elves win with 859 total hit points left +Outcome: 46 * 859 = 39514 + +####### ####### +#E.G#.# #G.G#.# G(200), G(98) +#.#G..# #.#G..# G(200) +#G.#.G# --> #..#..# +#G..#.# #...#G# G(95) +#...E.# #...G.# G(200) +####### ####### + +Combat ends after 35 full rounds +Goblins win with 793 total hit points left +Outcome: 35 * 793 = 27755 + +####### ####### +#.E...# #.....# +#.#..G# #.#G..# G(200) +#.###.# --> #.###.# +#E#G#G# #.#.#.# +#...#G# #G.G#G# G(98), G(38), G(200) +####### ####### + +Combat ends after 54 full rounds +Goblins win with 536 total hit points left +Outcome: 54 * 536 = 28944 + +######### ######### +#G......# #.G.....# G(137) +#.E.#...# #G.G#...# G(200), G(200) +#..##..G# #.G##...# G(200) +#...##..# --> #...##..# +#...#...# #.G.#...# G(200) +#.G...G.# #.......# +#.....G.# #.......# +######### ######### + +Combat ends after 20 full rounds +Goblins win with 937 total hit points left +Outcome: 20 * 937 = 18740 + +What is the outcome of the combat described in your puzzle input? + +--- Part Two --- + +According to your calculations, the Elves are going to lose badly. Surely, you won't mess up the timeline too much if you give them just a little advanced technology, right? + +You need to make sure the Elves not only win, but also suffer no losses: even the death of a single Elf is unacceptable. + +However, you can't go too far: larger changes will be more likely to permanently alter spacetime. + +So, you need to find the outcome of the battle in which the Elves have the lowest integer attack power (at least 4) that allows them to win without a single death. The Goblins always have an attack power of 3. + +In the first summarized example above, the lowest attack power the Elves need to win without losses is 15: + +####### ####### +#.G...# #..E..# E(158) +#...EG# #...E.# E(14) +#.#.#G# --> #.#.#.# +#..G#E# #...#.# +#.....# #.....# +####### ####### + +Combat ends after 29 full rounds +Elves win with 172 total hit points left +Outcome: 29 * 172 = 4988 + +In the second example above, the Elves need only 4 attack power: + +####### ####### +#E..EG# #.E.E.# E(200), E(23) +#.#G.E# #.#E..# E(200) +#E.##E# --> #E.##E# E(125), E(200) +#G..#.# #.E.#.# E(200) +#..E#.# #...#.# +####### ####### + +Combat ends after 33 full rounds +Elves win with 948 total hit points left +Outcome: 33 * 948 = 31284 + +In the third example above, the Elves need 15 attack power: + +####### ####### +#E.G#.# #.E.#.# E(8) +#.#G..# #.#E..# E(86) +#G.#.G# --> #..#..# +#G..#.# #...#.# +#...E.# #.....# +####### ####### + +Combat ends after 37 full rounds +Elves win with 94 total hit points left +Outcome: 37 * 94 = 3478 + +In the fourth example above, the Elves need 12 attack power: + +####### ####### +#.E...# #...E.# E(14) +#.#..G# #.#..E# E(152) +#.###.# --> #.###.# +#E#G#G# #.#.#.# +#...#G# #...#.# +####### ####### + +Combat ends after 39 full rounds +Elves win with 166 total hit points left +Outcome: 39 * 166 = 6474 + +In the last example above, the lone Elf needs 34 attack power: + +######### ######### +#G......# #.......# +#.E.#...# #.E.#...# E(38) +#..##..G# #..##...# +#...##..# --> #...##..# +#...#...# #...#...# +#.G...G.# #.......# +#.....G.# #.......# +######### ######### + +Combat ends after 30 full rounds +Elves win with 38 total hit points left +Outcome: 30 * 38 = 1140 + +After increasing the Elves' attack power until it is just barely enough for them to win without any Elves dying, what is the outcome of the combat described in your puzzle input? + +*/ +public class Day15 : IDay { - /* - * - --- Day 15: Beverage Bandits --- + public enum EntityType { Elf, Goblin, } - Having perfected their hot chocolate, the Elves have a new problem: the Goblins that live in these caves will do anything to steal it. Looks like they're here for a fight. + public bool Show { get; set; } = false; - You scan the area, generating a map of the walls (#), open cavern (.), and starting position of every Goblin (G) and Elf (E) (your puzzle input). - - Combat proceeds in rounds; in each round, each unit that is still alive takes a turn, resolving all of its actions before the next unit's turn begins. On each unit's turn, it tries to move into range of an enemy (if it isn't already) and then attack (if it is in range). - - All units are very disciplined and always follow very strict combat rules. Units never move or attack diagonally, as doing so would be dishonorable. When multiple choices are equally valid, ties are broken in reading order: top-to-bottom, then left-to-right. For instance, the order in which units take their turns within a round is the reading order of their starting positions in that round, regardless of the type of unit or whether other units have moved after the round started. For example: - - would take their - These units: turns in this order: - ####### ####### - #.G.E.# #.1.2.# - #E.G.E# #3.4.5# - #.G.E.# #.6.7.# - ####### ####### - - Each unit begins its turn by identifying all possible targets (enemy units). If no targets remain, combat ends. - - Then, the unit identifies all of the open squares (.) that are in range of each target; these are the squares which are adjacent (immediately up, down, left, or right) to any target and which aren't already occupied by a wall or another unit. Alternatively, the unit might already be in range of a target. If the unit is not already in range of a target, and there are no open squares which are in range of a target, the unit ends its turn. - - If the unit is already in range of a target, it does not move, but continues its turn with an attack. Otherwise, since it is not in range of a target, it moves. - - To move, the unit first considers the squares that are in range and determines which of those squares it could reach in the fewest steps. A step is a single movement to any adjacent (immediately up, down, left, or right) open (.) square. Units cannot move into walls or other units. The unit does this while considering the current positions of units and does not do any prediction about where units will be later. If the unit cannot reach (find an open path to) any of the squares that are in range, it ends its turn. If multiple squares are in range and tied for being reachable in the fewest steps, the square which is first in reading order is chosen. For example: - - Targets: In range: Reachable: Nearest: Chosen: - ####### ####### ####### ####### ####### - #E..G.# #E.?G?# #E.@G.# #E.!G.# #E.+G.# - #...#.# --> #.?.#?# --> #.@.#.# --> #.!.#.# --> #...#.# - #.G.#G# #?G?#G# #@G@#G# #!G.#G# #.G.#G# - ####### ####### ####### ####### ####### - - In the above scenario, the Elf has three targets (the three Goblins): - - Each of the Goblins has open, adjacent squares which are in range (marked with a ? on the map). - Of those squares, four are reachable (marked @); the other two (on the right) would require moving through a wall or unit to reach. - Three of these reachable squares are nearest, requiring the fewest steps (only 2) to reach (marked !). - Of those, the square which is first in reading order is chosen (+). - - The unit then takes a single step toward the chosen square along the shortest path to that square. If multiple steps would put the unit equally closer to its destination, the unit chooses the step which is first in reading order. (This requires knowing when there is more than one shortest path so that you can consider the first step of each such path.) For example: - - In range: Nearest: Chosen: Distance: Step: - ####### ####### ####### ####### ####### - #.E...# #.E...# #.E...# #4E212# #..E..# - #...?.# --> #...!.# --> #...+.# --> #32101# --> #.....# - #..?G?# #..!G.# #...G.# #432G2# #...G.# - ####### ####### ####### ####### ####### - - The Elf sees three squares in range of a target (?), two of which are nearest (!), and so the first in reading order is chosen (+). Under "Distance", each open square is marked with its distance from the destination square; the two squares to which the Elf could move on this turn (down and to the right) are both equally good moves and would leave the Elf 2 steps from being in range of the Goblin. Because the step which is first in reading order is chosen, the Elf moves right one square. - - Here's a larger example of movement: - - Initially: - ######### - #G..G..G# - #.......# - #.......# - #G..E..G# - #.......# - #.......# - #G..G..G# - ######### - - After 1 round: - ######### - #.G...G.# - #...G...# - #...E..G# - #.G.....# - #.......# - #G..G..G# - #.......# - ######### - - After 2 rounds: - ######### - #..G.G..# - #...G...# - #.G.E.G.# - #.......# - #G..G..G# - #.......# - #.......# - ######### - - After 3 rounds: - ######### - #.......# - #..GGG..# - #..GEG..# - #G..G...# - #......G# - #.......# - #.......# - ######### - - Once the Goblins and Elf reach the positions above, they all are either in range of a target or cannot find any square in range of a target, and so none of the units can move until a unit dies. - - After moving (or if the unit began its turn in range of a target), the unit attacks. - - To attack, the unit first determines all of the targets that are in range of it by being immediately adjacent to it. If there are no such targets, the unit ends its turn. Otherwise, the adjacent target with the fewest hit points is selected; in a tie, the adjacent target with the fewest hit points which is first in reading order is selected. - - The unit deals damage equal to its attack power to the selected target, reducing its hit points by that amount. If this reduces its hit points to 0 or fewer, the selected target dies: its square becomes . and it takes no further turns. - - Each unit, either Goblin or Elf, has 3 attack power and starts with 200 hit points. - - For example, suppose the only Elf is about to attack: - - HP: HP: - G.... 9 G.... 9 - ..G.. 4 ..G.. 4 - ..EG. 2 --> ..E.. - ..G.. 2 ..G.. 2 - ...G. 1 ...G. 1 - - The "HP" column shows the hit points of the Goblin to the left in the corresponding row. The Elf is in range of three targets: the Goblin above it (with 4 hit points), the Goblin to its right (with 2 hit points), and the Goblin below it (also with 2 hit points). Because three targets are in range, the ones with the lowest hit points are selected: the two Goblins with 2 hit points each (one to the right of the Elf and one below the Elf). Of those, the Goblin first in reading order (the one to the right of the Elf) is selected. The selected Goblin's hit points (2) are reduced by the Elf's attack power (3), reducing its hit points to -1, killing it. - - After attacking, the unit's turn ends. Regardless of how the unit's turn ends, the next unit in the round takes its turn. If all units have taken turns in this round, the round ends, and a new round begins. - - The Elves look quite outnumbered. You need to determine the outcome of the battle: the number of full rounds that were completed (not counting the round in which combat ends) multiplied by the sum of the hit points of all remaining units at the moment combat ends. (Combat only ends when a unit finds no targets during its turn.) - - Below is an entire sample combat. Next to each map, each row's units' hit points are listed from left to right. - - Initially: - ####### - #.G...# G(200) - #...EG# E(200), G(200) - #.#.#G# G(200) - #..G#E# G(200), E(200) - #.....# - ####### - - After 1 round: - ####### - #..G..# G(200) - #...EG# E(197), G(197) - #.#G#G# G(200), G(197) - #...#E# E(197) - #.....# - ####### - - After 2 rounds: - ####### - #...G.# G(200) - #..GEG# G(200), E(188), G(194) - #.#.#G# G(194) - #...#E# E(194) - #.....# - ####### - - Combat ensues; eventually, the top Elf dies: - - After 23 rounds: - ####### - #...G.# G(200) - #..G.G# G(200), G(131) - #.#.#G# G(131) - #...#E# E(131) - #.....# - ####### - - After 24 rounds: - ####### - #..G..# G(200) - #...G.# G(131) - #.#G#G# G(200), G(128) - #...#E# E(128) - #.....# - ####### - - After 25 rounds: - ####### - #.G...# G(200) - #..G..# G(131) - #.#.#G# G(125) - #..G#E# G(200), E(125) - #.....# - ####### - - After 26 rounds: - ####### - #G....# G(200) - #.G...# G(131) - #.#.#G# G(122) - #...#E# E(122) - #..G..# G(200) - ####### - - After 27 rounds: - ####### - #G....# G(200) - #.G...# G(131) - #.#.#G# G(119) - #...#E# E(119) - #...G.# G(200) - ####### - - After 28 rounds: - ####### - #G....# G(200) - #.G...# G(131) - #.#.#G# G(116) - #...#E# E(113) - #....G# G(200) - ####### - - More combat ensues; eventually, the bottom Elf dies: - - After 47 rounds: - ####### - #G....# G(200) - #.G...# G(131) - #.#.#G# G(59) - #...#.# - #....G# G(200) - ####### - - Before the 48th round can finish, the top-left Goblin finds that there are no targets remaining, and so combat ends. So, the number of full rounds that were completed is 47, and the sum of the hit points of all remaining units is 200+131+59+200 = 590. From these, the outcome of the battle is 47 * 590 = 27730. - - Here are a few example summarized combats: - - ####### ####### - #G..#E# #...#E# E(200) - #E#E.E# #E#...# E(197) - #G.##.# --> #.E##.# E(185) - #...#E# #E..#E# E(200), E(200) - #...E.# #.....# - ####### ####### - - Combat ends after 37 full rounds - Elves win with 982 total hit points left - Outcome: 37 * 982 = 36334 - - ####### ####### - #E..EG# #.E.E.# E(164), E(197) - #.#G.E# #.#E..# E(200) - #E.##E# --> #E.##.# E(98) - #G..#.# #.E.#.# E(200) - #..E#.# #...#.# - ####### ####### - - Combat ends after 46 full rounds - Elves win with 859 total hit points left - Outcome: 46 * 859 = 39514 - - ####### ####### - #E.G#.# #G.G#.# G(200), G(98) - #.#G..# #.#G..# G(200) - #G.#.G# --> #..#..# - #G..#.# #...#G# G(95) - #...E.# #...G.# G(200) - ####### ####### - - Combat ends after 35 full rounds - Goblins win with 793 total hit points left - Outcome: 35 * 793 = 27755 - - ####### ####### - #.E...# #.....# - #.#..G# #.#G..# G(200) - #.###.# --> #.###.# - #E#G#G# #.#.#.# - #...#G# #G.G#G# G(98), G(38), G(200) - ####### ####### - - Combat ends after 54 full rounds - Goblins win with 536 total hit points left - Outcome: 54 * 536 = 28944 - - ######### ######### - #G......# #.G.....# G(137) - #.E.#...# #G.G#...# G(200), G(200) - #..##..G# #.G##...# G(200) - #...##..# --> #...##..# - #...#...# #.G.#...# G(200) - #.G...G.# #.......# - #.....G.# #.......# - ######### ######### - - Combat ends after 20 full rounds - Goblins win with 937 total hit points left - Outcome: 20 * 937 = 18740 - - What is the outcome of the combat described in your puzzle input? - - --- Part Two --- - - According to your calculations, the Elves are going to lose badly. Surely, you won't mess up the timeline too much if you give them just a little advanced technology, right? - - You need to make sure the Elves not only win, but also suffer no losses: even the death of a single Elf is unacceptable. - - However, you can't go too far: larger changes will be more likely to permanently alter spacetime. - - So, you need to find the outcome of the battle in which the Elves have the lowest integer attack power (at least 4) that allows them to win without a single death. The Goblins always have an attack power of 3. - - In the first summarized example above, the lowest attack power the Elves need to win without losses is 15: - - ####### ####### - #.G...# #..E..# E(158) - #...EG# #...E.# E(14) - #.#.#G# --> #.#.#.# - #..G#E# #...#.# - #.....# #.....# - ####### ####### - - Combat ends after 29 full rounds - Elves win with 172 total hit points left - Outcome: 29 * 172 = 4988 - - In the second example above, the Elves need only 4 attack power: - - ####### ####### - #E..EG# #.E.E.# E(200), E(23) - #.#G.E# #.#E..# E(200) - #E.##E# --> #E.##E# E(125), E(200) - #G..#.# #.E.#.# E(200) - #..E#.# #...#.# - ####### ####### - - Combat ends after 33 full rounds - Elves win with 948 total hit points left - Outcome: 33 * 948 = 31284 - - In the third example above, the Elves need 15 attack power: - - ####### ####### - #E.G#.# #.E.#.# E(8) - #.#G..# #.#E..# E(86) - #G.#.G# --> #..#..# - #G..#.# #...#.# - #...E.# #.....# - ####### ####### - - Combat ends after 37 full rounds - Elves win with 94 total hit points left - Outcome: 37 * 94 = 3478 - - In the fourth example above, the Elves need 12 attack power: - - ####### ####### - #.E...# #...E.# E(14) - #.#..G# #.#..E# E(152) - #.###.# --> #.###.# - #E#G#G# #.#.#.# - #...#G# #...#.# - ####### ####### - - Combat ends after 39 full rounds - Elves win with 166 total hit points left - Outcome: 39 * 166 = 6474 - - In the last example above, the lone Elf needs 34 attack power: - - ######### ######### - #G......# #.......# - #.E.#...# #.E.#...# E(38) - #..##..G# #..##...# - #...##..# --> #...##..# - #...#...# #...#...# - #.G...G.# #.......# - #.....G.# #.......# - ######### ######### - - Combat ends after 30 full rounds - Elves win with 38 total hit points left - Outcome: 30 * 38 = 1140 - - After increasing the Elves' attack power until it is just barely enough for them to win without any Elves dying, what is the outcome of the combat described in your puzzle input? - - */ - public class Day15 : IDay + public class Entity { - public enum EntityType { Elf, Goblin, } + public const int GoblinAttackPower = 3; + public static int ElfAttackPower { get; set; } = 3; + public const int InitialHealth = 200; - public bool Show { get; set; } = false; + public EntityType Type { get; set; } + public int X { get; set; } + public int Y { get; set; } + public int Health { get; set; } = InitialHealth; - public class Entity + public bool IsAlive() { - public const int GoblinAttackPower = 3; - public static int ElfAttackPower { get; set; } = 3; - public const int InitialHealth = 200; + return Health > 0; + } - public EntityType Type { get; set; } - public int X { get; set; } - public int Y { get; set; } - public int Health { get; set; } = InitialHealth; - - public bool IsAlive() + public bool InRangeOf(Entity other) + { + if ( + (other.X + 1 == X && other.Y == Y) || + (other.X - 1 == X && other.Y == Y) || + (other.X == X && other.Y + 1 == Y) || + (other.X == X && other.Y - 1 == Y) || + false + ) { - return Health > 0; - } - - public bool InRangeOf(Entity other) - { - if ( - (other.X + 1 == X && other.Y == Y) || - (other.X - 1 == X && other.Y == Y) || - (other.X == X && other.Y + 1 == Y) || - (other.X == X && other.Y - 1 == Y) || - false - ) - { - return true; - } - return false; + return true; } + return false; + } - public void Attack(char[,] map, Entity other) - { - if(Type == EntityType.Elf) - { - other.Health -= ElfAttackPower; - } - else - { - other.Health -= GoblinAttackPower; - } - if (other.IsAlive() == false) - { - map[other.X, other.Y] = '.'; - } - } - - public void MoveTo(char[,] map, int x, int y) - { - map[X, Y] = '.'; - X = x; - Y = y; - map[X, Y] = (Type == EntityType.Elf) ? 'E' : 'G'; - } - } - - public class Target + public void Attack(char[,] map, Entity other) { - public int X { get; set; } - public int Y { get; set; } - public int Distance { get; set; } - public int Priority { get; set; } - public Entity Entity { get; set; } + if(Type == EntityType.Elf) + { + other.Health -= ElfAttackPower; + } + else + { + other.Health -= GoblinAttackPower; + } + if (other.IsAlive() == false) + { + map[other.X, other.Y] = '.'; + } } - private int _width = 0; - private int _height = 0; - private char[,] _map = null; - private List _entities = null; - private BreadthFirstSearchGrid _search = null; - private int _rounds = 0; + public void MoveTo(char[,] map, int x, int y) + { + map[X, Y] = '.'; + X = x; + Y = y; + map[X, Y] = (Type == EntityType.Elf) ? 'E' : 'G'; + } + } + + public class Target + { + public int X { get; set; } + public int Y { get; set; } + public int Distance { get; set; } + public int Priority { get; set; } + public Entity Entity { get; set; } + } + + private int _width; + private int _height; + private char[,] _map; + private List _entities; + private BreadthFirstSearchGrid _search; + private int _rounds; - private void Init(string[] inputs) + private void Init(string[] inputs) + { + _height = inputs.Length; + _width = inputs.Max(input => input.Length); + _map = new char[_width, _height]; + _entities = new List(); + for (int j = 0; j < _height; j++) { - _height = inputs.Length; - _width = inputs.Max(input => input.Length); - _map = new char[_width, _height]; - _entities = new List(); - for (int j = 0; j < _height; j++) + for (int i = 0; i < _width; i++) { - for (int i = 0; i < _width; i++) + if (i >= (inputs[j].Length)) { break; } + char cell = inputs[j][i]; + if (cell == '.') { - if (i >= (inputs[j].Length)) { break; } - char cell = inputs[j][i]; - if (cell == '.') - { - _map[i, j] = '.'; - } - else if (cell == '#') - { - _map[i, j] = '#'; - } - else if (cell == 'E') - { - _entities.Add(new Entity - { - Type = EntityType.Elf, - X = i, - Y = j, - }); - _map[i, j] = 'E'; - } - else if (cell == 'G') - { - _entities.Add(new Entity - { - Type = EntityType.Goblin, - X = i, - Y = j, - }); - _map[i, j] = 'G'; - } + _map[i, j] = '.'; } - } - _search = new BreadthFirstSearchGrid(_width, _height); - _rounds = 0; - } - - private IEnumerable GetOrderedEntities() - { - return _entities - .Where(e => e.IsAlive()) - .OrderBy(e => e.Y) - .ThenBy(e => e.X); - } - - public IEnumerable GetTargetEntities(Entity entity) - { - return _entities - .Where(e => e.IsAlive() && e.Type != entity.Type) - .OrderBy(e => e.Y) - .ThenBy(e => e.X); - } - - public Entity GetBestInRangeTarget(Entity entity, IEnumerable targets) - { - return targets - .Where(e => entity.InRangeOf(e)) - .OrderBy(e => e.Health) - .ThenBy(e => e.Y) - .ThenBy(e => e.X) - .FirstOrDefault(); - } - - private void AddTarget(List targets, int targetX, int targetY, int priority, Entity entity) - { - if (targetX >= 0 && targetX < _width && targetY >= 0 && targetY < _height && _map[targetX, targetY] == '.') - { - int distance = _search.QueryDistance(targetX, targetY); - if (distance >= 0) + else if (cell == '#') { - targets.Add(new Target + _map[i, j] = '#'; + } + else if (cell == 'E') + { + _entities.Add(new Entity { - X = targetX, - Y = targetY, - Distance = distance, - Priority = priority, - Entity = entity, + Type = EntityType.Elf, + X = i, + Y = j, }); + _map[i, j] = 'E'; + } + else if (cell == 'G') + { + _entities.Add(new Entity + { + Type = EntityType.Goblin, + X = i, + Y = j, + }); + _map[i, j] = 'G'; } } } + _search = new BreadthFirstSearchGrid(_width, _height); + _rounds = 0; + } - private void RunBattle() + private IEnumerable GetOrderedEntities() + { + return _entities + .Where(e => e.IsAlive()) + .OrderBy(e => e.Y) + .ThenBy(e => e.X); + } + + public IEnumerable GetTargetEntities(Entity entity) + { + return _entities + .Where(e => e.IsAlive() && e.Type != entity.Type) + .OrderBy(e => e.Y) + .ThenBy(e => e.X); + } + + public Entity GetBestInRangeTarget(Entity entity, IEnumerable targets) + { + return targets + .Where(e => entity.InRangeOf(e)) + .OrderBy(e => e.Health) + .ThenBy(e => e.Y) + .ThenBy(e => e.X) + .FirstOrDefault(); + } + + private void AddTarget(List targets, int targetX, int targetY, int priority, Entity entity) + { + if (targetX >= 0 && targetX < _width && targetY >= 0 && targetY < _height && _map[targetX, targetY] == '.') { - _rounds = 0; - bool running = true; - do + int distance = _search.QueryDistance(targetX, targetY); + if (distance >= 0) { - IEnumerable entities = GetOrderedEntities(); - foreach (Entity entity in entities) + targets.Add(new Target { - if (entity.IsAlive() == false) { continue; } - IEnumerable entitiesTargets = GetTargetEntities(entity); - if (entitiesTargets.Any() == false) - { - running = false; - break; - } - - // Attack - Entity targetInRange = GetBestInRangeTarget(entity, entitiesTargets); - if (targetInRange != null) - { - entity.Attack(_map, targetInRange); - continue; - } - - // Move - _search.SearchCharGrid(_map, '.', entity.X, entity.Y); - List targets = new List(); - int priority = 0; - foreach (Entity entityTarget in entitiesTargets) - { - AddTarget(targets, entityTarget.X, entityTarget.Y - 1, priority++, entityTarget); - AddTarget(targets, entityTarget.X - 1, entityTarget.Y, priority++, entityTarget); - AddTarget(targets, entityTarget.X + 1, entityTarget.Y, priority++, entityTarget); - AddTarget(targets, entityTarget.X, entityTarget.Y + 1, priority++, entityTarget); - } - Target bestTarget = targets.OrderBy(t => t.Distance).ThenBy(t => t.Priority).FirstOrDefault(); - if (bestTarget != null) - { - _search.SearchCharGrid(_map, '.', bestTarget.X, bestTarget.Y); - targets.Clear(); - Target dirTarget; - - dirTarget = new Target { X = entity.X, Y = entity.Y - 1, Priority = 0, }; - dirTarget.Distance = _search.QueryDistance(dirTarget.X, dirTarget.Y); - if (dirTarget.Distance >= 0) targets.Add(dirTarget); - - dirTarget = new Target { X = entity.X - 1, Y = entity.Y, Priority = 1, }; - dirTarget.Distance = _search.QueryDistance(dirTarget.X, dirTarget.Y); - if (dirTarget.Distance >= 0) targets.Add(dirTarget); - - dirTarget = new Target { X = entity.X + 1, Y = entity.Y, Priority = 2, }; - dirTarget.Distance = _search.QueryDistance(dirTarget.X, dirTarget.Y); - if (dirTarget.Distance >= 0) targets.Add(dirTarget); - - dirTarget = new Target { X = entity.X, Y = entity.Y + 1, Priority = 3, }; - dirTarget.Distance = _search.QueryDistance(dirTarget.X, dirTarget.Y); - if (dirTarget.Distance >= 0) targets.Add(dirTarget); - - Target finalTarget = targets - .OrderBy(t => t.Distance) - .ThenBy(t => t.Priority) - .FirstOrDefault(); - if (finalTarget == null) - { - throw new Exception("No possible direction"); - } - - entity.MoveTo(_map, finalTarget.X, finalTarget.Y); - - // Attack - Entity targetInRangeAfterMove = GetBestInRangeTarget(entity, entitiesTargets); - if (targetInRangeAfterMove != null) - { - entity.Attack(_map, targetInRangeAfterMove); - continue; - } - } - } - if(running == false) { break; } - _rounds++; - if (Show) { PrintBattlefield(); } - } while (running); - if (Show) { PrintBattlefield(); } - } - - private void PrintBattlefield() - { - Console.WriteLine(); - Console.WriteLine("Round: {0}", _rounds); - for (int j = 0; j < _height; j++) - { - for (int i = 0; i < _width; i++) - { - Console.Write(_map[i, j]); - } - IEnumerable entitiesOnLine = _entities.Where(e => e.IsAlive() && e.Y == j).OrderBy(e => e.X); - foreach (Entity entity in entitiesOnLine) - { - Console.Write(" {0}({1})", (entity.Type == EntityType.Elf) ? 'E' : 'G', entity.Health); - } - Console.WriteLine(); - } - } - - public string ResolvePart1(string[] inputs) - { - Entity.ElfAttackPower = 3; - Init(inputs); - RunBattle(); - int totalHealth = _entities.Where(e => e.IsAlive()).Sum(e => e.Health); - int result = totalHealth * _rounds; - return result.ToString(); - } - - public string ResolvePart2(string[] inputs) - { - Entity.ElfAttackPower = 3; - Init(inputs); - PrintBattlefield(); - do - { - Init(inputs); - RunBattle(); - bool isGoodOutcome = _entities - .Where(e => e.Type == EntityType.Elf) - .All(e => e.IsAlive()); - if (isGoodOutcome) { break; } - Entity.ElfAttackPower++; - } while (true); - Console.WriteLine("ElfAttackPower: {0}", Entity.ElfAttackPower); - PrintBattlefield(); - int totalHealth = _entities.Where(e => e.IsAlive()).Sum(e => e.Health); - int result = totalHealth * _rounds; - return result.ToString(); - } - - private class BreadthFirstSearchGrid - { - private class BFSCell - { - public bool Visited { get; set; } =false; - public BFSCell CameFrom { get; set; } = null; - public int Distance { get; set; } = -1; - public int X { get; set; } - public int Y { get; set; } - } - - private readonly BFSCell[,] _grid= null; - private readonly int _width = 0; - private readonly int _height = 0; - - public BreadthFirstSearchGrid(int width, int height) - { - _grid = new BFSCell[width, height]; - _width = width; - _height = height; - for (int j = 0; j < _height; j++) - { - for (int i = 0; i < _width; i++) - { - _grid[i, j] = new BFSCell { X = i, Y = j, }; - } - } - } - - public void Reset() - { - for(int j =0;j< _height; j++) - { - for(int i = 0; i < _width; i++) - { - BFSCell cell = _grid[i, j]; - cell.Visited = false; - cell.CameFrom = null; - cell.Distance = -1; - } - } - } - - private void ProcessCell(char[,] grid, char empty, Queue frontier, BFSCell current, int nextX, int nextY) - { - if (nextX < 0 || nextX >= _width || nextY < 0 || nextY >= _height) { return; } - if (grid[nextX, nextY] == empty || current== null) - { - BFSCell cell = _grid[nextX, nextY]; - if (cell.Visited == false) - { - frontier.Enqueue(cell); - cell.Visited = true; - cell.Distance = (current?.Distance ?? -1) + 1; - cell.CameFrom = current; - } - } - } - - public void SearchCharGrid(char[,] grid, char empty, int x, int y) - { - Reset(); - Queue frontier = new Queue(); - ProcessCell(grid, empty, frontier, null, x, y); - while (frontier.Any()) - { - BFSCell current = frontier.Dequeue(); - ProcessCell(grid, empty, frontier, current, current.X + 1, current.Y); - ProcessCell(grid, empty, frontier, current, current.X - 1, current.Y); - ProcessCell(grid, empty, frontier, current, current.X, current.Y + 1); - ProcessCell(grid, empty, frontier, current, current.X, current.Y - 1); - } - } - - public int QueryDistance(int x, int y) - { - if (x < 0 || x >= _width || y < 0 || y >= _height) { return -1; } - BFSCell cell = _grid[x, y]; - return cell.Distance; + X = targetX, + Y = targetY, + Distance = distance, + Priority = priority, + Entity = entity, + }); } } } -} + + private void RunBattle() + { + _rounds = 0; + bool running = true; + do + { + IEnumerable entities = GetOrderedEntities(); + foreach (Entity entity in entities) + { + if (entity.IsAlive() == false) { continue; } + IEnumerable entitiesTargets = GetTargetEntities(entity); + if (entitiesTargets.Any() == false) + { + running = false; + break; + } + + // Attack + Entity targetInRange = GetBestInRangeTarget(entity, entitiesTargets); + if (targetInRange != null) + { + entity.Attack(_map, targetInRange); + continue; + } + + // Move + _search.SearchCharGrid(_map, '.', entity.X, entity.Y); + List targets = new(); + int priority = 0; + foreach (Entity entityTarget in entitiesTargets) + { + AddTarget(targets, entityTarget.X, entityTarget.Y - 1, priority++, entityTarget); + AddTarget(targets, entityTarget.X - 1, entityTarget.Y, priority++, entityTarget); + AddTarget(targets, entityTarget.X + 1, entityTarget.Y, priority++, entityTarget); + AddTarget(targets, entityTarget.X, entityTarget.Y + 1, priority++, entityTarget); + } + Target bestTarget = targets.OrderBy(t => t.Distance).ThenBy(t => t.Priority).FirstOrDefault(); + if (bestTarget != null) + { + _search.SearchCharGrid(_map, '.', bestTarget.X, bestTarget.Y); + targets.Clear(); + Target dirTarget; + + dirTarget = new Target { X = entity.X, Y = entity.Y - 1, Priority = 0, }; + dirTarget.Distance = _search.QueryDistance(dirTarget.X, dirTarget.Y); + if (dirTarget.Distance >= 0) targets.Add(dirTarget); + + dirTarget = new Target { X = entity.X - 1, Y = entity.Y, Priority = 1, }; + dirTarget.Distance = _search.QueryDistance(dirTarget.X, dirTarget.Y); + if (dirTarget.Distance >= 0) targets.Add(dirTarget); + + dirTarget = new Target { X = entity.X + 1, Y = entity.Y, Priority = 2, }; + dirTarget.Distance = _search.QueryDistance(dirTarget.X, dirTarget.Y); + if (dirTarget.Distance >= 0) targets.Add(dirTarget); + + dirTarget = new Target { X = entity.X, Y = entity.Y + 1, Priority = 3, }; + dirTarget.Distance = _search.QueryDistance(dirTarget.X, dirTarget.Y); + if (dirTarget.Distance >= 0) targets.Add(dirTarget); + + Target finalTarget = targets + .OrderBy(t => t.Distance) + .ThenBy(t => t.Priority) + .FirstOrDefault(); + if (finalTarget == null) + { + throw new Exception("No possible direction"); + } + + entity.MoveTo(_map, finalTarget.X, finalTarget.Y); + + // Attack + Entity targetInRangeAfterMove = GetBestInRangeTarget(entity, entitiesTargets); + if (targetInRangeAfterMove != null) + { + entity.Attack(_map, targetInRangeAfterMove); + } + } + } + if(running == false) { break; } + _rounds++; + if (Show) { PrintBattlefield(); } + } while (running); + if (Show) { PrintBattlefield(); } + } + + private void PrintBattlefield() + { + Console.WriteLine(); + Console.WriteLine("Round: {0}", _rounds); + for (int j = 0; j < _height; j++) + { + for (int i = 0; i < _width; i++) + { + Console.Write(_map[i, j]); + } + IEnumerable entitiesOnLine = _entities.Where(e => e.IsAlive() && e.Y == j).OrderBy(e => e.X); + foreach (Entity entity in entitiesOnLine) + { + Console.Write(" {0}({1})", (entity.Type == EntityType.Elf) ? 'E' : 'G', entity.Health); + } + Console.WriteLine(); + } + } + + public string ResolvePart1(string[] inputs) + { + Entity.ElfAttackPower = 3; + Init(inputs); + RunBattle(); + int totalHealth = _entities.Where(e => e.IsAlive()).Sum(e => e.Health); + int result = totalHealth * _rounds; + return result.ToString(); + } + + public string ResolvePart2(string[] inputs) + { + Entity.ElfAttackPower = 3; + Init(inputs); + PrintBattlefield(); + do + { + Init(inputs); + RunBattle(); + bool isGoodOutcome = _entities + .Where(e => e.Type == EntityType.Elf) + .All(e => e.IsAlive()); + if (isGoodOutcome) { break; } + Entity.ElfAttackPower++; + } while (true); + Console.WriteLine("ElfAttackPower: {0}", Entity.ElfAttackPower); + PrintBattlefield(); + int totalHealth = _entities.Where(e => e.IsAlive()).Sum(e => e.Health); + int result = totalHealth * _rounds; + return result.ToString(); + } + + private class BreadthFirstSearchGrid + { + private class BFSCell + { + public bool Visited { get; set; } + public BFSCell CameFrom { get; set; } + public int Distance { get; set; } = -1; + public int X { get; set; } + public int Y { get; set; } + } + + private readonly BFSCell[,] _grid; + private readonly int _width; + private readonly int _height; + + public BreadthFirstSearchGrid(int width, int height) + { + _grid = new BFSCell[width, height]; + _width = width; + _height = height; + for (int j = 0; j < _height; j++) + { + for (int i = 0; i < _width; i++) + { + _grid[i, j] = new BFSCell { X = i, Y = j, }; + } + } + } + + public void Reset() + { + for(int j =0;j< _height; j++) + { + for(int i = 0; i < _width; i++) + { + BFSCell cell = _grid[i, j]; + cell.Visited = false; + cell.CameFrom = null; + cell.Distance = -1; + } + } + } + + private void ProcessCell(char[,] grid, char empty, Queue frontier, BFSCell current, int nextX, int nextY) + { + if (nextX < 0 || nextX >= _width || nextY < 0 || nextY >= _height) { return; } + if (grid[nextX, nextY] == empty || current== null) + { + BFSCell cell = _grid[nextX, nextY]; + if (cell.Visited == false) + { + frontier.Enqueue(cell); + cell.Visited = true; + cell.Distance = (current?.Distance ?? -1) + 1; + cell.CameFrom = current; + } + } + } + + public void SearchCharGrid(char[,] grid, char empty, int x, int y) + { + Reset(); + Queue frontier = new(); + ProcessCell(grid, empty, frontier, null, x, y); + while (frontier.Any()) + { + BFSCell current = frontier.Dequeue(); + ProcessCell(grid, empty, frontier, current, current.X + 1, current.Y); + ProcessCell(grid, empty, frontier, current, current.X - 1, current.Y); + ProcessCell(grid, empty, frontier, current, current.X, current.Y + 1); + ProcessCell(grid, empty, frontier, current, current.X, current.Y - 1); + } + } + + public int QueryDistance(int x, int y) + { + if (x < 0 || x >= _width || y < 0 || y >= _height) { return -1; } + BFSCell cell = _grid[x, y]; + return cell.Distance; + } + } +} \ No newline at end of file diff --git a/AdventOfCode2018/Day23.cs b/AdventOfCode2018/Day23.cs index ef98a02..42dffed 100644 --- a/AdventOfCode2018/Day23.cs +++ b/AdventOfCode2018/Day23.cs @@ -1,208 +1,203 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace AdventOfCode2018 +namespace AdventOfCode2018; +/* +--- Day 23: Experimental Emergency Teleportation --- + +Using your torch to search the darkness of the rocky cavern, you finally locate the man's friend: a small reindeer. + +You're not sure how it got so far in this cave. It looks sick - too sick to walk - and too heavy for you to carry all the way back. Sleighs won't be invented for another 1500 years, of course. + +The only option is experimental emergency teleportation. + +You hit the "experimental emergency teleportation" button on the device and push I accept the risk on no fewer than 18 different warning messages. Immediately, the device deploys hundreds of tiny nanobots which fly around the cavern, apparently assembling themselves into a very specific formation. The device lists the X,Y,Z position (pos) for each nanobot as well as its signal radius (r) on its tiny screen (your puzzle input). + +Each nanobot can transmit signals to any integer coordinate which is a distance away from it less than or equal to its signal radius (as measured by Manhattan distance). Coordinates a distance away of less than or equal to a nanobot's signal radius are said to be in range of that nanobot. + +Before you start the teleportation process, you should determine which nanobot is the strongest (that is, which has the largest signal radius) and then, for that nanobot, the total number of nanobots that are in range of it, including itself. + +For example, given the following nanobots: + +pos=<0,0,0>, r=4 +pos=<1,0,0>, r=1 +pos=<4,0,0>, r=3 +pos=<0,2,0>, r=1 +pos=<0,5,0>, r=3 +pos=<0,0,3>, r=1 +pos=<1,1,1>, r=1 +pos=<1,1,2>, r=1 +pos=<1,3,1>, r=1 + +The strongest nanobot is the first one (position 0,0,0) because its signal radius, 4 is the largest. Using that nanobot's location and signal radius, the following nanobots are in or out of range: + + The nanobot at 0,0,0 is distance 0 away, and so it is in range. + The nanobot at 1,0,0 is distance 1 away, and so it is in range. + The nanobot at 4,0,0 is distance 4 away, and so it is in range. + The nanobot at 0,2,0 is distance 2 away, and so it is in range. + The nanobot at 0,5,0 is distance 5 away, and so it is not in range. + The nanobot at 0,0,3 is distance 3 away, and so it is in range. + The nanobot at 1,1,1 is distance 3 away, and so it is in range. + The nanobot at 1,1,2 is distance 4 away, and so it is in range. + The nanobot at 1,3,1 is distance 5 away, and so it is not in range. + +In this example, in total, 7 nanobots are in range of the nanobot with the largest signal radius. + +Find the nanobot with the largest signal radius. How many nanobots are in range of its signals? + +--- Part Two --- + +Now, you just need to figure out where to position yourself so that you're actually teleported when the nanobots activate. + +To increase the probability of success, you need to find the coordinate which puts you in range of the largest number of nanobots. If there are multiple, choose one closest to your position (0,0,0, measured by manhattan distance). + +For example, given the following nanobot formation: + +pos=<10,12,12>, r=2 +pos=<12,14,12>, r=2 +pos=<16,12,12>, r=4 +pos=<14,14,14>, r=6 +pos=<50,50,50>, r=200 +pos=<10,10,10>, r=5 + +Many coordinates are in range of some of the nanobots in this formation. However, only the coordinate 12,12,12 is in range of the most nanobots: it is in range of the first five, but is not in range of the nanobot at 10,10,10. (All other coordinates are in range of fewer than five nanobots.) This coordinate's distance from 0,0,0 is 36. + +Find the coordinates that are in range of the largest number of nanobots. What is the shortest manhattan distance between any of those points and 0,0,0? + +*/ + +public class Day23 : IDay { - /* - --- Day 23: Experimental Emergency Teleportation --- - - Using your torch to search the darkness of the rocky cavern, you finally locate the man's friend: a small reindeer. - - You're not sure how it got so far in this cave. It looks sick - too sick to walk - and too heavy for you to carry all the way back. Sleighs won't be invented for another 1500 years, of course. - - The only option is experimental emergency teleportation. - - You hit the "experimental emergency teleportation" button on the device and push I accept the risk on no fewer than 18 different warning messages. Immediately, the device deploys hundreds of tiny nanobots which fly around the cavern, apparently assembling themselves into a very specific formation. The device lists the X,Y,Z position (pos) for each nanobot as well as its signal radius (r) on its tiny screen (your puzzle input). - - Each nanobot can transmit signals to any integer coordinate which is a distance away from it less than or equal to its signal radius (as measured by Manhattan distance). Coordinates a distance away of less than or equal to a nanobot's signal radius are said to be in range of that nanobot. - - Before you start the teleportation process, you should determine which nanobot is the strongest (that is, which has the largest signal radius) and then, for that nanobot, the total number of nanobots that are in range of it, including itself. - - For example, given the following nanobots: - - pos=<0,0,0>, r=4 - pos=<1,0,0>, r=1 - pos=<4,0,0>, r=3 - pos=<0,2,0>, r=1 - pos=<0,5,0>, r=3 - pos=<0,0,3>, r=1 - pos=<1,1,1>, r=1 - pos=<1,1,2>, r=1 - pos=<1,3,1>, r=1 - - The strongest nanobot is the first one (position 0,0,0) because its signal radius, 4 is the largest. Using that nanobot's location and signal radius, the following nanobots are in or out of range: - - The nanobot at 0,0,0 is distance 0 away, and so it is in range. - The nanobot at 1,0,0 is distance 1 away, and so it is in range. - The nanobot at 4,0,0 is distance 4 away, and so it is in range. - The nanobot at 0,2,0 is distance 2 away, and so it is in range. - The nanobot at 0,5,0 is distance 5 away, and so it is not in range. - The nanobot at 0,0,3 is distance 3 away, and so it is in range. - The nanobot at 1,1,1 is distance 3 away, and so it is in range. - The nanobot at 1,1,2 is distance 4 away, and so it is in range. - The nanobot at 1,3,1 is distance 5 away, and so it is not in range. - - In this example, in total, 7 nanobots are in range of the nanobot with the largest signal radius. - - Find the nanobot with the largest signal radius. How many nanobots are in range of its signals? - - --- Part Two --- - - Now, you just need to figure out where to position yourself so that you're actually teleported when the nanobots activate. - - To increase the probability of success, you need to find the coordinate which puts you in range of the largest number of nanobots. If there are multiple, choose one closest to your position (0,0,0, measured by manhattan distance). - - For example, given the following nanobot formation: - - pos=<10,12,12>, r=2 - pos=<12,14,12>, r=2 - pos=<16,12,12>, r=4 - pos=<14,14,14>, r=6 - pos=<50,50,50>, r=200 - pos=<10,10,10>, r=5 - - Many coordinates are in range of some of the nanobots in this formation. However, only the coordinate 12,12,12 is in range of the most nanobots: it is in range of the first five, but is not in range of the nanobot at 10,10,10. (All other coordinates are in range of fewer than five nanobots.) This coordinate's distance from 0,0,0 is 36. - - Find the coordinates that are in range of the largest number of nanobots. What is the shortest manhattan distance between any of those points and 0,0,0? - - */ - - public class Day23 : IDay + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) + List nanoBots = NanoBot.ListFromStrings(inputs); + NanoBot bestNanoBot = nanoBots.OrderBy(nanoBot => nanoBot.Range).LastOrDefault(); + int countInRange = nanoBots.Where(nanoBot => bestNanoBot.InRange(nanoBot)).Count(); + return countInRange.ToString(); + } + + public string ResolvePart2(string[] inputs) + { + List nanoBots = NanoBot.ListFromStrings(inputs); + long maxX = long.MinValue; + long maxY = long.MinValue; + long maxZ = long.MinValue; + long minX = long.MaxValue; + long minY = long.MaxValue; + long minZ = long.MaxValue; + foreach(NanoBot nanoBot in nanoBots) { - List nanoBots = NanoBot.ListFromStrings(inputs); - NanoBot bestNanoBot = nanoBots.OrderBy(nanoBot => nanoBot.Range).LastOrDefault(); - int countInRange = nanoBots.Where(nanoBot => bestNanoBot.InRange(nanoBot)).Count(); - return countInRange.ToString(); + if (nanoBot.X < minX) { minX = nanoBot.X; } + if (nanoBot.X > maxX) { maxX = nanoBot.X; } + if (nanoBot.Y < minY) { minY = nanoBot.Y; } + if (nanoBot.Y > maxY) { maxY = nanoBot.Y; } + if (nanoBot.Z < minZ) { minZ = nanoBot.Z; } + if (nanoBot.Z > maxZ) { maxZ = nanoBot.Z; } } - - public string ResolvePart2(string[] inputs) - { - List nanoBots = NanoBot.ListFromStrings(inputs); - long maxX = long.MinValue; - long maxY = long.MinValue; - long maxZ = long.MinValue; - long minX = long.MaxValue; - long minY = long.MaxValue; - long minZ = long.MaxValue; - foreach(NanoBot nanoBot in nanoBots) - { - if (nanoBot.X < minX) { minX = nanoBot.X; } - if (nanoBot.X > maxX) { maxX = nanoBot.X; } - if (nanoBot.Y < minY) { minY = nanoBot.Y; } - if (nanoBot.Y > maxY) { maxY = nanoBot.Y; } - if (nanoBot.Z < minZ) { minZ = nanoBot.Z; } - if (nanoBot.Z > maxZ) { maxZ = nanoBot.Z; } - } - long sizeX = maxX - minX; - long sizeY = maxY - minY; - long sizeZ = maxZ - minZ; - long scale = Math.Min(sizeX, Math.Min(sizeY, sizeZ)); + long sizeX = maxX - minX; + long sizeY = maxY - minY; + long sizeZ = maxZ - minZ; + long scale = Math.Min(sizeX, Math.Min(sizeY, sizeZ)); - do - { - scale /= 2; - if (scale <= 0) { scale = 1; } + do + { + scale /= 2; + if (scale <= 0) { scale = 1; } - long bestX = 0; - long bestY = 0; - long bestZ = 0; - long bestCount = 0; - for (long k = minZ; k <= maxZ; k += scale) + long bestX = 0; + long bestY = 0; + long bestZ = 0; + long bestCount = 0; + for (long k = minZ; k <= maxZ; k += scale) + { + for (long j = minY; j <= maxY; j += scale) { - for (long j = minY; j <= maxY; j += scale) + for (long i = minX; i <= maxX; i += scale) { - for (long i = minX; i <= maxX; i += scale) + int count = 0; + foreach(NanoBot nanoBot in nanoBots) { - int count = 0; - foreach(NanoBot nanoBot in nanoBots) - { - if (nanoBot.InRange(i, j, k, scale)) { count++; } - } - if(count> bestCount) - { - bestX = i; - bestY = j; - bestZ = k; - bestCount = count; - } + if (nanoBot.InRange(i, j, k, scale)) { count++; } + } + if(count> bestCount) + { + bestX = i; + bestY = j; + bestZ = k; + bestCount = count; } } } + } - minX = bestX - scale; - maxX = bestX + scale; - minY = bestY - scale; - maxY = bestY + scale; - minZ = bestZ - scale; - maxZ = bestZ + scale; + minX = bestX - scale; + maxX = bestX + scale; + minY = bestY - scale; + maxY = bestY + scale; + minZ = bestZ - scale; + maxZ = bestZ + scale; - if(scale == 1) - { - long distance = bestX + bestY + bestZ; - return distance.ToString(); - } + if(scale == 1) + { + long distance = bestX + bestY + bestZ; + return distance.ToString(); + } - } while (true); + } while (true); + } + + public class NanoBot + { + public long X { get; set; } + public long Y { get; set; } + public long Z { get; set; } + public long Range { get; set; } + + public static NanoBot FromString(string strInput) + { + string[] parts = strInput.Split(new[] { "pos=<", ",", ">, r=", }, StringSplitOptions.RemoveEmptyEntries); + if (parts.Length != 4) { return null; } + NanoBot nanoBot = new() { + X = Convert.ToInt64(parts[0]), + Y = Convert.ToInt64(parts[1]), + Z = Convert.ToInt64(parts[2]), + Range = Convert.ToInt64(parts[3]), + }; + return nanoBot; } - public class NanoBot + public static List ListFromStrings(string[] inputs) { - public long X { get; set; } - public long Y { get; set; } - public long Z { get; set; } - public long Range { get; set; } + List nanoBots = inputs + .Select(strInput => FromString(strInput)) + .Where(nanoBot => nanoBot != null) + .ToList(); + return nanoBots; + } - public static NanoBot FromString(string strInput) - { - string[] parts = strInput.Split(new string[] { "pos=<", ",", ">, r=", }, StringSplitOptions.RemoveEmptyEntries); - if (parts.Length != 4) { return null; } - NanoBot nanoBot = new NanoBot - { - X = Convert.ToInt64(parts[0]), - Y = Convert.ToInt64(parts[1]), - Z = Convert.ToInt64(parts[2]), - Range = Convert.ToInt64(parts[3]), - }; - return nanoBot; - } + public long ManhattanDistance(NanoBot other) + { + return ManhattanDistance(other.X, other.Y, other.Z); + } - public static List ListFromStrings(string[] inputs) - { - List nanoBots = inputs - .Select(strInput => FromString(strInput)) - .Where(nanoBot => nanoBot != null) - .ToList(); - return nanoBots; - } + public long ManhattanDistance(long x, long y, long z) + { + long distance = Math.Abs(X - x) + Math.Abs(Y - y) + Math.Abs(Z - z); + return distance; + } - public long ManhattanDistance(NanoBot other) - { - return ManhattanDistance(other.X, other.Y, other.Z); - } + public bool InRange(NanoBot other) + { + long distance = ManhattanDistance(other); + return distance <= Range; + } - public long ManhattanDistance(long x, long y, long z) - { - long distance = Math.Abs(X - x) + Math.Abs(Y - y) + Math.Abs(Z - z); - return distance; - } - - public bool InRange(NanoBot other) - { - long distance = ManhattanDistance(other); - return distance <= Range; - } - - public bool InRange(long x, long y, long z, long scale) - { - long distance = (long)Math.Ceiling(ManhattanDistance(x, y, z) / (double)scale); - long range = (long)Math.Ceiling(Range / (double)scale); - return distance <= range; - } + public bool InRange(long x, long y, long z, long scale) + { + long distance = (long)Math.Ceiling(ManhattanDistance(x, y, z) / (double)scale); + long range = (long)Math.Ceiling(Range / (double)scale); + return distance <= range; } } -} +} \ No newline at end of file diff --git a/AdventOfCode2018/IDay.cs b/AdventOfCode2018/IDay.cs index 76d78e3..34c0cf5 100644 --- a/AdventOfCode2018/IDay.cs +++ b/AdventOfCode2018/IDay.cs @@ -1,8 +1,7 @@ -namespace AdventOfCode2018 +namespace AdventOfCode2018; + +public interface IDay { - public interface IDay - { - string ResolvePart1(string[] inputs); - string ResolvePart2(string[] inputs); - } + string ResolvePart1(string[] inputs); + string ResolvePart2(string[] inputs); } \ No newline at end of file diff --git a/AdventOfCode2018/Program.cs b/AdventOfCode2018/Program.cs index b0d4ea8..e1a4147 100644 --- a/AdventOfCode2018/Program.cs +++ b/AdventOfCode2018/Program.cs @@ -1,42 +1,41 @@ using System; using System.IO; -namespace AdventOfCode2018 +namespace AdventOfCode2018; + +internal class Program { - internal class Program + private static void Main() { - private static void Main(string[] args) + int currentDayNumber = 15; + IDay currentDay = null; + + switch (currentDayNumber) { - int currentDayNumber = 15; - IDay currentDay = null; - - switch (currentDayNumber) - { - case 1: currentDay = new Day01(); break; - case 2: currentDay = new Day02(); break; - case 3: currentDay = new Day03(); break; - case 4: currentDay = new Day04(); break; - case 5: currentDay = new Day05(); break; - case 6: currentDay = new Day06(); break; - case 7: currentDay = new Day07(); break; - case 8: currentDay = new Day08(); break; - case 9: currentDay = new Day09(); break; - case 10: currentDay = new Day10(); break; - case 11: currentDay = new Day11(); break; - case 12: currentDay = new Day12(); break; - case 13: currentDay = new Day13(); break; - case 14: currentDay = new Day14(); break; - case 15: currentDay = new Day15(); break; - case 23: currentDay = new Day23(); break; - } - - string[] linesDay = File.ReadAllLines(string.Format("inputs/Day{0:00}.txt", currentDayNumber)); - string resultPart1 = currentDay.ResolvePart1(linesDay); - Console.WriteLine("Day{1:00} Result Part1: {0}", resultPart1, currentDayNumber); - string resultPart2 = currentDay.ResolvePart2(linesDay); - Console.WriteLine("Day{1:00} Result Part2: {0}", resultPart2, currentDayNumber); - - Console.Read(); + case 1: currentDay = new Day01(); break; + case 2: currentDay = new Day02(); break; + case 3: currentDay = new Day03(); break; + case 4: currentDay = new Day04(); break; + case 5: currentDay = new Day05(); break; + case 6: currentDay = new Day06(); break; + case 7: currentDay = new Day07(); break; + case 8: currentDay = new Day08(); break; + case 9: currentDay = new Day09(); break; + case 10: currentDay = new Day10(); break; + case 11: currentDay = new Day11(); break; + case 12: currentDay = new Day12(); break; + case 13: currentDay = new Day13(); break; + case 14: currentDay = new Day14(); break; + case 15: currentDay = new Day15(); break; + case 23: currentDay = new Day23(); break; } + + string[] linesDay = File.ReadAllLines($"inputs/Day{currentDayNumber:00}.txt"); + string resultPart1 = currentDay.ResolvePart1(linesDay); + Console.WriteLine("Day{1:00} Result Part1: {0}", resultPart1, currentDayNumber); + string resultPart2 = currentDay.ResolvePart2(linesDay); + Console.WriteLine("Day{1:00} Result Part2: {0}", resultPart2, currentDayNumber); + + Console.Read(); } -} +} \ No newline at end of file diff --git a/AdventOfCode2020.Tests/Day01_Tests.cs b/AdventOfCode2020.Tests/Day01_Tests.cs index 5809fae..42c1f83 100644 --- a/AdventOfCode2020.Tests/Day01_Tests.cs +++ b/AdventOfCode2020.Tests/Day01_Tests.cs @@ -1,49 +1,46 @@ -using Xunit; +namespace AdventOfCode2020.Tests; -namespace AdventOfCode2020.Tests +public class Day01_Tests { - public class Day01_Tests + #region ResolvePart1 + + [Fact] + public void ResolvePart1__Example() { - #region ResolvePart1 + var day = new Day01(); - [Fact] - public void ResolvePart1__Example() - { - var day = new Day01(); + string result = day.ResolvePart1(new[] { + "1721", + "979", + "366", + "299", + "675", + "1456", + }); - string result = day.ResolvePart1(new string[] { - "1721", - "979", - "366", - "299", - "675", - "1456", - }); - - Assert.Equal("514579", result); - } - - #endregion ResolvePart1 - - #region ResolvePart2 - - [Fact] - public void ResolvePart2__Example() - { - var day = new Day01(); - - string result = day.ResolvePart2(new string[] { - "1721", - "979", - "366", - "299", - "675", - "1456", - }); - - Assert.Equal("241861950", result); - } - - #endregion ResolvePart2 + Assert.Equal("514579", result); } + + #endregion ResolvePart1 + + #region ResolvePart2 + + [Fact] + public void ResolvePart2__Example() + { + var day = new Day01(); + + string result = day.ResolvePart2(new[] { + "1721", + "979", + "366", + "299", + "675", + "1456", + }); + + Assert.Equal("241861950", result); + } + + #endregion ResolvePart2 } \ No newline at end of file diff --git a/AdventOfCode2020.Tests/Day02_Tests.cs b/AdventOfCode2020.Tests/Day02_Tests.cs index 0c8033c..60b6a8e 100644 --- a/AdventOfCode2020.Tests/Day02_Tests.cs +++ b/AdventOfCode2020.Tests/Day02_Tests.cs @@ -1,43 +1,40 @@ -using Xunit; +namespace AdventOfCode2020.Tests; -namespace AdventOfCode2020.Tests +public class Day02_Tests { - public class Day02_Tests + #region ResolvePart1 + + [Fact] + public void ResolvePart1__Example() { - #region ResolvePart1 + var day = new Day02(); - [Fact] - public void ResolvePart1__Example() - { - var day = new Day02(); + string result = day.ResolvePart1(new[] { + "1-3 a: abcde", + "1-3 b: cdefg", + "2-9 c: ccccccccc", + }); - string result = day.ResolvePart1(new string[] { - "1-3 a: abcde", - "1-3 b: cdefg", - "2-9 c: ccccccccc", - }); - - Assert.Equal("2", result); - } - - #endregion ResolvePart1 - - #region ResolvePart2 - - [Fact] - public void ResolvePart2__Example() - { - var day = new Day02(); - - string result = day.ResolvePart2(new string[] { - "1-3 a: abcde", - "1-3 b: cdefg", - "2-9 c: ccccccccc", - }); - - Assert.Equal("1", result); - } - - #endregion ResolvePart1 + Assert.Equal("2", result); } + + #endregion ResolvePart1 + + #region ResolvePart2 + + [Fact] + public void ResolvePart2__Example() + { + var day = new Day02(); + + string result = day.ResolvePart2(new[] { + "1-3 a: abcde", + "1-3 b: cdefg", + "2-9 c: ccccccccc", + }); + + Assert.Equal("1", result); + } + + #endregion ResolvePart1 } \ No newline at end of file diff --git a/AdventOfCode2020.Tests/Day03_Tests.cs b/AdventOfCode2020.Tests/Day03_Tests.cs index bd11e8a..474eee5 100644 --- a/AdventOfCode2020.Tests/Day03_Tests.cs +++ b/AdventOfCode2020.Tests/Day03_Tests.cs @@ -1,51 +1,48 @@ -using Xunit; +namespace AdventOfCode2020.Tests; -namespace AdventOfCode2020.Tests +public class Day03_Tests { - public class Day03_Tests + [Fact] + public void ResolvePart1__Example() { - [Fact] - public void ResolvePart1__Example() - { - var day = new Day03(); + var day = new Day03(); - string result = day.ResolvePart1(new string[] { - "..##.......", - "#...#...#..", - ".#....#..#.", - "..#.#...#.#", - ".#...##..#.", - "..#.##.....", - ".#.#.#....#", - ".#........#", - "#.##...#...", - "#...##....#", - ".#..#...#.#", - }); + string result = day.ResolvePart1(new[] { + "..##.......", + "#...#...#..", + ".#....#..#.", + "..#.#...#.#", + ".#...##..#.", + "..#.##.....", + ".#.#.#....#", + ".#........#", + "#.##...#...", + "#...##....#", + ".#..#...#.#", + }); - Assert.Equal("7", result); - } + Assert.Equal("7", result); + } - [Fact] - public void ResolvePart2__Example() - { - var day = new Day03(); + [Fact] + public void ResolvePart2__Example() + { + var day = new Day03(); - string result = day.ResolvePart2(new string[] { - "..##.......", - "#...#...#..", - ".#....#..#.", - "..#.#...#.#", - ".#...##..#.", - "..#.##.....", - ".#.#.#....#", - ".#........#", - "#.##...#...", - "#...##....#", - ".#..#...#.#", - }); + string result = day.ResolvePart2(new[] { + "..##.......", + "#...#...#..", + ".#....#..#.", + "..#.#...#.#", + ".#...##..#.", + "..#.##.....", + ".#.#.#....#", + ".#........#", + "#.##...#...", + "#...##....#", + ".#..#...#.#", + }); - Assert.Equal("336", result); - } + Assert.Equal("336", result); } } \ No newline at end of file diff --git a/AdventOfCode2020.Tests/Day04_Tests.cs b/AdventOfCode2020.Tests/Day04_Tests.cs index 2ef625b..5ec0da9 100644 --- a/AdventOfCode2020.Tests/Day04_Tests.cs +++ b/AdventOfCode2020.Tests/Day04_Tests.cs @@ -1,78 +1,75 @@ -using Xunit; +namespace AdventOfCode2020.Tests; -namespace AdventOfCode2020.Tests +public class Day04_Tests { - public class Day04_Tests + [Fact] + public void ResolvePart1__Example() { - [Fact] - public void ResolvePart1__Example() - { - var day = new Day04(); + var day = new Day04(); - string result = day.ResolvePart1(new string[] { - "ecl:gry pid:860033327 eyr:2020 hcl:#fffffd", - "byr:1937 iyr:2017 cid:147 hgt:183cm", - "", - "iyr:2013 ecl:amb cid:350 eyr:2023 pid:028048884", - "hcl:#cfa07d byr:1929", - "", - "hcl:#ae17e1 iyr:2013", - "eyr:2024", - "ecl:brn pid:760753108 byr:1931", - "hgt:179cm", - "", - "hcl:#cfa07d eyr:2025 pid:166559648", - "iyr:2011 ecl:brn hgt:59in", - }); + string result = day.ResolvePart1(new[] { + "ecl:gry pid:860033327 eyr:2020 hcl:#fffffd", + "byr:1937 iyr:2017 cid:147 hgt:183cm", + "", + "iyr:2013 ecl:amb cid:350 eyr:2023 pid:028048884", + "hcl:#cfa07d byr:1929", + "", + "hcl:#ae17e1 iyr:2013", + "eyr:2024", + "ecl:brn pid:760753108 byr:1931", + "hgt:179cm", + "", + "hcl:#cfa07d eyr:2025 pid:166559648", + "iyr:2011 ecl:brn hgt:59in", + }); - Assert.Equal("2", result); - } + Assert.Equal("2", result); + } - [Fact] - public void ResolvePart2__ExampleInvalid() - { - var day = new Day04(); + [Fact] + public void ResolvePart2__ExampleInvalid() + { + var day = new Day04(); - string result = day.ResolvePart2(new string[] { - "eyr:1972 cid:100", - "hcl:#18171d ecl:amb hgt:170 pid:186cm iyr:2018 byr:1926", - "", - "iyr:2019", - "hcl:#602927 eyr:1967 hgt:170cm", - "ecl:grn pid:012533040 byr:1946", - "", - "hcl:dab227 iyr:2012", - "ecl:brn hgt:182cm pid:021572410 eyr:2020 byr:1992 cid:277", - "", - "hgt:59cm ecl:zzz", - "eyr:2038 hcl:74454a iyr:2023", - "pid:3556412378 byr:2007", - }); + string result = day.ResolvePart2(new[] { + "eyr:1972 cid:100", + "hcl:#18171d ecl:amb hgt:170 pid:186cm iyr:2018 byr:1926", + "", + "iyr:2019", + "hcl:#602927 eyr:1967 hgt:170cm", + "ecl:grn pid:012533040 byr:1946", + "", + "hcl:dab227 iyr:2012", + "ecl:brn hgt:182cm pid:021572410 eyr:2020 byr:1992 cid:277", + "", + "hgt:59cm ecl:zzz", + "eyr:2038 hcl:74454a iyr:2023", + "pid:3556412378 byr:2007", + }); - Assert.Equal("0", result); - } + Assert.Equal("0", result); + } - [Fact] - public void ResolvePart2__ExampleValid() - { - var day = new Day04(); + [Fact] + public void ResolvePart2__ExampleValid() + { + var day = new Day04(); - string result = day.ResolvePart2(new string[] { - "pid:087499704 hgt:74in ecl:grn iyr:2012 eyr:2030 byr:1980", - "hcl:#623a2f", - "", - "eyr:2029 ecl:blu cid:129 byr:1989", - "iyr:2014 pid:896056539 hcl:#a97842 hgt:165cm", - "", - "hcl:#888785", - "hgt:164cm byr:2001 iyr:2015 cid:88", - "pid:545766238 ecl:hzl", - "eyr:2022", - "", - "iyr:2010 hgt:158cm hcl:#b6652a ecl:blu byr:1944 eyr:2021 pid:093154719", - }); + string result = day.ResolvePart2(new[] { + "pid:087499704 hgt:74in ecl:grn iyr:2012 eyr:2030 byr:1980", + "hcl:#623a2f", + "", + "eyr:2029 ecl:blu cid:129 byr:1989", + "iyr:2014 pid:896056539 hcl:#a97842 hgt:165cm", + "", + "hcl:#888785", + "hgt:164cm byr:2001 iyr:2015 cid:88", + "pid:545766238 ecl:hzl", + "eyr:2022", + "", + "iyr:2010 hgt:158cm hcl:#b6652a ecl:blu byr:1944 eyr:2021 pid:093154719", + }); - Assert.Equal("4", result); - } + Assert.Equal("4", result); } } \ No newline at end of file diff --git a/AdventOfCode2020.Tests/Day05_Tests.cs b/AdventOfCode2020.Tests/Day05_Tests.cs index a9abf4d..d2de686 100644 --- a/AdventOfCode2020.Tests/Day05_Tests.cs +++ b/AdventOfCode2020.Tests/Day05_Tests.cs @@ -1,55 +1,52 @@ -using Xunit; +namespace AdventOfCode2020.Tests; -namespace AdventOfCode2020.Tests +public class Day05_Tests { - public class Day05_Tests + [Fact] + public void ResolvePart1__Example1() { - [Fact] - public void ResolvePart1__Example1() - { - var day = new Day05(); + var day = new Day05(); - string result = day.ResolvePart1(new string[] { - "FBFBBFFRLR", - }); + string result = day.ResolvePart1(new[] { + "FBFBBFFRLR", + }); - Assert.Equal("357", result); - } + Assert.Equal("357", result); + } - [Fact] - public void ResolvePart1__Example2() - { - var day = new Day05(); + [Fact] + public void ResolvePart1__Example2() + { + var day = new Day05(); - string result = day.ResolvePart1(new string[] { - "BFFFBBFRRR", - }); + string result = day.ResolvePart1(new[] { + "BFFFBBFRRR", + }); - Assert.Equal("567", result); - } + Assert.Equal("567", result); + } - [Fact] - public void ResolvePart1__Example3() - { - var day = new Day05(); + [Fact] + public void ResolvePart1__Example3() + { + var day = new Day05(); - string result = day.ResolvePart1(new string[] { - "FFFBBBFRRR", - }); + string result = day.ResolvePart1(new[] { + "FFFBBBFRRR", + }); - Assert.Equal("119", result); - } + Assert.Equal("119", result); + } - [Fact] - public void ResolvePart1__Example4() - { - var day = new Day05(); + [Fact] + public void ResolvePart1__Example4() + { + var day = new Day05(); - string result = day.ResolvePart1(new string[] { - "BBFFBBFRLL", - }); + string result = day.ResolvePart1(new[] { + "BBFFBBFRLL", + }); - Assert.Equal("820", result); - } + Assert.Equal("820", result); } } \ No newline at end of file diff --git a/AdventOfCode2020.Tests/Day06_Tests.cs b/AdventOfCode2020.Tests/Day06_Tests.cs index 6744172..7c7dcc4 100644 --- a/AdventOfCode2020.Tests/Day06_Tests.cs +++ b/AdventOfCode2020.Tests/Day06_Tests.cs @@ -1,59 +1,56 @@ -using Xunit; +namespace AdventOfCode2020.Tests; -namespace AdventOfCode2020.Tests +public class Day06_Tests { - public class Day06_Tests + [Fact] + public void ResolvePart1__Example() { - [Fact] - public void ResolvePart1__Example() - { - var day = new Day06(); + var day = new Day06(); - string result = day.ResolvePart1(new string[] { - "abc", - "", - "a", - "b", - "c", - "", - "ab", - "ac", - "", - "a", - "a", - "a", - "a", - "", - "b", - }); + string result = day.ResolvePart1(new[] { + "abc", + "", + "a", + "b", + "c", + "", + "ab", + "ac", + "", + "a", + "a", + "a", + "a", + "", + "b", + }); - Assert.Equal("11", result); - } + Assert.Equal("11", result); + } - [Fact] - public void ResolvePart2__Example() - { - var day = new Day06(); + [Fact] + public void ResolvePart2__Example() + { + var day = new Day06(); - string result = day.ResolvePart2(new string[] { - "abc", - "", - "a", - "b", - "c", - "", - "ab", - "ac", - "", - "a", - "a", - "a", - "a", - "", - "b", - }); + string result = day.ResolvePart2(new[] { + "abc", + "", + "a", + "b", + "c", + "", + "ab", + "ac", + "", + "a", + "a", + "a", + "a", + "", + "b", + }); - Assert.Equal("6", result); - } + Assert.Equal("6", result); } } \ No newline at end of file diff --git a/AdventOfCode2020.Tests/Day07_Tests.cs b/AdventOfCode2020.Tests/Day07_Tests.cs index 50158a6..22605c8 100644 --- a/AdventOfCode2020.Tests/Day07_Tests.cs +++ b/AdventOfCode2020.Tests/Day07_Tests.cs @@ -1,45 +1,42 @@ -using Xunit; +namespace AdventOfCode2020.Tests; -namespace AdventOfCode2020.Tests +public class Day07_Tests { - public class Day07_Tests + [Fact] + public void ResolvePart1__Example() { - [Fact] - public void ResolvePart1__Example() - { - var day = new Day07(); + var day = new Day07(); - string result = day.ResolvePart1(new string[] { - "light red bags contain 1 bright white bag, 2 muted yellow bags.", - "dark orange bags contain 3 bright white bags, 4 muted yellow bags.", - "bright white bags contain 1 shiny gold bag.", - "muted yellow bags contain 2 shiny gold bags, 9 faded blue bags.", - "shiny gold bags contain 1 dark olive bag, 2 vibrant plum bags.", - "dark olive bags contain 3 faded blue bags, 4 dotted black bags.", - "vibrant plum bags contain 5 faded blue bags, 6 dotted black bags.", - "faded blue bags contain no other bags.", - "dotted black bags contain no other bags.", - }); + string result = day.ResolvePart1(new[] { + "light red bags contain 1 bright white bag, 2 muted yellow bags.", + "dark orange bags contain 3 bright white bags, 4 muted yellow bags.", + "bright white bags contain 1 shiny gold bag.", + "muted yellow bags contain 2 shiny gold bags, 9 faded blue bags.", + "shiny gold bags contain 1 dark olive bag, 2 vibrant plum bags.", + "dark olive bags contain 3 faded blue bags, 4 dotted black bags.", + "vibrant plum bags contain 5 faded blue bags, 6 dotted black bags.", + "faded blue bags contain no other bags.", + "dotted black bags contain no other bags.", + }); - Assert.Equal("4", result); - } + Assert.Equal("4", result); + } - [Fact] - public void ResolvePart2__Example() - { - var day = new Day07(); + [Fact] + public void ResolvePart2__Example() + { + var day = new Day07(); - string result = day.ResolvePart2(new string[] { - "shiny gold bags contain 2 dark red bags.", - "dark red bags contain 2 dark orange bags.", - "dark orange bags contain 2 dark yellow bags.", - "dark yellow bags contain 2 dark green bags.", - "dark green bags contain 2 dark blue bags.", - "dark blue bags contain 2 dark violet bags.", - "dark violet bags contain no other bags.", - }); + string result = day.ResolvePart2(new[] { + "shiny gold bags contain 2 dark red bags.", + "dark red bags contain 2 dark orange bags.", + "dark orange bags contain 2 dark yellow bags.", + "dark yellow bags contain 2 dark green bags.", + "dark green bags contain 2 dark blue bags.", + "dark blue bags contain 2 dark violet bags.", + "dark violet bags contain no other bags.", + }); - Assert.Equal("126", result); - } + Assert.Equal("126", result); } } \ No newline at end of file diff --git a/AdventOfCode2020.Tests/Day08_Tests.cs b/AdventOfCode2020.Tests/Day08_Tests.cs index 20f29f3..72ec255 100644 --- a/AdventOfCode2020.Tests/Day08_Tests.cs +++ b/AdventOfCode2020.Tests/Day08_Tests.cs @@ -1,47 +1,44 @@ -using Xunit; +namespace AdventOfCode2020.Tests; -namespace AdventOfCode2020.Tests +public class Day08_Tests { - public class Day08_Tests + [Fact] + public void ResolvePart1__Example() { - [Fact] - public void ResolvePart1__Example() - { - var day = new Day08(); + var day = new Day08(); - string result = day.ResolvePart1(new string[] { - "nop +0", - "acc +1", - "jmp +4", - "acc +3", - "jmp -3", - "acc -99", - "acc +1", - "jmp -4", - "acc +6", - }); + string result = day.ResolvePart1(new[] { + "nop +0", + "acc +1", + "jmp +4", + "acc +3", + "jmp -3", + "acc -99", + "acc +1", + "jmp -4", + "acc +6", + }); - Assert.Equal("5", result); - } + Assert.Equal("5", result); + } - [Fact] - public void ResolvePart2__Example() - { - var day = new Day08(); + [Fact] + public void ResolvePart2__Example() + { + var day = new Day08(); - string result = day.ResolvePart2(new string[] { - "nop +0", - "acc +1", - "jmp +4", - "acc +3", - "jmp -3", - "acc -99", - "acc +1", - "jmp -4", - "acc +6", - }); + string result = day.ResolvePart2(new[] { + "nop +0", + "acc +1", + "jmp +4", + "acc +3", + "jmp -3", + "acc -99", + "acc +1", + "jmp -4", + "acc +6", + }); - Assert.Equal("8", result); - } + Assert.Equal("8", result); } } \ No newline at end of file diff --git a/AdventOfCode2020.Tests/Day09_Tests.cs b/AdventOfCode2020.Tests/Day09_Tests.cs index ac14953..e790065 100644 --- a/AdventOfCode2020.Tests/Day09_Tests.cs +++ b/AdventOfCode2020.Tests/Day09_Tests.cs @@ -1,69 +1,66 @@ -using Xunit; +namespace AdventOfCode2020.Tests; -namespace AdventOfCode2020.Tests +public class Day09_Tests { - public class Day09_Tests + [Fact] + public void ResolvePart1__Example() { - [Fact] - public void ResolvePart1__Example() - { - var day = new Day09(); + var day = new Day09(); - string result = day.ResolvePart1(new string[] { - "35", - "20", - "15", - "25", - "47", - "40", - "62", - "55", - "65", - "95", - "102", - "117", - "150", - "182", - "127", - "219", - "299", - "277", - "309", - "576", - }); + string result = day.ResolvePart1(new[] { + "35", + "20", + "15", + "25", + "47", + "40", + "62", + "55", + "65", + "95", + "102", + "117", + "150", + "182", + "127", + "219", + "299", + "277", + "309", + "576", + }); - Assert.Equal("127", result); - } + Assert.Equal("127", result); + } - [Fact] - public void ResolvePart2__Example() - { - var day = new Day09(); + [Fact] + public void ResolvePart2__Example() + { + var day = new Day09(); - string result = day.ResolvePart2(new string[] { - "35", - "20", - "15", - "25", - "47", - "40", - "62", - "55", - "65", - "95", - "102", - "117", - "150", - "182", - "127", - "219", - "299", - "277", - "309", - "576", - }); + string result = day.ResolvePart2(new[] { + "35", + "20", + "15", + "25", + "47", + "40", + "62", + "55", + "65", + "95", + "102", + "117", + "150", + "182", + "127", + "219", + "299", + "277", + "309", + "576", + }); - Assert.Equal("62", result); - } + Assert.Equal("62", result); } } \ No newline at end of file diff --git a/AdventOfCode2020.Tests/Day10_Tests.cs b/AdventOfCode2020.Tests/Day10_Tests.cs index a842c4b..e0cdfb4 100644 --- a/AdventOfCode2020.Tests/Day10_Tests.cs +++ b/AdventOfCode2020.Tests/Day10_Tests.cs @@ -1,45 +1,42 @@ -using Xunit; +namespace AdventOfCode2020.Tests; -namespace AdventOfCode2020.Tests +public class Day10_Tests { - public class Day10_Tests + [Fact(Skip="Not implemented")] + public void ResolvePart1__Example() { - [Fact(Skip="Not implemented")] - public void ResolvePart1__Example() - { - var day = new Day10(); + var day = new Day10(); - string result = day.ResolvePart1(new string[] { - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - }); + string result = day.ResolvePart1(new[] { + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + }); - Assert.Equal("YYY", result); - } + Assert.Equal("YYY", result); + } - [Fact(Skip="Not implemented")] - public void ResolvePart2__Example() - { - var day = new Day09(); + [Fact(Skip="Not implemented")] + public void ResolvePart2__Example() + { + var day = new Day09(); - string result = day.ResolvePart2(new string[] { - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - }); + string result = day.ResolvePart2(new[] { + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + }); - Assert.Equal("YYY", result); - } + Assert.Equal("YYY", result); } } \ No newline at end of file diff --git a/AdventOfCode2020.Tests/Day11_Tests.cs b/AdventOfCode2020.Tests/Day11_Tests.cs index 9e9bddf..14a76e3 100644 --- a/AdventOfCode2020.Tests/Day11_Tests.cs +++ b/AdventOfCode2020.Tests/Day11_Tests.cs @@ -1,45 +1,42 @@ -using Xunit; +namespace AdventOfCode2020.Tests; -namespace AdventOfCode2020.Tests +public class Day11_Tests { - public class Day11_Tests + [Fact(Skip="Not implemented")] + public void ResolvePart1__Example() { - [Fact(Skip="Not implemented")] - public void ResolvePart1__Example() - { - var day = new Day11(); + var day = new Day11(); - string result = day.ResolvePart1(new string[] { - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - }); + string result = day.ResolvePart1(new[] { + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + }); - Assert.Equal("YYY", result); - } + Assert.Equal("YYY", result); + } - [Fact(Skip="Not implemented")] - public void ResolvePart2__Example() - { - var day = new Day11(); + [Fact(Skip="Not implemented")] + public void ResolvePart2__Example() + { + var day = new Day11(); - string result = day.ResolvePart2(new string[] { - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - "XXXXXXXXXXXXXXX", - }); + string result = day.ResolvePart2(new[] { + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + "XXXXXXXXXXXXXXX", + }); - Assert.Equal("YYY", result); - } + Assert.Equal("YYY", result); } } \ No newline at end of file diff --git a/AdventOfCode2020.Tests/Usings.cs b/AdventOfCode2020.Tests/Usings.cs new file mode 100644 index 0000000..8c927eb --- /dev/null +++ b/AdventOfCode2020.Tests/Usings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file diff --git a/AdventOfCode2020/Day01.cs b/AdventOfCode2020/Day01.cs index 33177c0..3caf264 100644 --- a/AdventOfCode2020/Day01.cs +++ b/AdventOfCode2020/Day01.cs @@ -1,8 +1,8 @@ using System; -namespace AdventOfCode2020 -{ - /* +namespace AdventOfCode2020; + +/* --- Day 1: Report Repair --- After saving Christmas five years in a row, you've decided to take a vacation at a nice resort on a tropical island. Surely, Christmas will go on without you. @@ -41,49 +41,48 @@ In your expense report, what is the product of the three entries that sum to 202 - */ - public class Day01 : IDay +*/ +public class Day01 : IDay +{ + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) + int result = -1; + for (int i = 0; i < (inputs.Length - 1) && result < 0; i++) { - int result = -1; - for (int i = 0; i < (inputs.Length - 1) && result < 0; i++) + for (int j = i + 1; j < inputs.Length && result < 0; j++) { - for (int j = i + 1; j < inputs.Length && result < 0; j++) + if (string.IsNullOrEmpty(inputs[i]) || string.IsNullOrEmpty(inputs[j])) { continue; } + int numI = Convert.ToInt32(inputs[i]); + int numJ = Convert.ToInt32(inputs[j]); + if ((numI + numJ) == 2020) { - if (string.IsNullOrEmpty(inputs[i]) || string.IsNullOrEmpty(inputs[j])) { continue; } - int numI = Convert.ToInt32(inputs[i]); - int numJ = Convert.ToInt32(inputs[j]); - if ((numI + numJ) == 2020) - { - result = numI * numJ; - } + result = numI * numJ; } } - return result.ToString(); - } - - public string ResolvePart2(string[] inputs) - { - long result = -1; - for (int i = 0; i < (inputs.Length - 2) && result < 0; i++) - { - for (int j = i + 1; j < (inputs.Length - 1) && result < 0; j++) - { - for (int k = j + 1; k < inputs.Length && result < 0; k++) - { - if (string.IsNullOrEmpty(inputs[i]) || string.IsNullOrEmpty(inputs[j]) || string.IsNullOrEmpty(inputs[k])) { continue; } - long numI = Convert.ToInt64(inputs[i]); - long numJ = Convert.ToInt64(inputs[j]); - long numK = Convert.ToInt64(inputs[k]); - if ((numI + numJ + numK) == 2020) - { - result = numI * numJ * numK; - } - } - } - } - return result.ToString(); } + return result.ToString(); } -} + + public string ResolvePart2(string[] inputs) + { + long result = -1; + for (int i = 0; i < (inputs.Length - 2) && result < 0; i++) + { + for (int j = i + 1; j < (inputs.Length - 1) && result < 0; j++) + { + for (int k = j + 1; k < inputs.Length && result < 0; k++) + { + if (string.IsNullOrEmpty(inputs[i]) || string.IsNullOrEmpty(inputs[j]) || string.IsNullOrEmpty(inputs[k])) { continue; } + long numI = Convert.ToInt64(inputs[i]); + long numJ = Convert.ToInt64(inputs[j]); + long numK = Convert.ToInt64(inputs[k]); + if ((numI + numJ + numK) == 2020) + { + result = numI * numJ * numK; + } + } + } + } + return result.ToString(); + } +} \ No newline at end of file diff --git a/AdventOfCode2020/Day02.cs b/AdventOfCode2020/Day02.cs index 828122b..0ecd06f 100644 --- a/AdventOfCode2020/Day02.cs +++ b/AdventOfCode2020/Day02.cs @@ -1,9 +1,8 @@ using System; using System.Linq; -namespace AdventOfCode2020 -{ - /* +namespace AdventOfCode2020; +/* --- Day 2: Password Philosophy --- Your flight departs in a few days from the coastal airport; the easiest way down to the coast from here is via toboggan. @@ -36,57 +35,56 @@ Each policy actually describes two positions in the password, where 1 means the Given the same example list from above: - 1-3 a: abcde is valid: position 1 contains a and position 3 does not. - 1-3 b: cdefg is invalid: neither position 1 nor position 3 contains b. - 2-9 c: ccccccccc is invalid: both position 2 and position 9 contain c. +1-3 a: abcde is valid: position 1 contains a and position 3 does not. +1-3 b: cdefg is invalid: neither position 1 nor position 3 contains b. +2-9 c: ccccccccc is invalid: both position 2 and position 9 contain c. How many passwords are valid according to the new interpretation of the policies? - */ +*/ - public class Day02 : IDay +public class Day02 : IDay +{ + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) + int cntValid = 0; + + foreach (string input in inputs) { - int cntValid = 0; - - foreach (string input in inputs) - { - if (string.IsNullOrEmpty(input)) { continue; } - string[] parts = input.Split('-', ' ', ':'); - int min = Convert.ToInt32(parts[0]); - int max = Convert.ToInt32(parts[1]); - string character = parts[2]; - string password = parts[4]; - int cnt = password.Count(c => c == character[0]); - if (cnt <= max && cnt >= min) { cntValid++; } - } - - return cntValid.ToString(); + if (string.IsNullOrEmpty(input)) { continue; } + string[] parts = input.Split('-', ' ', ':'); + int min = Convert.ToInt32(parts[0]); + int max = Convert.ToInt32(parts[1]); + string character = parts[2]; + string password = parts[4]; + int cnt = password.Count(c => c == character[0]); + if (cnt <= max && cnt >= min) { cntValid++; } } - public string ResolvePart2(string[] inputs) - { - int cntValid = 0; - - foreach (string input in inputs) - { - if (string.IsNullOrEmpty(input)) { continue; } - string[] parts = input.Split('-', ' ', ':'); - int index0 = Convert.ToInt32(parts[0]); - int index1 = Convert.ToInt32(parts[1]); - string character = parts[2]; - string password = parts[4]; - if (password.Length < index0 || password.Length < index1) { continue; } - bool hasIndex0 = (password[index0 - 1] == character[0]); - bool hasIndex1 = (password[index1 - 1] == character[0]); - if ((hasIndex0 && hasIndex1) || (hasIndex0 == false && hasIndex1 == false)) { continue; } - if (hasIndex0 || hasIndex1) { cntValid++; } - } - - return cntValid.ToString(); - } + return cntValid.ToString(); } -} + + public string ResolvePart2(string[] inputs) + { + int cntValid = 0; + + foreach (string input in inputs) + { + if (string.IsNullOrEmpty(input)) { continue; } + string[] parts = input.Split('-', ' ', ':'); + int index0 = Convert.ToInt32(parts[0]); + int index1 = Convert.ToInt32(parts[1]); + string character = parts[2]; + string password = parts[4]; + if (password.Length < index0 || password.Length < index1) { continue; } + bool hasIndex0 = (password[index0 - 1] == character[0]); + bool hasIndex1 = (password[index1 - 1] == character[0]); + if ((hasIndex0 && hasIndex1) || (hasIndex0 == false && hasIndex1 == false)) { continue; } + if (hasIndex0 || hasIndex1) { cntValid++; } + } + + return cntValid.ToString(); + } +} \ No newline at end of file diff --git a/AdventOfCode2020/Day03.cs b/AdventOfCode2020/Day03.cs index 9a46e0e..0aeff6e 100644 --- a/AdventOfCode2020/Day03.cs +++ b/AdventOfCode2020/Day03.cs @@ -74,44 +74,43 @@ What do you get if you multiply together the number of trees encountered on each */ -namespace AdventOfCode2020 +namespace AdventOfCode2020; + +public class Day03 : IDay { - public class Day03 : IDay + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) - { - int treeCnt = FollowSlope(inputs, 3, 1); - return treeCnt.ToString(); - } + int treeCnt = FollowSlope(inputs, 3, 1); + return treeCnt.ToString(); + } - public string ResolvePart2(string[] inputs) - { - int treeCnt1 = FollowSlope(inputs, 1, 1); - int treeCnt2 = FollowSlope(inputs, 3, 1); - int treeCnt3 = FollowSlope(inputs, 5, 1); - int treeCnt4 = FollowSlope(inputs, 7, 1); - int treeCnt5 = FollowSlope(inputs, 1, 2); - long treeMult = treeCnt1 * treeCnt2 * treeCnt3 * treeCnt4 * treeCnt5; - return treeMult.ToString(); - } + public string ResolvePart2(string[] inputs) + { + int treeCnt1 = FollowSlope(inputs, 1, 1); + int treeCnt2 = FollowSlope(inputs, 3, 1); + int treeCnt3 = FollowSlope(inputs, 5, 1); + int treeCnt4 = FollowSlope(inputs, 7, 1); + int treeCnt5 = FollowSlope(inputs, 1, 2); + long treeMult = treeCnt1 * treeCnt2 * treeCnt3 * treeCnt4 * treeCnt5; + return treeMult.ToString(); + } - private static int FollowSlope(string[] inputs, int dx, int dy) + private static int FollowSlope(string[] inputs, int dx, int dy) + { + int x = 0; + int y = 0; + int treeCnt = 0; + x += dx; + y += dy; + while (y < inputs.Length) { - int x = 0; - int y = 0; - int treeCnt = 0; + string input = inputs[y]; + char c = input[x % input.Length]; + if (c == '#') { treeCnt++; } x += dx; y += dy; - while (y < inputs.Length) - { - string input = inputs[y]; - char c = input[x % input.Length]; - if (c == '#') { treeCnt++; } - x += dx; - y += dy; - } - return treeCnt; } - + return treeCnt; } -} + +} \ No newline at end of file diff --git a/AdventOfCode2020/Day04.cs b/AdventOfCode2020/Day04.cs index 31351a4..6e51857 100644 --- a/AdventOfCode2020/Day04.cs +++ b/AdventOfCode2020/Day04.cs @@ -124,145 +124,143 @@ Count the number of valid passports - those that have all required fields and va */ -namespace AdventOfCode2020 +namespace AdventOfCode2020; + +public class Day04 : IDay { - public class Day04 : IDay + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) - { - List> passports = Passports_Parse(inputs); - int cnt = 0; - List neededFields = new List - { - "byr", // Birth Year - "iyr", // Issue Year - "eyr", // Expiration Year - "hgt", // Height - "hcl", // Hair Color - "ecl", // Eye Color - "pid", // Passport ID - }; + List> passports = Passports_Parse(inputs); + int cnt = 0; + List neededFields = new() { + "byr", // Birth Year + "iyr", // Issue Year + "eyr", // Expiration Year + "hgt", // Height + "hcl", // Hair Color + "ecl", // Eye Color + "pid", // Passport ID + }; - foreach (Dictionary passport in passports) - { - bool valid = true; - foreach (string field in neededFields) - { - if (passport.ContainsKey(field) == false) - { - valid = false; - break; - } - } - if (valid) { cnt++; } - } - return cnt.ToString(); - } - - public string ResolvePart2(string[] inputs) + foreach (Dictionary passport in passports) { - List> passports = Passports_Parse(inputs); - int cnt = 0; - foreach (Dictionary passport in passports) + bool valid = true; + foreach (string field in neededFields) { - if (Passport_Validate(passport) == false) { continue; } - cnt++; - } - return cnt.ToString(); - } - - private List> Passports_Parse(string[] inputs) - { - List> passports = new List>(); - Dictionary passport = new Dictionary(); - foreach (string input in inputs) - { - if (string.IsNullOrEmpty(input)) + if (passport.ContainsKey(field) == false) { - if (passport.Count > 0) - { - passports.Add(passport); - passport = new Dictionary(); - } - continue; - } - string[] pairs = input.Split(' '); - foreach (string pair in pairs) - { - string[] data = pair.Split(':'); - if (passport.ContainsKey(data[0])) - { - passport[data[0]] = data[1]; - } - else - { - passport.Add(data[0], data[1]); - } + valid = false; + break; } } - if (passport.Count > 0) - { - passports.Add(passport); - } - return passports; + if (valid) { cnt++; } } - - private bool Passport_Validate(Dictionary passport) - { - if (passport.ContainsKey("byr") == false) { return false; } - int? birthYear = Year_Parse(passport["byr"]); - if (birthYear == null || birthYear < 1920 || birthYear > 2002) { return false; } - - if (passport.ContainsKey("iyr") == false) { return false; } - int? issueYear = Year_Parse(passport["iyr"]); - if (issueYear == null || issueYear < 2010 || issueYear > 2020) { return false; } - - if (passport.ContainsKey("eyr") == false) { return false; } - int? expirationYear = Year_Parse(passport["eyr"]); - if (expirationYear == null || expirationYear < 2020 || expirationYear > 2030) { return false; } - - if (passport.ContainsKey("hgt") == false) { return false; } - string strHeight = passport["hgt"]; - if (strHeight.EndsWith("cm")) - { - string strHeightCm = strHeight.Substring(0, strHeight.Length - 2); - if (strHeightCm.All(char.IsNumber) == false) { return false; } - int heightCm = Convert.ToInt32(strHeightCm); - if (heightCm < 150 || heightCm > 193) { return false; } - } - else if (strHeight.EndsWith("in")) - { - string strHeightIn = strHeight.Substring(0, strHeight.Length - 2); - if (strHeightIn.All(char.IsNumber) == false) { return false; } - int heightIn = Convert.ToInt32(strHeightIn); - if (heightIn < 59 || heightIn > 76) { return false; } - } - else { return false; } - - if (passport.ContainsKey("hcl") == false) { return false; } - string strHairColor = passport["hcl"]; - if (strHairColor.StartsWith("#") == false) { return false; } - string strHairColorHex = strHairColor.Substring(1); - if (strHairColorHex.All(c => char.IsNumber(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) == false) { return false; } - - if (passport.ContainsKey("ecl") == false) { return false; } - string strEyeColor = passport["ecl"]; - if (strEyeColor != "amb" && strEyeColor != "blu" && strEyeColor != "brn" && strEyeColor != "gry" && strEyeColor != "grn" && strEyeColor != "hzl" && strEyeColor != "oth") { return false; } - - if (passport.ContainsKey("pid") == false) { return false; } - string strPassportID = passport["pid"]; - if (strPassportID.Length != 9) { return false; } - if (strPassportID.All(char.IsNumber) == false) { return false; } - - return true; - } - - private int? Year_Parse(string input) - { - if (input.Length != 4) { return null; } - if (input.All(char.IsNumber) == false) { return null; } - return Convert.ToInt32(input); - } - + return cnt.ToString(); } -} + + public string ResolvePart2(string[] inputs) + { + List> passports = Passports_Parse(inputs); + int cnt = 0; + foreach (Dictionary passport in passports) + { + if (Passport_Validate(passport) == false) { continue; } + cnt++; + } + return cnt.ToString(); + } + + private List> Passports_Parse(string[] inputs) + { + List> passports = new(); + Dictionary passport = new(); + foreach (string input in inputs) + { + if (string.IsNullOrEmpty(input)) + { + if (passport.Count > 0) + { + passports.Add(passport); + passport = new Dictionary(); + } + continue; + } + string[] pairs = input.Split(' '); + foreach (string pair in pairs) + { + string[] data = pair.Split(':'); + if (passport.ContainsKey(data[0])) + { + passport[data[0]] = data[1]; + } + else + { + passport.Add(data[0], data[1]); + } + } + } + if (passport.Count > 0) + { + passports.Add(passport); + } + return passports; + } + + private bool Passport_Validate(Dictionary passport) + { + if (passport.ContainsKey("byr") == false) { return false; } + int? birthYear = Year_Parse(passport["byr"]); + if (birthYear == null || birthYear < 1920 || birthYear > 2002) { return false; } + + if (passport.ContainsKey("iyr") == false) { return false; } + int? issueYear = Year_Parse(passport["iyr"]); + if (issueYear == null || issueYear < 2010 || issueYear > 2020) { return false; } + + if (passport.ContainsKey("eyr") == false) { return false; } + int? expirationYear = Year_Parse(passport["eyr"]); + if (expirationYear == null || expirationYear < 2020 || expirationYear > 2030) { return false; } + + if (passport.ContainsKey("hgt") == false) { return false; } + string strHeight = passport["hgt"]; + if (strHeight.EndsWith("cm")) + { + string strHeightCm = strHeight.Substring(0, strHeight.Length - 2); + if (strHeightCm.All(char.IsNumber) == false) { return false; } + int heightCm = Convert.ToInt32(strHeightCm); + if (heightCm < 150 || heightCm > 193) { return false; } + } + else if (strHeight.EndsWith("in")) + { + string strHeightIn = strHeight.Substring(0, strHeight.Length - 2); + if (strHeightIn.All(char.IsNumber) == false) { return false; } + int heightIn = Convert.ToInt32(strHeightIn); + if (heightIn < 59 || heightIn > 76) { return false; } + } + else { return false; } + + if (passport.ContainsKey("hcl") == false) { return false; } + string strHairColor = passport["hcl"]; + if (strHairColor.StartsWith("#") == false) { return false; } + string strHairColorHex = strHairColor.Substring(1); + if (strHairColorHex.All(c => char.IsNumber(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) == false) { return false; } + + if (passport.ContainsKey("ecl") == false) { return false; } + string strEyeColor = passport["ecl"]; + if (strEyeColor != "amb" && strEyeColor != "blu" && strEyeColor != "brn" && strEyeColor != "gry" && strEyeColor != "grn" && strEyeColor != "hzl" && strEyeColor != "oth") { return false; } + + if (passport.ContainsKey("pid") == false) { return false; } + string strPassportID = passport["pid"]; + if (strPassportID.Length != 9) { return false; } + if (strPassportID.All(char.IsNumber) == false) { return false; } + + return true; + } + + private int? Year_Parse(string input) + { + if (input.Length != 4) { return null; } + if (input.All(char.IsNumber) == false) { return null; } + return Convert.ToInt32(input); + } + +} \ No newline at end of file diff --git a/AdventOfCode2020/Day05.cs b/AdventOfCode2020/Day05.cs index 1704845..42aa019 100644 --- a/AdventOfCode2020/Day05.cs +++ b/AdventOfCode2020/Day05.cs @@ -59,156 +59,155 @@ What is the ID of your seat? using System; using System.Linq; -namespace AdventOfCode2020 +namespace AdventOfCode2020; + +public class Day05 : IDay { - public class Day05 : IDay + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) + int maxSerialNumber = 0; + foreach (string input in inputs) { - int maxSerialNumber = 0; - foreach (string input in inputs) - { - Seat seat = Seat_Parse(input); - if (seat == null) { continue; } - int newSerialNumber = seat.GetSerialNumber(); - if (newSerialNumber > maxSerialNumber) { maxSerialNumber = newSerialNumber; } - } - return maxSerialNumber.ToString(); + Seat seat = Seat_Parse(input); + if (seat == null) { continue; } + int newSerialNumber = seat.GetSerialNumber(); + if (newSerialNumber > maxSerialNumber) { maxSerialNumber = newSerialNumber; } + } + return maxSerialNumber.ToString(); + } + + public string ResolvePart2(string[] inputs) + { + // Fill the seats + char[][] seats = new char[8][]; + for (int i = 0; i < 8; i++) + { + seats[i] = new char[128]; + for (int j = 0; j < 128; j++) { seats[i][j] = '.'; } + } + foreach (string input in inputs) + { + Seat seat = Seat_Parse(input); + if (seat == null) { continue; } + + seats[seat.Column][seat.Row] = 'X'; } - public string ResolvePart2(string[] inputs) + // Show seats + for (int i = 0; i < 8; i++) { - // Fill the seats - char[][] seats = new char[8][]; - for (int i = 0; i < 8; i++) + for (int j = 0; j < 128; j++) { - seats[i] = new char[128]; - for (int j = 0; j < 128; j++) { seats[i][j] = '.'; } + Console.Write(seats[i][j]); } - foreach (string input in inputs) - { - Seat seat = Seat_Parse(input); - if (seat == null) { continue; } + Console.WriteLine(); + } - seats[seat.Column][seat.Row] = 'X'; - } - - // Show seats - for (int i = 0; i < 8; i++) + // Find my seat + int mySeatSerialNumber = -1; + for (int i = 0; i < 8 && mySeatSerialNumber < 0; i++) + { + for (int j = 0; j < 128 && mySeatSerialNumber < 0; j++) { - for (int j = 0; j < 128; j++) + if (seats[i][j] == '.') { - Console.Write(seats[i][j]); - } - Console.WriteLine(); - } - - // Find my seat - int mySeatSerialNumber = -1; - for (int i = 0; i < 8 && mySeatSerialNumber < 0; i++) - { - for (int j = 0; j < 128 && mySeatSerialNumber < 0; j++) - { - if (seats[i][j] == '.') + int neighbourCount = 0; + for (int k = -1; k < 2; k++) { - int neighbourCount = 0; - for (int k = -1; k < 2; k++) + for (int l = -1; l < 2; l++) { - for (int l = -1; l < 2; l++) + int col = (i + k); + if (col < 0) { col += 8; } + if (col >= 8) { col -= 8; } + int row = (j + l); + if (row < 0) { row += 128; } + if (row >= 128) { row -= 128; } + if (seats[col][row] == 'X') { - int col = (i + k); - if (col < 0) { col += 8; } - if (col >= 8) { col -= 8; } - int row = (j + l); - if (row < 0) { row += 128; } - if (row >= 128) { row -= 128; } - if (seats[col][row] == 'X') - { - neighbourCount++; - } + neighbourCount++; } } - if (neighbourCount == 8) - { - Seat mySeat = new Seat { Row = j, Column = i, }; - mySeatSerialNumber = mySeat.GetSerialNumber(); - } + } + if (neighbourCount == 8) + { + Seat mySeat = new() { Row = j, Column = i, }; + mySeatSerialNumber = mySeat.GetSerialNumber(); } } } - return mySeatSerialNumber.ToString(); + } + return mySeatSerialNumber.ToString(); + } + + private class Range + { + public int Start { get; set; } + public int End { get; set; } + + public void SplitLeft() + { + int len = End - Start; + int half = (len + 1) / 2; + End -= half; } - private class Range + public void SplitRight() { - public int Start { get; set; } - public int End { get; set; } - - public void SplitLeft() - { - int len = End - Start; - int half = (len + 1) / 2; - End -= half; - } - - public void SplitRight() - { - int len = End - Start; - int half = (len + 1) / 2; - Start += half; - } - } - - private class Seat - { - public int Row { get; set; } - public int Column { get; set; } - - public int GetSerialNumber() - { - return (Row * 8) + Column; - } - } - - private Seat Seat_Parse(string input) - { - if (input.Length != 10 || - input.All(c => c == 'F' || c == 'B' || c == 'L' || c == 'R') == false || - false) - { - return null; - } - Seat seat = new Seat(); - - Range row = new Range { Start = 0, End = 127, }; - for (int i = 0; i < 7; i++) - { - if (input[i] == 'F') - { - row.SplitLeft(); - } - if (input[i] == 'B') - { - row.SplitRight(); - } - } - seat.Row = row.Start; - - Range column = new Range { Start = 0, End = 7, }; - for (int i = 7; i < 10; i++) - { - if (input[i] == 'L') - { - column.SplitLeft(); - } - if (input[i] == 'R') - { - column.SplitRight(); - } - } - seat.Column = column.Start; - - return seat; + int len = End - Start; + int half = (len + 1) / 2; + Start += half; } } -} + + private class Seat + { + public int Row { get; set; } + public int Column { get; set; } + + public int GetSerialNumber() + { + return (Row * 8) + Column; + } + } + + private Seat Seat_Parse(string input) + { + if (input.Length != 10 || + input.All(c => c == 'F' || c == 'B' || c == 'L' || c == 'R') == false || + false) + { + return null; + } + Seat seat = new(); + + Range row = new() { Start = 0, End = 127, }; + for (int i = 0; i < 7; i++) + { + if (input[i] == 'F') + { + row.SplitLeft(); + } + if (input[i] == 'B') + { + row.SplitRight(); + } + } + seat.Row = row.Start; + + Range column = new() { Start = 0, End = 7, }; + for (int i = 7; i < 10; i++) + { + if (input[i] == 'L') + { + column.SplitLeft(); + } + if (input[i] == 'R') + { + column.SplitRight(); + } + } + seat.Column = column.Start; + + return seat; + } +} \ No newline at end of file diff --git a/AdventOfCode2020/Day06.cs b/AdventOfCode2020/Day06.cs index 46ac871..a9ee400 100644 --- a/AdventOfCode2020/Day06.cs +++ b/AdventOfCode2020/Day06.cs @@ -52,79 +52,78 @@ For each group, count the number of questions to which anyone answered "yes". Wh */ -namespace AdventOfCode2020 -{ - public class Day06 : IDay - { - public string ResolvePart1(string[] inputs) - { - Dictionary groupMap = new Dictionary(); - List> groupMaps = new List>(); - foreach (string input in inputs) - { - if (string.IsNullOrEmpty(input) && groupMap.Count > 0) - { - groupMaps.Add(groupMap); - groupMap = new Dictionary(); - continue; - } +namespace AdventOfCode2020; - foreach (char c in input) - { - if (groupMap.ContainsKey(c) == false) - { - groupMap.Add(c, true); - } - } - } - if (groupMap.Count > 0) +public class Day06 : IDay +{ + public string ResolvePart1(string[] inputs) + { + Dictionary groupMap = new(); + List> groupMaps = new(); + foreach (string input in inputs) + { + if (string.IsNullOrEmpty(input) && groupMap.Count > 0) { groupMaps.Add(groupMap); + groupMap = new Dictionary(); + continue; } - int total = groupMaps.Sum(groupMap => groupMap.Count); - return total.ToString(); - + foreach (char c in input) + { + if (groupMap.ContainsKey(c) == false) + { + groupMap.Add(c, true); + } + } + } + if (groupMap.Count > 0) + { + groupMaps.Add(groupMap); } - public string ResolvePart2(string[] inputs) - { - int groupCount = 0; - Dictionary groupMap = new Dictionary(); - List>> groupMaps = new List>>(); - foreach (string input in inputs) - { - if (string.IsNullOrEmpty(input) && groupCount > 0) - { - groupMaps.Add(new Tuple>(groupCount, groupMap)); - groupCount = 0; - groupMap = new Dictionary(); - continue; - } + int total = groupMaps.Sum(groupMap => groupMap.Count); + return total.ToString(); - groupCount++; - foreach (char c in input) - { - if (groupMap.ContainsKey(c) == false) - { - groupMap.Add(c, 1); - } - else - { - groupMap[c] = groupMap[c] + 1; - } - } - } - if (groupCount > 0) + } + + public string ResolvePart2(string[] inputs) + { + int groupCount = 0; + Dictionary groupMap = new(); + List>> groupMaps = new(); + foreach (string input in inputs) + { + if (string.IsNullOrEmpty(input) && groupCount > 0) { groupMaps.Add(new Tuple>(groupCount, groupMap)); + groupCount = 0; + groupMap = new Dictionary(); + continue; } - int total = groupMaps.Sum(group => + groupCount++; + foreach (char c in input) { - return group.Item2.Count(p => p.Value == group.Item1); - }); - return total.ToString(); + if (groupMap.ContainsKey(c) == false) + { + groupMap.Add(c, 1); + } + else + { + groupMap[c] = groupMap[c] + 1; + } + } } + if (groupCount > 0) + { + groupMaps.Add(new Tuple>(groupCount, groupMap)); + } + + int total = groupMaps.Sum(group => + { + return group.Item2.Count(p => p.Value == group.Item1); + }); + return total.ToString(); } -} +} \ No newline at end of file diff --git a/AdventOfCode2020/Day07.cs b/AdventOfCode2020/Day07.cs index 0883b7c..184b191 100644 --- a/AdventOfCode2020/Day07.cs +++ b/AdventOfCode2020/Day07.cs @@ -68,140 +68,139 @@ How many individual bags are required inside your single shiny gold bag? */ -namespace AdventOfCode2020 +namespace AdventOfCode2020; + +public class Day07 : IDay { - public class Day07 : IDay + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) + string myBagColor = "shiny gold"; + + List rules = new(); + foreach (string input in inputs) { - string myBagColor = "shiny gold"; + BaggageRule rule = BaggageRule_Parse(input); + rules.Add(rule); + } - List rules = new List(); - foreach (string input in inputs) + List bagColorsToCheck = new() { myBagColor }; + List bagColorsChecked = new() { myBagColor }; + int cntBagColors = 0; + while (bagColorsToCheck.Count > 0) + { + string currentColor = bagColorsToCheck[0]; + bagColorsToCheck.RemoveAt(0); + + foreach (BaggageRule rule in rules) { - BaggageRule rule = BaggageRule_Parse(input); - rules.Add(rule); - } - - List bagColorsToCheck = new List { myBagColor }; - List bagColorsChecked = new List { myBagColor }; - int cntBagColors = 0; - while (bagColorsToCheck.Count > 0) - { - string currentColor = bagColorsToCheck[0]; - bagColorsToCheck.RemoveAt(0); - - foreach (BaggageRule rule in rules) + if (rule.Contain.Any(r => r.BagColor == currentColor)) { - if (rule.Contain.Any(r => r.BagColor == currentColor)) + if (bagColorsChecked.Contains(rule.BagColor) == false) { - if (bagColorsChecked.Contains(rule.BagColor) == false) - { - bagColorsToCheck.Add(rule.BagColor); - bagColorsChecked.Add(rule.BagColor); - cntBagColors++; - } + bagColorsToCheck.Add(rule.BagColor); + bagColorsChecked.Add(rule.BagColor); + cntBagColors++; } } } - - return cntBagColors.ToString(); } - public string ResolvePart2(string[] inputs) - { - string myBagColor = "shiny gold"; - - List rules = new List(); - foreach (string input in inputs) - { - BaggageRule rule = BaggageRule_Parse(input); - rules.Add(rule); - } - Dictionary dictRules = rules.ToDictionary(x => x.BagColor); - - int cnt = BaggageRule_CountChilds(myBagColor, dictRules); - - return cnt.ToString(); - } - - public class BaggageContainRule - { - public string BagColor { get; set; } - public int Count { get; set; } - } - - public class BaggageRule - { - public string BagColor { get; set; } - - public List Contain { get; set; } - } - - public BaggageRule BaggageRule_Parse(string input) - { - string[] words = input.Split(' '); - string status = "Parse Color 1"; - BaggageRule rule = new BaggageRule(); - rule.Contain = new List(); - BaggageContainRule containRule = null; - string color1 = string.Empty; - - foreach (string word in words) - { - switch (status) - { - case "Parse Color 1": - color1 = word; - status = "Parse Color 2"; - break; - case "Parse Color 2": - rule.BagColor = string.Concat(color1, " ", word); - status = "Expect bags"; - break; - case "Expect bags": - if (word != "bags") { throw new Exception("Expecting bags"); } - status = "Expect contain"; - break; - case "Expect contain": - if (word != "contain") { throw new Exception("Expecting contain"); } - status = "Parse Contain count"; - break; - case "Parse Contain count": - if (word == "no") { status = "End"; break; } - containRule = new BaggageContainRule(); - containRule.Count = Convert.ToInt32(word); - status = "Parse Contain color 1"; - break; - case "Parse Contain color 1": - color1 = word; - status = "Parse Contain color 2"; - break; - case "Parse Contain color 2": - containRule.BagColor = string.Concat(color1, " ", word); - rule.Contain.Add(containRule); - status = "Parse Contain continue"; - break; - case "Parse Contain continue": - if (word == "bag," || word == "bags,") { status = "Parse Contain count"; break; } - status = "End"; - break; - case "End": - break; - } - } - return rule; - } - - public int BaggageRule_CountChilds(string color, Dictionary dictRules) - { - int cnt = 0; - BaggageRule rule = dictRules[color]; - foreach (BaggageContainRule containRule in rule.Contain) - { - cnt += (BaggageRule_CountChilds(containRule.BagColor, dictRules) + 1) * containRule.Count; - } - return cnt; - } + return cntBagColors.ToString(); } -} + + public string ResolvePart2(string[] inputs) + { + string myBagColor = "shiny gold"; + + List rules = new(); + foreach (string input in inputs) + { + BaggageRule rule = BaggageRule_Parse(input); + rules.Add(rule); + } + Dictionary dictRules = rules.ToDictionary(x => x.BagColor); + + int cnt = BaggageRule_CountChilds(myBagColor, dictRules); + + return cnt.ToString(); + } + + public class BaggageContainRule + { + public string BagColor { get; set; } + public int Count { get; set; } + } + + public class BaggageRule + { + public string BagColor { get; set; } + + public List Contain { get; set; } + } + + public BaggageRule BaggageRule_Parse(string input) + { + string[] words = input.Split(' '); + string status = "Parse Color 1"; + BaggageRule rule = new(); + rule.Contain = new List(); + BaggageContainRule containRule = null; + string color1 = string.Empty; + + foreach (string word in words) + { + switch (status) + { + case "Parse Color 1": + color1 = word; + status = "Parse Color 2"; + break; + case "Parse Color 2": + rule.BagColor = string.Concat(color1, " ", word); + status = "Expect bags"; + break; + case "Expect bags": + if (word != "bags") { throw new Exception("Expecting bags"); } + status = "Expect contain"; + break; + case "Expect contain": + if (word != "contain") { throw new Exception("Expecting contain"); } + status = "Parse Contain count"; + break; + case "Parse Contain count": + if (word == "no") { status = "End"; break; } + containRule = new BaggageContainRule(); + containRule.Count = Convert.ToInt32(word); + status = "Parse Contain color 1"; + break; + case "Parse Contain color 1": + color1 = word; + status = "Parse Contain color 2"; + break; + case "Parse Contain color 2": + containRule.BagColor = string.Concat(color1, " ", word); + rule.Contain.Add(containRule); + status = "Parse Contain continue"; + break; + case "Parse Contain continue": + if (word == "bag," || word == "bags,") { status = "Parse Contain count"; break; } + status = "End"; + break; + case "End": + break; + } + } + return rule; + } + + public int BaggageRule_CountChilds(string color, Dictionary dictRules) + { + int cnt = 0; + BaggageRule rule = dictRules[color]; + foreach (BaggageContainRule containRule in rule.Contain) + { + cnt += (BaggageRule_CountChilds(containRule.BagColor, dictRules) + 1) * containRule.Count; + } + return cnt; + } +} \ No newline at end of file diff --git a/AdventOfCode2020/Day08.cs b/AdventOfCode2020/Day08.cs index 1d9452a..5e21106 100644 --- a/AdventOfCode2020/Day08.cs +++ b/AdventOfCode2020/Day08.cs @@ -93,137 +93,136 @@ Fix the program so that it terminates normally by changing exactly one jmp (to n */ -namespace AdventOfCode2020 +namespace AdventOfCode2020; + +public class Day08 : IDay { - public class Day08 : IDay + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) - { - VM vm = new VM(inputs); - vm.Run(); - return vm.Accumulator.ToString(); - } + VM vm = new(inputs); + vm.Run(); + return vm.Accumulator.ToString(); + } - public string ResolvePart2(string[] inputs) + public string ResolvePart2(string[] inputs) + { + VM vm = new(inputs); + foreach (Instruction instruction in vm.Instructions) { - VM vm = new VM(inputs); - foreach (Instruction instruction in vm.Instructions) + if (instruction.OpCode == OpCode.Acc) { continue; } + if (instruction.OpCode == OpCode.Nop) { - if (instruction.OpCode == OpCode.Acc) { continue; } - if (instruction.OpCode == OpCode.Nop) - { - instruction.OpCode = OpCode.Jmp; - vm.Run(); - if (vm.Ended) { break; } - instruction.OpCode = OpCode.Nop; - } - if (instruction.OpCode == OpCode.Jmp) - { - instruction.OpCode = OpCode.Nop; - vm.Run(); - if (vm.Ended) { break; } - instruction.OpCode = OpCode.Jmp; - } + instruction.OpCode = OpCode.Jmp; + vm.Run(); + if (vm.Ended) { break; } + instruction.OpCode = OpCode.Nop; } - return vm.Accumulator.ToString(); - } - - public enum OpCode - { - Acc, - Jmp, - Nop, - }; - - public class Instruction - { - public OpCode OpCode { get; set; } - public int Value { get; set; } - public bool Executed { get; set; } - - public Instruction(string input) + if (instruction.OpCode == OpCode.Jmp) { - string[] parts = input.Split(' '); - - if (parts[0] == "acc") - { - OpCode = OpCode.Acc; - } - if (parts[0] == "jmp") - { - OpCode = OpCode.Jmp; - } - if (parts[0] == "nop") - { - OpCode = OpCode.Nop; - } - - if (parts[1].StartsWith("+")) - { - Value = Convert.ToInt32(parts[1].Substring(1)); - } - else - { - Value = Convert.ToInt32(parts[1]); - } - Executed = false; + instruction.OpCode = OpCode.Nop; + vm.Run(); + if (vm.Ended) { break; } + instruction.OpCode = OpCode.Jmp; } } + return vm.Accumulator.ToString(); + } - public class VM + public enum OpCode + { + Acc, + Jmp, + Nop, + } + + public class Instruction + { + public OpCode OpCode { get; set; } + public int Value { get; set; } + public bool Executed { get; set; } + + public Instruction(string input) { - public List Instructions { get; set; } + string[] parts = input.Split(' '); - public int Accumulator { get; set; } - - public bool Ended { get; set; } - - public VM(string[] inputs) + if (parts[0] == "acc") { - Instructions = new List(); - foreach (string input in inputs) - { - Instructions.Add(new Instruction(input)); - } - Accumulator = 0; - Ended = false; + OpCode = OpCode.Acc; + } + if (parts[0] == "jmp") + { + OpCode = OpCode.Jmp; + } + if (parts[0] == "nop") + { + OpCode = OpCode.Nop; } - public void Run() + if (parts[1].StartsWith("+")) { - foreach (Instruction instruction in Instructions) + Value = Convert.ToInt32(parts[1].Substring(1)); + } + else + { + Value = Convert.ToInt32(parts[1]); + } + Executed = false; + } + } + + private class VM + { + public List Instructions { get; set; } + + public int Accumulator { get; set; } + + public bool Ended { get; set; } + + public VM(string[] inputs) + { + Instructions = new List(); + foreach (string input in inputs) + { + Instructions.Add(new Instruction(input)); + } + Accumulator = 0; + Ended = false; + } + + public void Run() + { + foreach (Instruction instruction in Instructions) + { + instruction.Executed = false; + } + Ended = false; + Accumulator = 0; + int idx = 0; + while (Instructions[idx].Executed == false) + { + Instruction currentInstruction = Instructions[idx]; + if (currentInstruction.OpCode == OpCode.Acc) { - instruction.Executed = false; + Accumulator += currentInstruction.Value; + currentInstruction.Executed = true; + idx++; } - Ended = false; - Accumulator = 0; - int idx = 0; - while (Instructions[idx].Executed == false) + if (currentInstruction.OpCode == OpCode.Jmp) { - Instruction currentInstruction = Instructions[idx]; - if (currentInstruction.OpCode == OpCode.Acc) - { - Accumulator += currentInstruction.Value; - currentInstruction.Executed = true; - idx++; - } - if (currentInstruction.OpCode == OpCode.Jmp) - { - currentInstruction.Executed = true; - idx += currentInstruction.Value; - } - if (currentInstruction.OpCode == OpCode.Nop) - { - currentInstruction.Executed = true; - idx++; - } - if (idx >= Instructions.Count) - { - Ended = true; - break; - } + currentInstruction.Executed = true; + idx += currentInstruction.Value; + } + if (currentInstruction.OpCode == OpCode.Nop) + { + currentInstruction.Executed = true; + idx++; + } + if (idx >= Instructions.Count) + { + Ended = true; + break; } } } } -} +} \ No newline at end of file diff --git a/AdventOfCode2020/Day09.cs b/AdventOfCode2020/Day09.cs index dde59af..b2f36c8 100644 --- a/AdventOfCode2020/Day09.cs +++ b/AdventOfCode2020/Day09.cs @@ -91,83 +91,82 @@ What is the encryption weakness in your XMAS-encrypted list of numbers? */ -namespace AdventOfCode2020 +namespace AdventOfCode2020; + +public class Day09 : IDay { - public class Day09 : IDay + public string ResolvePart1(string[] inputs) { - public string ResolvePart1(string[] inputs) + int preamble = 25; + if (inputs.Length < preamble) { preamble = 5; } + + List numbers = inputs.Select(x => Convert.ToInt64(x)).ToList(); + int firstInvalid = XMAS_FindFirstInvalid(preamble, numbers); + return numbers[firstInvalid].ToString(); + } + + public string ResolvePart2(string[] inputs) + { + int preamble = 25; + if (inputs.Length < preamble) { preamble = 5; } + + List numbers = inputs.Select(x => Convert.ToInt64(x)).ToList(); + int firstInvalid = XMAS_FindFirstInvalid(preamble, numbers); + + long numberInvalid = numbers[firstInvalid]; + long numberChecksum = -1; + bool found = false; + for (int i = firstInvalid - 1; i > 0 && found == false; i--) { - int preamble = 25; - if (inputs.Length < preamble) { preamble = 5; } - - List numbers = inputs.Select(x => Convert.ToInt64(x)).ToList(); - int firstInvalid = XMAS_FindFirstInvalid(preamble, numbers); - return numbers[firstInvalid].ToString(); - } - - public string ResolvePart2(string[] inputs) - { - int preamble = 25; - if (inputs.Length < preamble) { preamble = 5; } - - List numbers = inputs.Select(x => Convert.ToInt64(x)).ToList(); - int firstInvalid = XMAS_FindFirstInvalid(preamble, numbers); - - long numberInvalid = numbers[firstInvalid]; - long numberChecksum = -1; - bool found = false; - for (int i = firstInvalid - 1; i > 0 && found == false; i--) + long sum = numbers[i]; + long max = numbers[i]; + long min = numbers[i]; + for (int j = (i - 1); j >= 0 && found == false; j--) { - long sum = numbers[i]; - long max = numbers[i]; - long min = numbers[i]; - for (int j = (i - 1); j >= 0 && found == false; j--) + sum += numbers[j]; + if (numbers[j] > max) { max = numbers[j]; } + if (numbers[j] < min) { min = numbers[j]; } + if (sum == numberInvalid) { - sum += numbers[j]; - if (numbers[j] > max) { max = numbers[j]; } - if (numbers[j] < min) { min = numbers[j]; } - if (sum == numberInvalid) - { - found = true; - numberChecksum = max + min; - } - if (sum > numberInvalid) - { - break; - } + found = true; + numberChecksum = max + min; } - } - - return numberChecksum.ToString(); - } - - private static int XMAS_FindFirstInvalid(int preamble, List numbers) - { - int firstInvalid = -1; - for (int i = preamble; i < numbers.Count; i++) - { - bool valid = false; - long number = numbers[i]; - for (int j = (i - preamble); j < (i - 1) && valid == false; j++) + if (sum > numberInvalid) { - for (int k = (j + 1); k < i && valid == false; k++) - { - long sum = numbers[j] + numbers[k]; - if (sum == number) - { - valid = true; - } - } - } - if (valid == false) - { - firstInvalid = i; break; } } - - return firstInvalid; } + return numberChecksum.ToString(); } -} + + private static int XMAS_FindFirstInvalid(int preamble, List numbers) + { + int firstInvalid = -1; + for (int i = preamble; i < numbers.Count; i++) + { + bool valid = false; + long number = numbers[i]; + for (int j = (i - preamble); j < (i - 1) && valid == false; j++) + { + for (int k = (j + 1); k < i && valid == false; k++) + { + long sum = numbers[j] + numbers[k]; + if (sum == number) + { + valid = true; + } + } + } + if (valid == false) + { + firstInvalid = i; + break; + } + } + + return firstInvalid; + } + +} \ No newline at end of file diff --git a/AdventOfCode2020/Day10.cs b/AdventOfCode2020/Day10.cs index 2666784..7a9f20d 100644 --- a/AdventOfCode2020/Day10.cs +++ b/AdventOfCode2020/Day10.cs @@ -91,18 +91,17 @@ Find a chain that uses all of your adapters to connect the charging outlet to yo */ -namespace AdventOfCode2020 -{ - public class Day10 : IDay - { - public string ResolvePart1(string[] inputs) - { - throw new NotImplementedException(); - } +namespace AdventOfCode2020; - public string ResolvePart2(string[] inputs) - { - throw new NotImplementedException(); - } +public class Day10 : IDay +{ + public string ResolvePart1(string[] inputs) + { + throw new NotImplementedException(); } -} + + public string ResolvePart2(string[] inputs) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/AdventOfCode2020/Day11.cs b/AdventOfCode2020/Day11.cs index 3ec3d87..6136eec 100644 --- a/AdventOfCode2020/Day11.cs +++ b/AdventOfCode2020/Day11.cs @@ -7,18 +7,17 @@ */ -namespace AdventOfCode2020 -{ - public class Day11 : IDay - { - public string ResolvePart1(string[] inputs) - { - throw new NotImplementedException(); - } +namespace AdventOfCode2020; - public string ResolvePart2(string[] inputs) - { - throw new NotImplementedException(); - } +public class Day11 : IDay +{ + public string ResolvePart1(string[] inputs) + { + throw new NotImplementedException(); } -} + + public string ResolvePart2(string[] inputs) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/AdventOfCode2020/IDay.cs b/AdventOfCode2020/IDay.cs index 3c2f99f..68633af 100644 --- a/AdventOfCode2020/IDay.cs +++ b/AdventOfCode2020/IDay.cs @@ -1,8 +1,7 @@ -namespace AdventOfCode2020 +namespace AdventOfCode2020; + +public interface IDay { - public interface IDay - { - string ResolvePart1(string[] inputs); - string ResolvePart2(string[] inputs); - } -} + string ResolvePart1(string[] inputs); + string ResolvePart2(string[] inputs); +} \ No newline at end of file diff --git a/AdventOfCode2020/Program.cs b/AdventOfCode2020/Program.cs index 652bb46..4f45f54 100644 --- a/AdventOfCode2020/Program.cs +++ b/AdventOfCode2020/Program.cs @@ -1,66 +1,65 @@ using System; using System.IO; -namespace AdventOfCode2020 +namespace AdventOfCode2020; + +class Program { - class Program + static void Main() { - static void Main(string[] args) + int currentDayNumber = 0; + + DateTime date = DateTime.UtcNow.AddHours(-5); + if (date.Month == 12 && currentDayNumber == 0) { - int currentDayNumber = 0; - - DateTime date = DateTime.UtcNow.AddHours(-5); - if (date.Month == 12 && currentDayNumber == 0) - { - currentDayNumber = date.Day; - } - - RunDay(currentDayNumber); - - Console.Read(); + currentDayNumber = date.Day; } - public static void RunDay(int currentDayNumber) + RunDay(currentDayNumber); + + Console.Read(); + } + + public static void RunDay(int currentDayNumber) + { + Console.WriteLine($"Day {currentDayNumber:00}"); + Console.WriteLine("------"); + Console.WriteLine(); + + IDay currentDay = null; + Type dayType = Type.GetType($"AdventOfCode2020.Day{currentDayNumber:00}"); + if (dayType != null) { - Console.WriteLine(string.Format("Day {0:00}", currentDayNumber)); - Console.WriteLine("------"); - Console.WriteLine(); + currentDay = Activator.CreateInstance(dayType) as IDay; + } + if (currentDay == null) + { + Console.WriteLine("!!!!!!!"); + Console.WriteLine("Day implementation not found."); + return; + } - IDay currentDay = null; - Type dayType = Type.GetType(string.Format("AdventOfCode2020.Day{0:00}", currentDayNumber)); - if (dayType != null) - { - currentDay = Activator.CreateInstance(dayType) as IDay; - } - if (currentDay == null) - { - Console.WriteLine("!!!!!!!"); - Console.WriteLine("Day implementation not found."); - return; - } - - string[] linesDay = File.ReadAllLines(string.Format("inputs/Day{0:00}.txt", currentDayNumber)); - try - { - string resultPart1 = currentDay.ResolvePart1(linesDay); - Console.WriteLine("Day{1:00} Result Part1: {0}", resultPart1, currentDayNumber); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - Console.WriteLine(ex.StackTrace); - } - try - { - string resultPart2 = currentDay.ResolvePart2(linesDay); - Console.WriteLine("Day{1:00} Result Part2: {0}", resultPart2, currentDayNumber); - } - catch (Exception ex) - { - Console.WriteLine("!!!!!!!"); - Console.WriteLine(ex.Message); - Console.WriteLine(ex.StackTrace); - } + string[] linesDay = File.ReadAllLines($"inputs/Day{currentDayNumber:00}.txt"); + try + { + string resultPart1 = currentDay.ResolvePart1(linesDay); + Console.WriteLine("Day{1:00} Result Part1: {0}", resultPart1, currentDayNumber); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + Console.WriteLine(ex.StackTrace); + } + try + { + string resultPart2 = currentDay.ResolvePart2(linesDay); + Console.WriteLine("Day{1:00} Result Part2: {0}", resultPart2, currentDayNumber); + } + catch (Exception ex) + { + Console.WriteLine("!!!!!!!"); + Console.WriteLine(ex.Message); + Console.WriteLine(ex.StackTrace); } } -} +} \ No newline at end of file diff --git a/AdventOfCode2023.Tests/Day01_Tests.cs b/AdventOfCode2023.Tests/Day01_Tests.cs index 213526f..0816928 100644 --- a/AdventOfCode2023.Tests/Day01_Tests.cs +++ b/AdventOfCode2023.Tests/Day01_Tests.cs @@ -7,7 +7,7 @@ public class Day01_Tests { var day = new Day01(); - string result = day.ResolvePart1(new string[] { + string result = day.ResolvePart1(new[] { "1abc2", "pqr3stu8vwx", "a1b2c3d4e5f", @@ -22,7 +22,7 @@ public class Day01_Tests { var day = new Day01(); - string result = day.ResolvePart2(new string[] { + string result = day.ResolvePart2(new[] { "two1nine", "eightwothree", "abcone2threexyz", diff --git a/AdventOfCode2023/Day01.cs b/AdventOfCode2023/Day01.cs index a83d4f2..a47b7d6 100644 --- a/AdventOfCode2023/Day01.cs +++ b/AdventOfCode2023/Day01.cs @@ -78,8 +78,7 @@ public class Day01 : IDay public string ResolvePart2(string[] inputs) { - List<(string Text, int Value)> digits = new List<(string Text, int Value)> - { + List<(string Text, int Value)> digits = new() { ("1", 1), ("2", 2), ("3", 3),