From 512a804713488b79be0a553ffd795750ca1baf1f Mon Sep 17 00:00:00 2001 From: Kevin Vlaanderen Date: Wed, 13 Dec 2023 11:21:07 +0100 Subject: [PATCH] 2023 13-2 --- 2023/src/tasks/day13/tasks.go | 161 ++++++++++++++++++++--------- 2023/src/tasks/day13/tasks_test.go | 7 ++ 2 files changed, 119 insertions(+), 49 deletions(-) diff --git a/2023/src/tasks/day13/tasks.go b/2023/src/tasks/day13/tasks.go index 236fc2d..515d9b6 100644 --- a/2023/src/tasks/day13/tasks.go +++ b/2023/src/tasks/day13/tasks.go @@ -3,72 +3,135 @@ package day13 import ( "2023/src/framework" "github.com/samber/lo" + lop "github.com/samber/lo/parallel" ) func Task1(data string) (result framework.Result[int]) { blocks := framework.LineBlocks(data) - horizontalIndices := make([]int, 0) - verticalIndices := make([]int, 0) + lop.ForEach(blocks, func(block []string, index int) { + direction, index := findReflection(block, false) + switch direction { + case Horizontal: + result.Value += index * 100 + case Vertical: + result.Value += index + } + }) -Block: - for _, block := range blocks { - width, height := len(block[0]), len(block) + return +} - rows := make([][]bool, height) - columns := make([][]bool, width) +func Task2(data string) (result framework.Result[int]) { + blocks := framework.LineBlocks(data) - for y, line := range block { - if rows[y] == nil { - rows[y] = make([]bool, width) - } - for x, char := range line { - if columns[x] == nil { - columns[x] = make([]bool, height) - } - rows[y][x] = char == '#' - columns[x][y] = char == '#' - } + lop.ForEach(blocks, func(block []string, index int) { + direction, index := findReflection(block, true) + switch direction { + case Horizontal: + result.Value += index * 100 + case Vertical: + result.Value += index } + }) - rowHashes := lo.Map(rows, func(row []bool, index int) framework.Hash { - return framework.ComputeHash(row) - }) - columnHashes := lo.Map(columns, func(column []bool, index int) framework.Hash { - return framework.ComputeHash(column) - }) - - MidX: - for mid := 0; mid < width-1; mid++ { - checkN := min(mid+1, width-mid-1) - for i := 0; i < checkN; i++ { - if columnHashes[mid-i] != columnHashes[mid+i+1] { - continue MidX - } + return +} + +func findReflection(block []string, checkVariants bool) (Direction, int) { + rows, columns := parseBlock(block) + + rowHashes := calculateHashes(rows, checkVariants) + columnHashes := calculateHashes(columns, checkVariants) + + if found, index := reflectionFound(columnHashes, checkVariants); found { + return Vertical, index + } + if found, index := reflectionFound(rowHashes, checkVariants); found { + return Horizontal, index + } + panic("no reflection found") +} + +func parseBlock(block []string) ([][]bool, [][]bool) { + width, height := len(block[0]), len(block) + + rows := make([][]bool, height) + columns := make([][]bool, width) + + for y, line := range block { + if rows[y] == nil { + rows[y] = make([]bool, width) + } + for x, char := range line { + if columns[x] == nil { + columns[x] = make([]bool, height) } - verticalIndices = append(verticalIndices, mid+1) - continue Block + rows[y][x] = char == '#' + columns[x][y] = char == '#' + } + } + return rows, columns +} + +func calculateHashes(data [][]bool, checkVariants bool) []HashGroup { + return lo.Map(data, func(item []bool, index int) (hashGroup HashGroup) { + hashGroup.original = framework.ComputeHash(item) + if checkVariants { + hashGroup.variants = lo.Map(item, func(_ bool, index int) framework.Hash { + newRow := make([]bool, len(item)) + copy(newRow, item) + newRow[index] = !item[index] + return framework.ComputeHash(newRow) + }) } + return + }) +} + +func reflectionFound(hashes []HashGroup, checkVariants bool) (bool, int) { + size := len(hashes) + + for mid := 0; mid < size-1; mid++ { + checkN := min(mid+1, size-mid-1) - MidY: - for mid := 0; mid < height-1; mid++ { - checkN := min(mid+1, height-mid-1) - for i := 0; i < checkN; i++ { - if rowHashes[mid-i] != rowHashes[mid+i+1] { - continue MidY + matchFound := true + variantUsed := false + + for offset := 0; offset < checkN; offset++ { + if hashes[mid-offset].original == hashes[mid+offset+1].original { + continue + } + if checkVariants && !variantUsed { + if compareLeftRight(mid-offset, mid+offset+1, hashes) || + compareLeftRight(mid+offset+1, mid-offset, hashes) { + variantUsed = true + continue } } - horizontalIndices = append(horizontalIndices, mid+1) - continue Block + matchFound = false + } + if matchFound && (!checkVariants || variantUsed) { + return true, mid + 1 } } + return false, 0 +} - for _, row := range horizontalIndices { - result.Value += row * 100 - } - for _, column := range verticalIndices { - result.Value += column - } +func compareLeftRight(originalIndex, variantIndex int, hashes []HashGroup) bool { + return lo.ContainsBy(hashes[variantIndex].variants, func(variant framework.Hash) bool { + return variant == hashes[originalIndex].original + }) +} - return +type HashGroup struct { + original framework.Hash + variants []framework.Hash } + +type Direction uint8 + +const ( + Horizontal Direction = iota + Vertical +) diff --git a/2023/src/tasks/day13/tasks_test.go b/2023/src/tasks/day13/tasks_test.go index dcd722c..d0305be 100644 --- a/2023/src/tasks/day13/tasks_test.go +++ b/2023/src/tasks/day13/tasks_test.go @@ -13,6 +13,13 @@ var taskDefinitions = []_testing.TaskDefinition[int]{ {"day13", 30802, _testing.RealData}, }, }, + { + Task: Task2, + Tests: []_testing.TestDefinition[int]{ + {"data", 400, _testing.TestData}, + {"day13", 37876, _testing.RealData}, + }, + }, } func TestDay13(t *testing.T) {