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) { int foldsIndex = input.IndexOf((byte)'f'); ReadOnlySpan <byte> foldsInput = input.Slice(foldsIndex); ReadOnlySpan <byte> dotsInput = input.Slice(0, foldsIndex - 1); Span <int> xFolds = stackalloc int[32]; Span <int> yFolds = stackalloc int[32]; ParseFolds(foldsInput, xFolds, yFolds, out int numXFolds, out int numYFolds, out bool firstFoldIsX); var firstFoldAxis = firstFoldIsX ? xFolds[0] : yFolds[0]; int maxX = xFolds[0] * 2 + 1; int maxY = yFolds[0] * 2 + 1; Span <byte> finalXPositions = stackalloc byte[maxX + 1]; Span <byte> finalYPositions = stackalloc byte[maxY + 1]; for (byte x = 0; x < 40; x++) { finalXPositions[x] = x; } for (int i = numXFolds - 1; i >= 0; i--) { int fold = xFolds[i]; var dst = finalXPositions.Slice(fold + 1, fold); finalXPositions.Slice(0, fold).CopyTo(dst); dst.Reverse(); } for (byte y = 0; y < 6; y++) { finalYPositions[y] = y; } for (int i = numYFolds - 1; i >= 0; i--) { int fold = yFolds[i]; var dst = finalYPositions.Slice(fold + 1, fold); finalYPositions.Slice(0, fold).CopyTo(dst); dst.Reverse(); } Span <int> letterMasks = stackalloc int[8]; var dotsAfterOneFold = new HashSet <int>(); int dotsInputCursor = 0; while (dotsInputCursor < dotsInput.Length) { ParseDot(dotsInput, ref dotsInputCursor, out int x, out int y); if (firstFoldIsX) { if (x > firstFoldAxis) { x = 2 * firstFoldAxis - x; } } else { if (y > firstFoldAxis) { y = 2 * firstFoldAxis - y; } } if (dotsAfterOneFold.Add((x << 16) | y)) { x = finalXPositions[x]; y = finalYPositions[y]; (int letter, int col) = Math.DivRem(x, 5); letterMasks[letter] |= 1 << (29 - (y * 5 + col)); } } solution.SubmitPart1(dotsAfterOneFold.Count); Span <char> letters = stackalloc char[8]; for (int i = 0; i < 8; i++) { letters[i] = OCR.MaskToLetter(letterMasks[i]); } solution.SubmitPart2(letters); }