private static void ParseBotInstruction(ref SpanReader parser, out int bot, out bool isLowBot, out int low, out bool isHighBot, out int high) { parser.SkipLength("bot ".Length); bot = parser.ReadPosIntUntil(' '); parser.SkipLength("gives low to ".Length); isLowBot = parser.Peek() == 'b'; parser.SkipLength(isLowBot ? "bot ".Length : "output ".Length); low = parser.ReadPosIntUntil(' '); parser.SkipLength("and high to ".Length); isHighBot = parser.Peek() == 'b'; parser.SkipLength(isHighBot ? "bot ".Length : "output ".Length); high = parser.ReadPosIntUntil('\n'); }
private static FieldsData ParseFields(ref SpanReader reader) { int departureFieldsIndex = 0; int[] departureFields = new int[6]; var fieldList = new List <Field>(); int maxFieldVal = int.MinValue; while (reader.Peek() != '\n') { ReadOnlySpan <byte> fieldName = reader.ReadUntil(':'); reader.SkipLength(1); int l1 = reader.ReadPosIntUntil('-'); int r1 = reader.ReadPosIntUntil(' '); reader.SkipLength("or ".Length); int l2 = reader.ReadPosIntUntil('-'); int r2 = reader.ReadPosIntUntil('\n'); fieldList.Add(new Field(l1, r1, l2, r2)); if (fieldName.StartsWith(new byte[] { (byte)'d', (byte)'e' })) { departureFields[departureFieldsIndex++] = fieldList.Count - 1; } if (r2 > maxFieldVal) { maxFieldVal = r2; } } return(new FieldsData(fieldList, departureFields, maxFieldVal)); }
private static List <byte> ParseInput(ReadOnlySpan <byte> input) { var materialLocations = new List <byte>(); var materials = new Dictionary <string, int>(); var reader = new SpanReader(input); for (int floor = 1; floor < 5; floor++) { reader.SkipLength(floor is 1 or 3 ? "The first floor contains ".Length : "The second floor contains ".Length); if (reader.Peek() == 'n') // nothing relevant { reader.SkipLength("nothing relevant.\n".Length); continue; } bool isLastItem = false; while (!isLastItem) { ParseItem(ref reader, out string element, out bool isGenerator, out isLastItem); if (!materials.TryGetValue(element, out int materialIndex)) { materialIndex = materialLocations.Count; materials[element] = materialIndex; materialLocations.Add(0); } materialLocations[materialIndex] |= (byte)(isGenerator ? floor << 4 : floor); } } return(materialLocations); }
public void Solve(ReadOnlySpan <byte> input, Solution solution) { int freqIndex = 0; int freqTotal = 0; var freqs = new List <Frequency>(); var reader = new SpanReader(input); while (!reader.Done) { freqs.Add(new Frequency { Value = freqTotal, Index = freqIndex }); freqIndex++; int mul = reader.Peek() == '-' ? -1 : 1; reader.SkipLength(1); freqTotal += mul * reader.ReadPosIntUntil('\n'); } foreach (Frequency freq in freqs) { int mod = freq.Value % freqTotal; freq.ModTotal = mod < 0 ? mod + freqTotal : mod; } // sort by mods first, then by value freqs.Sort((a, b) => a.ModTotal != b.ModTotal ? a.ModTotal.CompareTo(b.ModTotal) : a.Value.CompareTo(b.Value)); var prev = new Frequency { ModTotal = -1 }; int minDiff = int.MaxValue; int minIndex = int.MaxValue; int minFreq = 0; foreach (Frequency freq in freqs) { if (freq.ModTotal == prev.ModTotal) { int diff = freq.Value - prev.Value; if (diff < minDiff || (diff == minDiff && prev.Index < minIndex)) { minDiff = diff; minIndex = prev.Index; minFreq = freq.Value; } } prev = freq; } solution.SubmitPart1(freqTotal); solution.SubmitPart2(minFreq); }
public void Solve(ReadOnlySpan <byte> input, Solution solution) { var reader = new SpanReader(input.TrimEnd((byte)'\n')); int earliestTime = reader.ReadPosIntUntil('\n'); int part1Id = -1; int part1Time = int.MaxValue; BigInteger product = 1; var buses = new List <(int n, int a)>(); for (int i = 0; !reader.Done; i++) { if (reader.Peek() == 'x') { reader.SkipLength("x,".Length); continue; } int busId = reader.ReadPosIntUntil(','); // Part 1 int waitTime = busId - (earliestTime % busId); if (waitTime < part1Time) { part1Id = busId; part1Time = waitTime; } // Part 2 product *= busId; int remainder = (busId - i) % busId; if (remainder < 0) { remainder += busId; } buses.Add((busId, remainder)); } int part1 = part1Id * part1Time; BigInteger part2 = 0; foreach ((int n, int a) in buses) { BigInteger p = product / n; part2 += a * BigInteger.ModPow(p, n - 2, n) * p; } part2 %= product; solution.SubmitPart1(part1); solution.SubmitPart2(part2); }
public void Solve(ReadOnlySpan <byte> input, Solution solution) { // assume the origin is at 1 << 15, 1 << 15 const ushort xOrigin = 1 << 15; const ushort yOrigin = 1 << 15; // pack the x and y ushorts into a uint uint pos = unchecked ((uint)xOrigin << 16 | yOrigin); uint dir = Up; var seenLocations = new HashSet <uint> { pos }; int distanceToFirstRepeatedLocation = -1; var reader = new SpanReader(input.TrimEnd((byte)'\n')); while (true) { dir = MakeTurn(dir, reader.Peek() == 'L'); reader.SkipLength(1); uint distance = (uint)reader.ReadPosIntUntil(','); if (distanceToFirstRepeatedLocation == -1) { for (uint i = 0; i < distance; i++) { pos = unchecked (pos + dir); if (!seenLocations.Add(pos)) { distanceToFirstRepeatedLocation = ManhattanDistance(pos); } } } else { pos = unchecked (pos + dir * distance); } if (reader.Done) { break; } reader.SkipLength(1); } int distanceToDestination = ManhattanDistance(pos); solution.SubmitPart1(distanceToDestination); solution.SubmitPart2(distanceToFirstRepeatedLocation);
private static void ParseItem(ref SpanReader reader, out string element, out bool isGenerator, out bool isLastItem) { isLastItem = reader[1] == 'n'; // "and a <something>" reader.SkipLength(isLastItem ? "and a ".Length : "a ".Length); ReadOnlySpan <byte> elementSpan = reader.ReadUntil(' '); isGenerator = reader.Peek() == 'g'; reader.SkipUntil(isLastItem ? '\n' : ' '); if (!isGenerator) { elementSpan = elementSpan.Slice(0, elementSpan.Length - "-compatible".Length); } element = Encoding.ASCII.GetString(elementSpan); }
public void Solve(ReadOnlySpan <byte> input, Solution solution) { int lines = input.Count((byte)'\n'); var instrs = new Instruction[lines]; int i = 0; var reader = new SpanReader(input); while (!reader.Done) { byte op = reader.Peek(); reader.SkipLength("cpy ".Length); Param arg1, arg2; if (op is (byte)'c' or(byte) 'j') { arg1 = ParseParamUntil(ref reader, ' '); arg2 = ParseParamUntil(ref reader, '\n'); }
public void Solve(ReadOnlySpan <byte> input, Solution solution) { bool[,] pixels = new bool[50, 6]; bool[] rowBuffer = new bool[50]; bool[] colBuffer = new bool[6]; foreach (ReadOnlySpan <byte> line in input.SplitLines()) { if (line[1] == 'e') // rect { var reader = new SpanReader(line.Slice("rect ".Length)); int width = reader.ReadPosIntUntil('x'); int height = reader.ReadPosIntUntilEnd(); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { pixels[x, y] = true; } } } else if (line[7] == 'c') // rotate column { var reader = new SpanReader(line.Slice("rotate column x=".Length)); int column = reader.ReadPosIntUntil(' '); reader.SkipLength("by ".Length); int rotateAmount = reader.ReadPosIntUntilEnd(); for (int i = 0; i < 6; i++) { colBuffer[i] = pixels[column, i]; int target = i - rotateAmount; if (target < 0) { target += 6; } // if the target has already been swapped, get it from the buffer pixels[column, i] = target < i ? colBuffer[target] : pixels[column, target]; } } else // rotate row { var reader = new SpanReader(line.Slice("rotate row y=".Length)); int row = reader.Peek() - '0'; reader.SkipLength("0 by ".Length); int rotateAmount = reader.ReadPosIntUntilEnd(); for (int i = 0; i < 50; i++) { rowBuffer[i] = pixels[i, row]; int target = i - rotateAmount; if (target < 0) { target += 50; } // if the target has already been swapped, get it from the buffer pixels[i, row] = target < i ? rowBuffer[target] : pixels[target, row]; } } } int part1 = 0; foreach (bool pixel in pixels) { if (pixel) { part1++; } } Span <char> part2 = stackalloc char[10]; for (int i = 0; i < 10; i++) { int letterPixels = 0; for (int row = 0; row < 6; row++) { for (int col = 0; col < 5; col++) { if (pixels[i * 5 + col, row]) { letterPixels |= 1 << (29 - (row * 5 + col)); } } } part2[i] = OCR.MaskToLetter(letterPixels); } solution.SubmitPart1(part1); solution.SubmitPart2(part2); }
public void Solve(ReadOnlySpan <byte> input, Solution solution) { // Part 1 int x1 = 0, y1 = 0; int dx1 = 1, dy1 = 0; // Part 2 int x2 = 0, y2 = 0; int dx2 = 10, dy2 = 1; var reader = new SpanReader(input); while (!reader.Done) { byte dir = reader.Peek(); reader.SkipLength(1); int amount = reader.ReadPosIntUntil('\n'); switch (dir) { case (byte)'N': y1 += amount; dy2 += amount; break; case (byte)'S': y1 -= amount; dy2 -= amount; break; case (byte)'E': x1 += amount; dx2 += amount; break; case (byte)'W': x1 -= amount; dx2 -= amount; break; case (byte)'L': for (int i = amount; i > 0; i -= 90) { RotateLeft(ref dx1, ref dy1); RotateLeft(ref dx2, ref dy2); } break; case (byte)'R': for (int i = amount; i > 0; i -= 90) { RotateRight(ref dx1, ref dy1); RotateRight(ref dx2, ref dy2); } break; case (byte)'F': x1 += amount * dx1; y1 += amount * dy1; x2 += amount * dx2; y2 += amount * dy2; break; } } int part1 = Math.Abs(x1) + Math.Abs(y1); int part2 = Math.Abs(x2) + Math.Abs(y2); solution.SubmitPart1(part1); solution.SubmitPart2(part2); }
public void Solve(ReadOnlySpan <byte> input, Solution solution) { var ingredientCount = new Dictionary <string, int>(); var allgerenCandidates = new Dictionary <string, HashSet <string> >(); var ingredientSet = new HashSet <string>(); var reader = new SpanReader(input); int totalIngredients = 0; while (!reader.Done) { while (reader.Peek() != '(') { string ingredient = Encoding.ASCII.GetString(reader.ReadUntil(' ')); ingredientCount[ingredient] = ingredientCount.GetValueOrDefault(ingredient) + 1; ingredientSet.Add(ingredient); totalIngredients++; } reader.SkipLength("(contains ".Length); foreach (ReadOnlySpan <byte> allergen in reader.ReadUntil(')').Split(new[] { (byte)',', (byte)' ' })) { string allergenStr = Encoding.ASCII.GetString(allergen); if (allgerenCandidates.TryGetValue(allergenStr, out HashSet <string>?curSet)) { curSet.IntersectWith(ingredientSet); } else { allgerenCandidates[allergenStr] = new HashSet <string>(ingredientSet); } } reader.SkipLength(1); ingredientSet.Clear(); } int allergenIndex = 0; string[] allergens = new string[allgerenCandidates.Count]; foreach (string allergen in allgerenCandidates.Keys) { allergens[allergenIndex++] = allergen; } Array.Sort(allergens); string?[] ingredients = new string?[allergens.Length]; int part1 = totalIngredients; for (int allergensLeft = 0; allergensLeft < allergens.Length; allergensLeft++) { string foundIngredient = string.Empty; for (int i = 0; i < allergens.Length; i++) { if (ingredients[i] != null) { continue; } string allergen = allergens[i]; HashSet <string> candidates = allgerenCandidates[allergen]; if (candidates.Count == 1) { foundIngredient = candidates.Single(); ingredients[i] = foundIngredient; part1 -= ingredientCount[foundIngredient]; break; } } foreach (HashSet <string> candidates in allgerenCandidates.Values) { candidates.Remove(foundIngredient); } } string part2 = string.Join(',', ingredients); solution.SubmitPart1(part1); solution.SubmitPart2(part2); }
public void Solve(ReadOnlySpan <byte> input, Solution solution) { // negative means output, positive means bot var botOutputs = new Dictionary <int, (bool IsLowBot, int Low, bool IsHighBot, int High)>(); var valueQueue = new Queue <(bool IsBot, int Destination, int Value)>(); int maxBotId = 0; int maxOutputId = 0; // first pass we just keep track of where the bot sends its chips var parser = new SpanReader(input); while (!parser.Done) { if (parser.Peek() == 'b') { ParseBotInstruction(ref parser, out int bot, out bool isLowBot, out int low, out bool isHighBot, out int high); botOutputs[bot] = (isLowBot, low, isHighBot, high); maxBotId = Math.Max(bot, maxBotId); if (!isLowBot) { maxOutputId = Math.Max(maxOutputId, low); } if (!isHighBot) { maxOutputId = Math.Max(maxOutputId, high); } } else { ParseBotStartingValue(ref parser, out int bot, out int value); valueQueue.Enqueue((true, bot, value)); } } int[]? botValues = new int[maxBotId + 1]; int[]? outputValues = new int[maxOutputId + 1]; int part1 = 0; while (valueQueue.TryDequeue(out (bool IsBot, int Destination, int Value)x)) { (bool isBot, int destination, int value) = x; if (!isBot) { outputValues[destination] = value; continue; } int curValue = botValues[destination]; if (curValue == 0) { botValues[destination] = value; } else { (bool IsLowBot, int Low, bool IsHighBot, int High) = botOutputs[destination]; int low = Math.Min(curValue, value); int high = Math.Max(curValue, value); if (low == 17 && high == 61) { part1 = destination; } valueQueue.Enqueue((IsLowBot, Low, low)); valueQueue.Enqueue((IsHighBot, High, high)); } } int part2 = outputValues[0] * outputValues[1] * outputValues[2]; solution.SubmitPart1(part1); solution.SubmitPart2(part2); }