From 2b8315b3abd51c37ee6f9942912d1d4857c88b9b Mon Sep 17 00:00:00 2001 From: James Plante Date: Sun, 3 Dec 2023 15:45:47 -0500 Subject: [PATCH] Uploading Days 1-3 --- .gitignore | 15 ++++++ README.md | 3 ++ day1/Day1.cs | 89 ++++++++++++++++++++++++++++++++ day1/Program.cs | 6 +++ day1/day1.csproj | 8 +++ day2/Day2.cs | 95 ++++++++++++++++++++++++++++++++++ day2/Program.cs | 6 +++ day2/day2.csproj | 8 +++ day3/Day3.cs | 121 ++++++++++++++++++++++++++++++++++++++++++++ day3/MachinePart.cs | 10 ++++ day3/Program.cs | 7 +++ day3/day3.csproj | 8 +++ 12 files changed, 376 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 day1/Day1.cs create mode 100644 day1/Program.cs create mode 100644 day1/day1.csproj create mode 100644 day2/Day2.cs create mode 100644 day2/Program.cs create mode 100644 day2/day2.csproj create mode 100644 day3/Day3.cs create mode 100644 day3/MachinePart.cs create mode 100644 day3/Program.cs create mode 100644 day3/day3.csproj diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cebf4d9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +# ---> VisualStudioCode +.vscode/* + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +# .NET binaries +**/bin/* +**/obj/* + +# Advent of Code Solution Files +**/input*.txt diff --git a/README.md b/README.md new file mode 100644 index 0000000..a478fa0 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# adventofcode2023 + +Advent of Code 2023 Solutions \ No newline at end of file diff --git a/day1/Day1.cs b/day1/Day1.cs new file mode 100644 index 0000000..c8a84a8 --- /dev/null +++ b/day1/Day1.cs @@ -0,0 +1,89 @@ +namespace AdventOfCode2023; + +using System.Text.RegularExpressions; + +public class Day1 +{ + private static int artsyStringToInt(string s) + { + var matches = Regex.Matches(s, @"[0-9]"); + var result = -1; + if (matches.Count == 1) + { + result = int.Parse($"{matches[0]}{matches[0]}"); + } + else if (matches.Count > 1) + { + result = int.Parse($"{matches[0]}{matches[matches.Count - 1]}"); + } + return result; + } + + private static bool tryResolveNumericValue(string digit, out int? result) + { + var nameToDigit = new Dictionary() { + {"one", 1}, + {"two", 2}, + {"three", 3}, + {"four", 4}, + {"five", 5}, + {"six", 6}, + {"seven", 7}, + {"eight", 8}, + {"nine", 9} + }; + var matches = Regex.Matches(digit, @"one|two|three|four|five|six|seven|eight|nine"); + if (matches.Count > 0) + { + result = nameToDigit[matches[0].ToString()]; + return true; + } + result = null; + return false; + } + + private static int searchStringForDigit(string s, bool digitReversed = false) + { + var currentWord = ""; + foreach (var c in s) + { + if (Char.IsDigit(c)) + { + return int.Parse(c.ToString()); + } + else if (Char.IsLetter(c)) + { + int? foundDigit; + if (digitReversed) + { + currentWord = c.ToString() + currentWord; + } + else + { + currentWord = currentWord + c.ToString(); + } + if (tryResolveNumericValue(currentWord, out foundDigit) && foundDigit != null) + { + return (int)foundDigit; // VSCode needs a cast here for some reason + } + } + } + return -1; + } + + private static int artsyStringToIntPartTwo(string s) + { + var reversedString = new string(s.Reverse().ToArray()); + return int.Parse($"{searchStringForDigit(s)}{searchStringForDigit(reversedString, true)}"); + } + + public static int PartOne(IList lines) + { + return lines.Aggregate(0, (current, line) => current + artsyStringToInt(line)); + } + + public static int PartTwo(IList lines) + { + return lines.Aggregate(0, (current, line) => current + artsyStringToIntPartTwo(line)); + } +} \ No newline at end of file diff --git a/day1/Program.cs b/day1/Program.cs new file mode 100644 index 0000000..0c8a789 --- /dev/null +++ b/day1/Program.cs @@ -0,0 +1,6 @@ +using AdventOfCode2023; + +var fileContents = File.ReadAllText(Path.GetFullPath("input.txt")); +var lines = fileContents.Split(Environment.NewLine); +Console.WriteLine($"The answer to Part 1 is {Day1.PartOne(lines)}"); +Console.WriteLine($"The answer to Part 2 is {Day1.PartTwo(lines)}"); \ No newline at end of file diff --git a/day1/day1.csproj b/day1/day1.csproj new file mode 100644 index 0000000..b8e5116 --- /dev/null +++ b/day1/day1.csproj @@ -0,0 +1,8 @@ + + + Exe + net7.0 + enable + enable + + \ No newline at end of file diff --git a/day2/Day2.cs b/day2/Day2.cs new file mode 100644 index 0000000..cbb429a --- /dev/null +++ b/day2/Day2.cs @@ -0,0 +1,95 @@ +namespace day2; + +public class Day2 +{ + private static IList> _splitLineToCubeSets(string line) + { + var cubeSets = new List>(); + var cubeSetStrings = line.Split(";"); + foreach (var cubeSetString in cubeSetStrings) + { + var cubeStrings = cubeSetString.Split(","); + var newCubeSet = new Dictionary(); + foreach (var cubeString in cubeStrings) + { + var splitCube = cubeString.Trim().Split(" "); + newCubeSet.Add(splitCube[1], int.Parse(splitCube[0])); + } + cubeSets.Add(newCubeSet); + } + return cubeSets; + } + + private static bool _isGamePossible(string gameLine, IDictionary expectedBag) + { + var parsedGame = _splitLineToCubeSets(gameLine); + foreach (var parsedCubeSet in parsedGame) + { + var isSetPossible = parsedCubeSet.Aggregate(true, (current, kvp) => current && kvp.Value <= expectedBag[kvp.Key]); + if (!isSetPossible) + { + return false; + } + } + + return true; + } + + private static IDictionary _minimumPossibleCubes(string gameLine) + { + var parsedGame = _splitLineToCubeSets(gameLine); + var minimumCubes = new Dictionary(); + foreach (var cubeSet in parsedGame) + { + foreach (var (color, frequency) in cubeSet) + { + minimumCubes[color] = minimumCubes.ContainsKey(color) ? Math.Max(minimumCubes[color], frequency) : frequency; + } + } + + return minimumCubes; + } + + + public static int PartOne(string[] lines) + { + var finalResult = 0; + foreach (var line in lines) + { + var splitLine = line.Split(":").Select(s => s.Trim()).ToList(); + var gameNumber = int.Parse(splitLine[0].Split(" ")[1]); + var gameLine = splitLine[1]; + var expectedBag = new Dictionary() { + { "red", 12 }, + { "green", 13 }, + { "blue", 14 } + }; + + if (_isGamePossible(gameLine, expectedBag)) + { + finalResult += gameNumber; + } + } + return finalResult; + } + + public static int PartTwo(string[] lines) + { + var finalResult = 0; + foreach (var line in lines) + { + var splitLine = line.Split(":").Select(s => s.Trim()).ToList(); + var gameNumber = int.Parse(splitLine[0].Split(" ")[1]); + var gameLine = splitLine[1]; + + var minimumPossibleCubes = _minimumPossibleCubes(gameLine); + var minimumRed = minimumPossibleCubes.ContainsKey("red") ? minimumPossibleCubes["red"] : 0; + var minimumGreen = minimumPossibleCubes.ContainsKey("green") ? minimumPossibleCubes["green"] : 0; + var minimumBlue = minimumPossibleCubes.ContainsKey("blue") ? minimumPossibleCubes["blue"] : 0; + var power = minimumRed * minimumGreen * minimumBlue; + + finalResult += power; + } + return finalResult; + } +} diff --git a/day2/Program.cs b/day2/Program.cs new file mode 100644 index 0000000..d1cf9c6 --- /dev/null +++ b/day2/Program.cs @@ -0,0 +1,6 @@ +using day2; + +var fileContents = File.ReadAllText(Path.GetFullPath("input.txt")); +var lines = fileContents.Split(Environment.NewLine); +Console.WriteLine($"The answer to Part 1 is {Day2.PartOne(lines)}"); +Console.WriteLine($"The answer to Part 2 is {Day2.PartTwo(lines)}"); \ No newline at end of file diff --git a/day2/day2.csproj b/day2/day2.csproj new file mode 100644 index 0000000..b8e5116 --- /dev/null +++ b/day2/day2.csproj @@ -0,0 +1,8 @@ + + + Exe + net7.0 + enable + enable + + \ No newline at end of file diff --git a/day3/Day3.cs b/day3/Day3.cs new file mode 100644 index 0000000..e932d70 --- /dev/null +++ b/day3/Day3.cs @@ -0,0 +1,121 @@ + +namespace day3; + +public class Day3 +{ + private int _rows; + private int _columns; + private char[][] _grid; + + public Day3(string fileContents) + { + var lines = fileContents.Split(Environment.NewLine); + _grid = lines.Select(line => line.ToCharArray()).ToArray(); + _rows = _grid.Length; + _columns = _grid[0].Length; + } + + private bool _isCharacterASymbol(char c) { + return !char.IsDigit(c) && c != '.'; + } + + private bool _isSymbolInSurroundingLocation(int i, int j) + { + var foundSymbol = false; + for (var ii = i - 1; ii <= i + 1; ii++) + { + for (var jj = j - 1; jj <= j + 1; jj++) + { + if (ii >= 0 && jj >= 0 && ii < _rows && jj < _columns) { + foundSymbol |= _isCharacterASymbol(_grid[ii][jj]); + } + } + } + return foundSymbol; + } + + private IEnumerable _getSurroundingMachineParts(int i, int j, IList machineParts) + { + return machineParts.Where(machinePart => machinePart.Locations.Aggregate(false, (hasBeenFound, currentPoint) => { + var differenceRow = Math.Abs(i - currentPoint.Item1); + var differenceCol = Math.Abs(j - currentPoint.Item2); + return hasBeenFound || (!(differenceRow == 0 && differenceCol == 0) && differenceRow <= 1 && differenceCol <= 1); + })); + } + + private IList _getAllMachinePartsInGrid() + { + var machinePartsList = new List(); + int currentlyParsedNumber = 0; + var locations = new List<(int, int)>(); + bool isSymbolFound = false; + + // We want to iterate over every cell + for (int i = 0; i < _rows; i++) + { + for (int j = 0; j < _columns; j++) + { + var cellContents = _grid[i][j]; + if (char.IsDigit(cellContents)) + { + // Check the surroundings for a symbol + isSymbolFound |= _isSymbolInSurroundingLocation(i, j); + locations.Add((i, j)); + currentlyParsedNumber = (currentlyParsedNumber * 10) + int.Parse(cellContents.ToString()); + } + + // Check if we are done scanning the number (i.e. at the end of a row or we find a non-integer) + if (!char.IsDigit(cellContents) || j == _columns - 1) + { + if (isSymbolFound) + { + machinePartsList.Add(new MachinePart { + Id = machinePartsList.Count, + Value = currentlyParsedNumber, + Locations = locations + }); + } + + locations = new List<(int, int)>(); + currentlyParsedNumber = 0; + isSymbolFound = false; + } + } + } + + return machinePartsList; + } + + public int PartOne() + { + var machinePartsList = _getAllMachinePartsInGrid(); + return machinePartsList.Aggregate(0, (total, current) => total + current.Value); + } + + public long PartTwo() + { + var machinePartsList = _getAllMachinePartsInGrid(); + var runningTotal = 0L; + + // We are going to do a scan for all gears + + for (int i = 0; i < _rows; i++) + { + for (int j = 0; j < _columns; j++) + { + var cellContents = _grid[i][j]; + if (cellContents == '*') + { + var surroundingMachineParts = _getSurroundingMachineParts(i, j, machinePartsList); + var numberOfSurroundingMachingParts = surroundingMachineParts.Count(); + if (numberOfSurroundingMachingParts == 2) { + runningTotal += surroundingMachineParts.Aggregate(1, (currentRatio, machinePart) => currentRatio * machinePart.Value); + } + } + } + } + + return runningTotal; + } + +} diff --git a/day3/MachinePart.cs b/day3/MachinePart.cs new file mode 100644 index 0000000..6685a87 --- /dev/null +++ b/day3/MachinePart.cs @@ -0,0 +1,10 @@ +namespace day3; + +public class MachinePart +{ + public int Id { get; set; } + public int Value { get; set; } + + public IList<(int, int)> Locations { get; set; } = new List<(int, int)>(); + +} diff --git a/day3/Program.cs b/day3/Program.cs new file mode 100644 index 0000000..fc3ab5c --- /dev/null +++ b/day3/Program.cs @@ -0,0 +1,7 @@ +using day3; + +var fileContents = File.ReadAllText(Path.GetFullPath("input.txt")); +var day3 = new Day3(fileContents); +Console.WriteLine($"The answer to Part 1 is {day3.PartOne()}"); +Console.WriteLine($"The answer to Part 2 is {day3.PartTwo()}"); +Console.WriteLine("Hello World"); \ No newline at end of file diff --git a/day3/day3.csproj b/day3/day3.csproj new file mode 100644 index 0000000..b8e5116 --- /dev/null +++ b/day3/day3.csproj @@ -0,0 +1,8 @@ + + + Exe + net7.0 + enable + enable + + \ No newline at end of file