🌟 Advent of Code (AoC) 2023 🌟

PermalÀnk
Medlem ★
●
Skrivet av ZyntaaX:

Haha hÀrligt att du löste det sjÀlv. Jag testkörde din kod med min input och fick rÀtt svar. MÀrkligt

Se nedan:

Anledningen Àr att om linjens summa Àr 0 slutade den exekvera dÄ jag av misstag kollade summan istÀllet för att kolla sÄ varenda siffra var 0.

Dold text
Visa signatur

CPU: Ryzen 5600xGPU: 1080 TI ROG Strix RAM:2x16GB G.skill Trident @ 3600MHz MoBo: Asus B550FPSU: Corsair SF750
En resa till Nordkorea
2 dagar i Tjernobyl

PermalÀnk
Medlem
●
Skrivet av Yoshman:

Brydde mig inte om att optimera bort allokeringar, översatte min Python-lösning rakt av till Go. MÀrkligt nog blev den snabbare Àn din Rust-lösning, Go har i.o.f.s. fÄtt en del prestandaoptimeringar senaste Äret och Go-program Àr typiskt nÀstan lika snabba som C, C++ och Rust program (som ur alla praktiska hÀnseenden brukar vara lika snabba om man skriver motsvarande kod).

PĂ„ min dator

Rust

======== DAY 9 ======== Part 1: 2175229206 Part 1 took 0.354792ms Part 2: 942 Part 2 took 0.357041ms

Go

2175229206 Took 144.083”s 942 Took 142.75”s

package main import ( "fmt" "os" "strconv" "strings" "time" ) type PredFn func(history []int, subPrediction int) int func parseOasis(content string) [][]int { histories := [][]int{} for _, line := range strings.Split(content, "\n") { history := []int{} for _, numStr := range strings.Fields(line) { num, _ := strconv.Atoi(numStr) history = append(history, num) } histories = append(histories, history) } return histories } func prediction(history []int, predFn PredFn) int { if allZeros(history) { return 0 } return predFn(history, prediction(pairwiseDiff(history), predFn)) } func pairwiseDiff(xs []int) []int { ys := make([]int, len(xs)-1) for i := 0; i < len(xs)-1; i++ { ys[i] = xs[i+1] - xs[i] } return ys } func allZeros(history []int) bool { for _, num := range history { if num != 0 { return false } } return true } func sumHistories(histories [][]int, predFn PredFn) int { sum := 0 for _, history := range histories { sum += prediction(history, predFn) } return sum } func predictionForward(history []int, subPrediction int) int { return history[len(history)-1] + subPrediction } func predictionBackward(history []int, subPrediction int) int { return history[0] - subPrediction } func main() { content, _ := os.ReadFile("input.txt") histories := parseOasis((string(content))) start := time.Now() part1 := sumHistories(histories, predictionForward) part1Duration := time.Since(start) start = time.Now() part2 := sumHistories(histories, predictionBackward) part2Duration := time.Since(start) fmt.Println(part1) fmt.Println("Took ", part1Duration) fmt.Println(part2) fmt.Println("Took ", part2Duration) }

Go source

Genom att skippa allokeringar och anvÀnda simd gÄr det nÄgot snabbare. Testade att skriva en Scala/jvm version som anvÀnder avx2. AnvÀnder en del maskning viket inte genererar sÄ effektiv avx2 kod, tyvÀrr sÄ dog min avx512 dator precis nÀr aoc startade.
Benchmark pÄ en i7-8559U:

[info] Benchmark Mode Cnt Score Error Units [info] AoC2023Day09Benchmark.aoc2023day09benchmark avgt 5 4,482 ± 0,989 us/op

AnvÀnder nog en annan algorithm ocksÄ. Summerar först ner till en 21 element lÄng vektor som jag kör 20 varv av extrapolate pÄ utan att kolla efter om alla element Àr 0.

Liknande lösning i uiua fick jag ner till 33us per del
uiua pad

I ← ⊜(⊜⋕≠@\s.)≠@\n.&fras "9.txt" /+;⍄⊃(↘¯1-:↻1.)(+⊱⇌)-1⧻.:0 /+I /+;⍄⊃(↘¯1-:↻1.)(+⊱⇌)-1⧻.:0 ⇌/+I

Dold text
La till en snabb uiua lösning i spoilern...
PermalÀnk
●

Dag: 9
SprÄk: C

HÀr Àr gÄrdagens sÄ fÄr vi se om jag hinner ikapp senare ikvÀll.

#include <assert.h> #include <stdio.h> #include <stdlib.h> #define HISTORYLEN 21 #define NUMLINES 200 int predict(int l[], int length); int predict_backwards(int l[], int length); int zeroes(int list[], int length); void* parseinput(char* filename); void readlist(char* str, int* list); int main() { int (*history)[HISTORYLEN] = parseinput("input"); int part1 = 0, part2 = 0; for (int h=0; h<NUMLINES; ++h) { part1 += predict(history[h], HISTORYLEN); part2 += predict_backwards(history[h], HISTORYLEN); } printf("Part 1: %i\nPart 2: %i\n", part1, part2); assert(part1 == 1772145754); assert(part2 == 867); } int predict(int l[], int length) { if (zeroes(l, length)) return 0; int tmp[HISTORYLEN]; for (int i=0; i<length-1; ++i) tmp[i] = l[i+1] - l[i]; return l[length-1] + predict(tmp, length-1); } int predict_backwards(int l[], int length) { if (zeroes(l, length)) return 0; int tmp[HISTORYLEN]; for (int i=0; i<length-1; ++i) tmp[i] = l[i+1] - l[i]; return l[0] - predict_backwards(tmp, length-1); } int zeroes(int list[], int length) { for (int i=0; i<length; ++i) if (list[i] != 0) return 0; return 1; } void* parseinput(char* filename) { int (*h)[HISTORYLEN] = calloc(NUMLINES*HISTORYLEN, sizeof (int)); FILE* fptr = fopen(filename, "r"); int i = 0; char line[220]; while (fgets(line, sizeof line, fptr)) { readlist(line, h[i++]); } return h; } // Read list of numbers from string: "1 2 3" -> {1, 2, 3} void readlist(char* str, int* list) { int i = 0, num_read; while (1) { if (sscanf(str, "%i %n", &list[i++], &num_read) != 1) break; str += num_read; } }

Dold text
PermalÀnk
Medlem ★
●

Dag: 10
SprÄk: Python

Det var lite pyssligt i dag...

GrundförutsÀttningen Àr att next Àr en 3D array som man indexerar med y, x, direction för att slÄ upp nÀsta koordinat och riktning man stÄr i.

Findpath hittar den slinga som gör att man har det inneslutna pÄ höger sida.
Markera allting som ligger pÄ höger sida om slingan med 1.
Markera slingan med 2.
Hitta sekvenser av 2...2,1...1,0...0,1...1, 2...2. Dessa nollor kommer vara inneslutna av ettor, sÄ sÀtt dessa ocksÄ till ettor,
Ta bort alla tvÄor och summera

import numpy as np from itertools import groupby maze = np.pad(np.array([[c for c in s.strip()] for s in open("input10.txt").readlines()]), 1, constant_values='.') invalid = [99, 99, 99] moves = { # N E S W '.': np.array([ invalid, invalid, invalid, invalid]), 'S': np.array([[-1,+0,+0], [+0,+1,+0], [+1,+0,+0], [+0,-1,+0]]), '|': np.array([[-1,+0,+0], invalid, [+1,+0,+0], invalid]), '-': np.array([ invalid, [+0,+1,+0], invalid, [+0,-1,+0]]), 'F': np.array([[+0,+1,+1], invalid, invalid, [+1,+0,-1]]), '7': np.array([[+0,-1,+3], [+1,+0,+1], invalid, invalid]), 'L': np.array([ invalid, invalid, [+0,+1,-1], [-1,+0,-3]]), 'J': np.array([ invalid, [-1,+0,-1], [+0,-1,+1], invalid])} on_the_right= { 'S': [[], [], [], []], '|': [[+0,+1], [], [0, -1], []], '-': [[], [+1,+0], [], [-1,+0]], 'F': [[], [], [], [-1,-1]], '7': [[-1,+1], [], [], []], 'L': [[], [], [+1,-1], []], 'J': [[], [+1,+1], [], []]} next = np.array([[moves[x] for x in y] for y in maze]) inside = np.zeros(maze.shape, dtype = np.int_) starty, startx = list(zip(*np.where(maze == 'S')))[0] def findpath(): for dir in range(4): state = (starty, startx, dir) turns = 0 path = [state] while ((step := next[state]) != invalid).all(): state = tuple(state + step) path.append(state) if step[2] in [1,-3]: turns += 1 elif step[2] in [-1, 3]: turns += -1 if state == (starty, startx, state[2]): if turns > 0: return path break def mark_right_of_path(path): for p in path: if o := on_the_right[maze[p[0], p[1]]][p[2]]: for i in range(2): for j in range(2): inside[p[0] + i * o[0], p[1] + j * o[1]] = 1 def mark_path(path): for p in path: inside[p[0], p[1]] = 2 def fill_enclosed(inside): for l in inside: groups = [(k, list(g)) for k, g in groupby(enumerate(l), key = lambda a: a[1])] for i in range(len(groups) - 3): if groups[i + 0][0] == 2 and groups[i + 1][0] == 1: j = 2 while groups[i + j][0] == 0 and groups[i + j + 1][0] == 1: for startx in groups[i + j][1]: l[startx[0]] = 1 j += 2 path = findpath() mark_right_of_path(path) mark_path(path) fill_enclosed(inside) print(len(path) // 2, (inside == 1).sum())

Dold text
PermalÀnk
Medlem ★
●

Dag: 10
SprÄk: Rust
Lösning: Github
Körtid: 0.1/3 ms (del 1/2)

Efter att ha lagt alldeles för mycket tid pÄ att hitta en snygg lösning för att "klÀmma sig igenom" gav jag upp och skalade up/ner hela brÀdet innan flood-fillen. Borde ha gjort det omedelbart nÀr klÀmma sig igenom visade sig vara svÄrare Àn jag trott, men istÀllet för att tÀnka om sÄ envisas en med att fÄ första idén att funka

Dold text
PermalÀnk
Medlem ★
●

Dag: 10
SprÄk: Python

NORTH = 0 EAST = 1 SOUTH = 2 WEST = 3 indir2outdir = { ('|', NORTH): NORTH, ('|', SOUTH): SOUTH, ('-', EAST): EAST, ('-', WEST): WEST, ('L', WEST): NORTH, ('L', SOUTH): EAST, ('J', EAST): NORTH, ('J', SOUTH): WEST, ('7', NORTH): WEST, ('7', EAST): SOUTH, ('F', NORTH): EAST, ('F', WEST): SOUTH } fitting_tile = {} # Used to replace 'S' with a fitting tile for (tile, dir1), dir2 in indir2outdir.items(): fitting_tile[(dir2, dir1)] = tile def read_lines(filename): lines = open(f'day10/{filename}.txt').read().splitlines() lines.insert(0, '.' * len(lines[0])) lines.append('.' * len(lines[0])) lines = [f'.{line}.' for line in lines] m = {} for i, line in enumerate(lines): for j, c in enumerate(line): if c == 'S': start = (i, j) m[(i, j)] = c return lines, m, start def next_dir(tile, dir): return indir2outdir.get((tile, dir), -1) def next_pos(pos, dir): if dir == NORTH: return (pos[0]-1, pos[1]) elif dir == EAST: return (pos[0], pos[1]+1) elif dir == SOUTH: return (pos[0]+1, pos[1]) elif dir == WEST: return (pos[0], pos[1]-1) # Part 1 def walk(m, start): for dir in [NORTH, EAST, SOUTH, WEST]: start_dir = dir pos = start if next_dir(m[next_pos(pos, dir)], dir) != -1: on_loop = set() steps = 0 while steps == 0 or m[pos] != 'S': on_loop.add(pos) end_dir = dir pos = next_pos(pos, dir) dir = next_dir(m[pos], dir) steps += 1 # Replace 'S' with a fitting tile (used in part 2) m[start] = fitting_tile[(start_dir, end_dir)] return (steps//2, on_loop) # Part 2. Count number of collisions (odd => inside) def count_inside(lines, m, on_loop): inside = 0 for i in range(len(lines)): count = 0 for j in range(len(lines[0])): if (i, j) in on_loop: if m[(i, j)] in '|LJ': # ignore other tiles ("collinear") count += 1 elif count % 2 == 1: inside += 1 return inside def solve(filename): lines, m, start = read_lines(filename) distance, on_loop = walk(m, start) inside = count_inside(lines, m, on_loop) return (distance, inside) assert solve('input') == (4, 1) assert solve('input2') == (8, 1) assert solve('input3') == (23, 4) assert solve('input4') == (22, 4) assert solve('input5') == (70, 8) assert solve('input6') == (80, 10) #assert solve('input_real') == ... print('OK')

Dold text
PermalÀnk
●

Dag: 10
SprÄk: C

Det hÀr blev inge vackert. Men koden ger rÀtt svar och det Àr för sent pÄ kvÀllen för att sitta och slipa.

#include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAZESIZE 150 enum direction { UP, DOWN, LEFT, RIGHT }; char mazechar(char (*maze)[MAZESIZE], int row, int col); void setfloodchar(char (*flood)[MAZESIZE], int row, int col, char c); void floodfill(char (*flood)[MAZESIZE], int row, int col, char c); void* parseinput(char* filename); void findstart(char (*maze)[MAZESIZE], int* startrow, int* startcol); // for part 1, just find the starting location and walk // along the pipes until returning to the starting point. // Half the final distance will be the furthest point. // When walking along the pipe, also keep marking the pipe // locations as well as left and right sides of the path. // This will help in part 2. int main() { char (*maze)[MAZESIZE] = parseinput("input"); // Make a blank copy of the maze for part 2. char (*flood)[MAZESIZE] = malloc(MAZESIZE* (MAZESIZE+1) * sizeof (char)); for (int i=0; i<MAZESIZE; ++i) { memset(flood[i], ' ', MAZESIZE); flood[i][MAZESIZE-1] = '\0'; } int row, col, distance = 0; enum direction dir; findstart(maze, &row, &col); setfloodchar(flood, row, col, 'P'); // Mark as pipe in flood map. char at = mazechar(maze, row, col); char above = mazechar(maze, row-1, col); char below = mazechar(maze, row+1, col); char left = mazechar(maze, row, col-1); char right = mazechar(maze, row, col+1); if (above == '|' || above == 'F' || above == '7') { dir = UP; --row; setfloodchar(flood, row, col, 'P'); } else if (below == '|' || below == 'J' || below == 'L') { dir = DOWN; ++row; setfloodchar(flood, row, col, 'P'); } else if (left == '-' || left == 'F' || left == 'L') { dir = LEFT; --col; setfloodchar(flood, row, col, 'P'); } else if (right == '-' || right == 'J' || right == '7') { dir = RIGHT; ++col; setfloodchar(flood, row, col, 'P'); } do { at = mazechar(maze, row, col); above = mazechar(maze, row-1, col); below = mazechar(maze, row+1, col); left = mazechar(maze, row, col-1); right = mazechar(maze, row, col+1); if (dir==UP && at=='|') { setfloodchar(flood, row, col, 'P'); setfloodchar(flood, row, col-1, 'L'); setfloodchar(flood, row, col+1, 'R'); dir = UP; --row; } else if (dir==LEFT && at=='L') { setfloodchar(flood, row, col, 'P'); setfloodchar(flood, row+1, col, 'L'); setfloodchar(flood, row, col-1, 'L'); dir = UP; --row; } else if (dir==RIGHT && at=='J') { setfloodchar(flood, row, col, 'P'); setfloodchar(flood, row+1, col, 'R'); setfloodchar(flood, row, col+1, 'R'); dir = UP; --row; } else if (dir==DOWN && at=='|') { setfloodchar(flood, row, col, 'P'); setfloodchar(flood, row, col+1, 'L'); setfloodchar(flood, row, col-1, 'R'); dir = DOWN; ++row; } else if (dir==LEFT && at=='F') { setfloodchar(flood, row, col, 'P'); setfloodchar(flood, row-1, col, 'R'); setfloodchar(flood, row, col-1, 'R'); dir = DOWN; ++row; } else if (dir==RIGHT && at=='7') { setfloodchar(flood, row, col, 'P'); setfloodchar(flood, row-1, col, 'L'); setfloodchar(flood, row, col+1, 'L'); dir = DOWN; ++row; } else if (dir==UP && at=='7') { setfloodchar(flood, row, col, 'P'); setfloodchar(flood, row-1, col, 'R'); setfloodchar(flood, row, col+1, 'R'); dir = LEFT; --col; } else if (dir==DOWN && at=='J') { setfloodchar(flood, row, col, 'P'); setfloodchar(flood, row+1, col, 'L'); setfloodchar(flood, row, col+1, 'L'); dir = LEFT; --col; } else if (dir==LEFT && at=='-') { setfloodchar(flood, row, col, 'P'); setfloodchar(flood, row+1, col, 'L'); setfloodchar(flood, row-1, col, 'R'); dir = LEFT; --col; } else if (dir==UP && at=='F') { setfloodchar(flood, row, col, 'P'); setfloodchar(flood, row-1, col, 'L'); setfloodchar(flood, row, col-1, 'L'); dir = RIGHT; ++col; } else if (dir==DOWN && at=='L') { setfloodchar(flood, row, col, 'P'); setfloodchar(flood, row+1, col, 'R'); setfloodchar(flood, row, col-1, 'R'); dir = RIGHT; ++col; } else if (dir==RIGHT && at=='-') { setfloodchar(flood, row, col, 'P'); setfloodchar(flood, row-1, col, 'L'); setfloodchar(flood, row+1, col, 'R'); dir = RIGHT; ++col; } ++distance; } while (at != 'S'); // Part 2. For each character that has been marked as R, // flood fill around it to cover then entire area between // the pipes. int p2 = 0; for (int i=0; i<MAZESIZE; ++i) for (int j=0; j<MAZESIZE-1; ++j) if (mazechar(flood, i, j) == 'R') { floodfill(flood, i-1, j, 'R'); floodfill(flood, i+1, j, 'R'); floodfill(flood, i, j-1, 'R'); floodfill(flood, i, j+1, 'R'); } // Then count all the Rs. for (int i=0; i<MAZESIZE; ++i) for (int j=0; j<MAZESIZE-1; ++j) if (mazechar(flood, i, j) == 'R') ++p2; printf("Part 1: %i\nPart 2: %i\n", distance/2, p2); assert(distance/2 == 6768); assert(p2 == 351); } char mazechar(char (*maze)[MAZESIZE], int row, int col) { if (row < 0 || row >= strlen(maze[0]) || col < 0 || col > strlen(maze[0])) return '\0'; return maze[row][col]; } void setfloodchar(char (*flood)[MAZESIZE], int row, int col, char c) { if (row < 0 || row >= strlen(flood[0]) || col < 0 || col > strlen(flood[0])) return; if (flood[row][col] != 'P' && flood[row][col] != '\0') // Don't overwrite pipe. flood[row][col] = c; } void floodfill(char (*flood)[MAZESIZE], int row, int col, char c) { if (row < 0 || row >= strlen(flood[0]) || col < 0 || col > strlen(flood[0])) return; if (flood[row][col] != ' ') return; flood[row][col] = c; floodfill(flood, row-1, col, c); floodfill(flood, row+1, col, c); floodfill(flood, row, col-1, c); floodfill(flood, row, col+1, c); } void* parseinput(char* filename) { char (*maze)[MAZESIZE] = calloc(MAZESIZE*(MAZESIZE+1), sizeof (char)); FILE* fptr = fopen(filename, "r"); int i = 0; while (fgets(maze[i++], MAZESIZE+1, fptr)) ; return maze; } // Find starting point. void findstart(char (*maze)[MAZESIZE], int* startrow, int* startcol) { char* cpt; for (int l=0; l<MAZESIZE; ++l) { if (cpt = strchr(maze[l], 'S')) { *startrow = l; *startcol = cpt - maze[l]; return; } } }

Dold text
PermalÀnk
Hedersmedlem ★
●

Dag: 10 (del 1)
SprÄk: Python
Lösning: GitHub

Urk. Har inte ens gett mig pÄ del 2 Ànnu. Koden var ganska fruktansvÀrd nÀr jag vÀl fick rÀtt svar, la en del tid pÄ att stÀda upp efterÄt. Nu Àr det frÀmst PipeGrid.__init__ och huvudloopen jag inte gillar.
Gjorde det mesta i en subklass till Grid-klassen jag skapade för dag 3, fast om jag sparade nÄgot tid pÄ det Àr högst tveksamt.

Visa signatur

Asus ROG STRIX B550-F / Ryzen 5800X3D / 48 GB 3200 MHz CL14 / Asus TUF 3080 OC / WD SN850 1 TB, Kingston NV1 2 TB + NAS / Corsair RM650x V3 / Acer XB271HU (1440p165) / LG C1 55"
Mobil: Moto G200

PermalÀnk
Medlem ★
●

Dag: 11
SprÄk: Python

from itertools import combinations universe = ([(x,y) for x, s in enumerate(open("input11.txt").readlines()) for y, c in enumerate(s.strip()) if c == '#']) def expand(s, factor): d = {} offset = 0 for i in range(max(s) + 1): if i in s: d[i] = i + offset else: offset += factor - 1 return d def distances(factor): xs, ys = tuple(map(set, zip(*universe))) xt = expand(xs, factor) yt = expand(ys, factor) return sum(abs(xt[x1] - xt[x2]) + abs(yt[y1] - yt[y2]) for (x1, y1), (x2, y2) in combinations(universe, 2)) print(distances(2), distances(1000000))

Dold text
PermalÀnk
Hedersmedlem ★
●

Dag: 11
SprÄk: Python
Lösning: GitHub

FortsÀtter pÄ spÄret lÄngt och lÀttförstÄtt. Körde den naiva lösningen för del 1, och behöll den istÀllet för att skriva om den efter att del 2 var löst. Pga det sÄ Àr del 2 mer Àn dubbelt sÄ snabb som del 1 trots att den lÀgger in 1 miljon gÄnger sÄ mycket mellanrum.

Dold text
Visa signatur

Asus ROG STRIX B550-F / Ryzen 5800X3D / 48 GB 3200 MHz CL14 / Asus TUF 3080 OC / WD SN850 1 TB, Kingston NV1 2 TB + NAS / Corsair RM650x V3 / Acer XB271HU (1440p165) / LG C1 55"
Mobil: Moto G200

PermalÀnk
●
Skrivet av Thomas:

FortsÀtter pÄ spÄret lÄngt och lÀttförstÄtt. Körde den naiva lösningen för del 1, och behöll den istÀllet för att skriva om den efter att del 2 var löst. Pga det sÄ Àr del 2 mer Àn dubbelt sÄ snabb som del 1 trots att den lÀgger in 1 miljon gÄnger sÄ mycket mellanrum.

Dold text

Jag körde pÄ ett tredje alternativ som jag tror Àr lÄngsammare Àn bÄda dina.

att spara en lista pÄ tomma kolumner och rader och kontrollera mot den vid varje avstÄndsberÀkning.

Dold text
PermalÀnk
Medlem
●

Dag: 11
SprÄk: TypeScript
Lösning: GitHub

Kod
Samma kod för uppgift 1 och 2, Àndrar bara konstanten för hur mycket utrymmet vÀxer.

import { readFileSync } from 'fs' import _ from 'underscore' const FILE_PATH = './src/resources/11.txt' const GALAXY_SYMBOL = '#' // 1 for part 1, 1000000 for part 2 const SPACE_EXPANSION_COEFFICIENT = 1000000 type Map = string[][] interface Galaxy { x: number y: number } interface GalaxyPair { galaxyOne: Galaxy galaxyTwo: Galaxy } export default function (): void { const lines = readFileSync(FILE_PATH, 'utf-8').trim().split('\n') const [map, galaxies, galaxyPairs] = buildGalaxyMap(lines, SPACE_EXPANSION_COEFFICIENT) const allShortestPaths: number[] = getShortestPathForPairs(galaxyPairs) console.log('Sum of shortest paths: ', allShortestPaths.reduce((acc, next) => acc + next)) } function getShortestPathForPairs (pairs: GalaxyPair[]): number[] { const paths: number[] = [] pairs.forEach((pair) => { const shortestPath: number = Math.abs(pair.galaxyOne.x - pair.galaxyTwo.x) + Math.abs(pair.galaxyOne.y - pair.galaxyTwo.y) paths.push(shortestPath) }) return paths } function buildGalaxyMap (lines, spaceExpansionCoefficient: number): [Map, Galaxy[], GalaxyPair[]] { let map: Map = [] const galaxies: Galaxy[] = [] const pairs: GalaxyPair[] = [] // Creates the map lines.forEach((line) => { const row: string[] = [] const values = line.split('').filter(Boolean) values.forEach((val) => { if (val !== '\r') { row.push(val) } }) map.push(row) }) // Maps all the galaxies for (let y = 0; y < map.length; y++) { for (let x = 0; x < map[y].length; x++) { if (map[y][x] === GALAXY_SYMBOL) { galaxies.push({ x, y }) } } } // Creates all possible pairs for (let i = 0; i < galaxies.length - 1; i++) { for (let j = i + 1; j < galaxies.length; j++) { const pair: GalaxyPair = { galaxyOne: galaxies[i], galaxyTwo: galaxies[j] } pairs.push(pair) } } // Get points where space expands on Y axis let expansionPoints: number[] = getSpaceExpansionCoordsForRow(map) // Updates all the galaxy Y coords with space expansion in account let passes = 0 expansionPoints.forEach((point) => { const p = point + passes * (spaceExpansionCoefficient - (spaceExpansionCoefficient === 1 ? 0 : 1)) galaxies.filter((g) => g.y >= p).forEach((g) => { g.y += spaceExpansionCoefficient - (spaceExpansionCoefficient === 1 ? 0 : 1) }) passes++ }) // Inverts our map, to get expansion points for X map = _.zip(...map) // Get points where space expands on original X axis expansionPoints = getSpaceExpansionCoordsForRow(map) // Updates all the galaxy X coords with space expansion in account passes = 0 expansionPoints.forEach((point) => { const p = point + passes * (spaceExpansionCoefficient - (spaceExpansionCoefficient === 1 ? 0 : 1)) galaxies.filter((g) => g.x >= p).forEach((g) => { g.x += spaceExpansionCoefficient - (spaceExpansionCoefficient === 1 ? 0 : 1) }) passes++ }) // Reverts the 2D array back to it's original map = _.zip(...map) return [map, galaxies, pairs] } function getSpaceExpansionCoordsForRow (map: Map): number[] { const expansionsRows: number[] = [] for (let y = 0; y < map.length; y++) { let rowHasGalaxy = false for (let x = 0; x < map[y].length; x++) { if (map[y][x] === GALAXY_SYMBOL) { rowHasGalaxy = true break } } if (!rowHasGalaxy) { expansionsRows.push(y) } } return expansionsRows }

Dold text
Visa signatur

Ryzen 7 7800X3D | Nvidia Geforce RTX 4070 Ti 12gb | Corsair Vengeance DDR5 6000MHz RGB CL30 2x16GB | EVGA Supernova G2 750W | ASUS ROG Strix B650E-F Gaming | Be Quiet! Dark Rock Pro 5
Citera för svar!

PermalÀnk
Medlem
●

Dag 10 (Del 1 & 2)
SprÄk: Java
GitHub

Del 1 var ett ganska kul problem.

Dag 11 (Del 1 & 2)
SprÄk: Java
GitHub

För mycket julbord igÄr, hade svÄrt att tÀnka idag, gick ÀndÄ hyfsat.

PermalÀnk
●

Dag: 11
SprÄk: C

Jag tycker den blev ganska nÀtt och lÀttlÀst (för att vara C) Àven om den inte Àr den mest effektiva algoritmen (fast ÀndÄ klar pÄ 18 ms).

#include <assert.h> #include <stdio.h> #include <stdlib.h> // Macros. #define SIZE 140 #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MIN(a,b) ((a) < (b) ? (a) : (b)) // Data structures. typedef struct Galaxy { int row; int col; } Galaxy; typedef struct Universe { Galaxy* galaxies; char* occupiedrows; char* occupiedcols; } Universe; // Function declarations. long int distance(Universe* u, int g1, int g2, int expansionfactor); Universe* parseinput(char* filename); int main() { Universe* u = parseinput("input"); long int part1 = 0, part2 = 0; // Row and column coordinates start at (1, 1) in the upper // left corner. A row coordinate of 0 marks the end of the // initialized galaxies. Assert that there is at least one // uninitialized galaxy at the end of the list. assert(!u->galaxies[SIZE*SIZE-1].row); for (int i=0; u->galaxies[i].row; ++i) for (int j=i+1; u->galaxies[j].row; ++j) { part1 += distance(u, i, j, 2); part2 += distance(u, i, j, 1000000); } printf("Part 1: %li\nPart 2: %li\n", part1, part2); assert(part1 == 9918828); assert(part2 == 692506533832); } long int distance(Universe* u, int g1, int g2, int expansionfactor) { int maxrow = MAX(u->galaxies[g1].row, u->galaxies[g2].row); int maxcol = MAX(u->galaxies[g1].col, u->galaxies[g2].col); int minrow = MIN(u->galaxies[g1].row, u->galaxies[g2].row); int mincol = MIN(u->galaxies[g1].col, u->galaxies[g2].col); long int distance = maxrow + maxcol - minrow - mincol; for (int i=minrow+1; i<maxrow; ++i) distance += u->occupiedrows[i] ? 0 : expansionfactor - 1; for (int i=mincol+1; i<maxcol; ++i) distance += u->occupiedcols[i] ? 0 : expansionfactor - 1; return distance; } Universe* parseinput(char* filename) { Universe* u = malloc(sizeof (Universe)); u->galaxies = calloc(SIZE*SIZE, sizeof (Galaxy)); u->occupiedrows = calloc(SIZE+1, sizeof (char)); u->occupiedcols = calloc(SIZE+1, sizeof (char)); int c, row = 1, col = 1, gnum = 0; FILE* fptr = fopen(filename, "r"); while ((c = fgetc(fptr)) != EOF) { if (c == '#') { u->occupiedrows[row] = 1; u->occupiedcols[col] = 1; u->galaxies[gnum].row = row; u->galaxies[gnum++].col = col; } else if (c == '\n') { ++row; col = 0; // Will be 1 at end of loop. } ++col; } return u; }

Dold text
PermalÀnk
Datavetare ★
●

Dag: 11
SprÄk: Go

package main import ( "fmt" "os" "strings" ) type Galaxy struct { X int64 Y int64 } type IntSet map[int64]bool func ParseImage(input string) ([]Galaxy, IntSet, IntSet) { galaxies := []Galaxy{} xs := IntSet{} ys := IntSet{} for y, line := range strings.Split(input, "\n") { for x, tile := range line { if tile == '#' { galaxies = append(galaxies, Galaxy{int64(x), int64(y)}) xs[int64(x)], ys[int64(y)] = true, true } } } return galaxies, xs, ys } func Expand(galaxies []Galaxy, xs, ys IntSet, factor int64) []Galaxy { expandedGalaxies := []Galaxy{} for _, galaxy := range galaxies { expandedGalaxies = append(expandedGalaxies, Galaxy{ X: ExpandCoord(galaxy.X, xs, factor), Y: ExpandCoord(galaxy.Y, ys, factor), }) } return expandedGalaxies } func ExpandCoord(i int64, xs IntSet, factor int64) int64 { expandedI := int64(0) for j := int64(0); j < i; j++ { if xs[j] { expandedI++ } else { expandedI += factor } } return expandedI } func Distance(a, b Galaxy) int64 { return Abs(a.X-b.X) + Abs(a.Y-b.Y) } func Abs(i int64) int64 { if i < 0 { return -i } return i } func SumDistances(galaxies []Galaxy) int64 { sum := int64(0) for i := 0; i < len(galaxies); i++ { for j := i + 1; j < len(galaxies); j++ { sum += Distance(galaxies[i], galaxies[j]) } } return sum } func main() { content, _ := os.ReadFile("day11.txt") galaxies, xs, ys := ParseImage(string(content)) fmt.Println(SumDistances(Expand(galaxies, xs, ys, 2))) fmt.Println(SumDistances(Expand(galaxies, xs, ys, 1_000_000))) }

Körtid 0,29ms för ett delproblem och 0,68ms för parsing+bÄda delproblem pÄ M3, 0,34ms/0,75ms pÄ 7800X3D
Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

PermalÀnk
Medlem
●

Dag: 11
SprÄk: uiua

uiua pad dag 11 exempel

I ← ⊜(=@#)≠@\n.&fras "11.txt" Cols ← ⊚¬/ↄ I Rows ← ⊚¬≡/ↄ I Coords ← ≡(+⊙×:⊙⊙(-1)⍜°⊟⊓(/+>Rows|/+>Cols)).⊚ Dist ← Ă·2/+♭⊠(/+⌔-). Dist Coords I 2 Dist Coords I 1e6

Dold text
PermalÀnk
Medlem
●

Dag: 11
SprÄk: Scala

Scala collections Àr otroligt smidiga men tyvÀrr Àr vissa funktioner vÀldigt lÄngsamma. C2 JIT kan ha problem med att optimera, graal fungerar klart bÀttre men oftast behöver man skriva saker för hand om man vill ha bÀttre prestanda. Skrev bara om lagom mycket för att fÄ en okej benchmark. T.ex. finns det en vÀldigt lÄngsam .transpose kvar som tar upp runt 0.19ms av körtiden.

Benchmark Mode Cnt Score Error Units both avgt 5 601,310 ± 18,722 us/op dist avgt 5 163,994 ± 4,245 us/op rowsCols avgt 5 188,437 ± 20,510 us/op transpose avgt 5 184,193 ± 12,004 us/op cols avgt 5 191,901 ± 12,678 us/op rows avgt 5 1,725 ± 0,166 us/op

import scala.collection.immutable.ArraySeq import scala.io.Source import scala.util.Using object Day11: val path = """11.txt""" val input = Using.resource(Source.fromFile(path))(_.getLines().to(ArraySeq)) final case class Point(x: Long, y: Long): def distTo(that: Point) = Math.abs(that.x - x) + Math.abs(that.y - y) def points(input: ArraySeq[String], exp: Int, rows: ArraySeq[Int], cols: ArraySeq[Int]) = val buf = ArraySeq.newBuilder[Point] for y <- input.indices x <- input.head.indices if input(y)(x) == '#' do val r = rows.count(_ < y) val c = cols.count(_ < x) buf += Point(x + c * (exp -1), y + r * (exp - 1)) buf.result() def dist(p: ArraySeq[Point]): Long = var acc = 0L for i1 <- p.indices i2 <- i1 until p.length do acc += p(i1).distTo(p(i2)) acc def both = val rows = input.zipWithIndex.collect: case (line, y) if !line.contains('#') => y val cols = input.transpose.zipWithIndex.collect: case (line, x) if !line.contains('#') => x val p1 = points(input, 2, rows, cols) val p2 = points(input, 1_000_000, rows, cols) (dist(p1), dist(p2)) def main(args: Array[String]): Unit = println(both)

Körtid 0.60ms för bÄda problemen pÄ en i7-8559U
PermalÀnk
●

Dag 12 i Python

lines = open('input12.txt', 'rt').read().split('\n') combinations_cache = {} def combinations_cache_lookup(pos, group_index, group_len): v = combinations_cache.get((pos, group_index, group_len)) if v is None: v = combinations(pos, group_index, group_len) combinations_cache[(pos, group_index, group_len)] = v return v def combinations(pos, group_index, group_len): if pos == len(row): if group_len == 0: return 1 if group_index == len(groups) else 0 else: return 1 if group_index == len(groups) - 1 and groups[group_index] == group_len else 0 valid = 0 if row[pos] == '.' or row[pos] == '?': if group_len == 0: valid += combinations_cache_lookup(pos+1, group_index, 0) elif groups[group_index] == group_len: valid += combinations_cache_lookup(pos+1, group_index+1, 0) if row[pos] == '#' or row[pos] == '?': if group_index < len(groups) and group_len < groups[group_index]: valid += combinations_cache_lookup(pos+1, group_index, group_len+1) return valid res = 0 for l in lines: row, groups = l.split() groups = [int(x) for x in groups.split(',')] row = '?'.join([row] * 5) groups = groups * 5 combinations_cache.clear() valid = combinations(0, 0, 0) res += valid print(res)

Dold text
PermalÀnk
Medlem ★
●

Klarade Dag 1 ganska enkelt i Powershell (höhö, Àr ingen utvecklare). Sen blev det genast fruktansvÀrt mycket svÄrare. FÄr se om jag ger mig pÄ nÄgon nivÄ till.

Visa signatur

R7 5800X | Asus ROG Strix X570-I Gaming | 16 GB RAM | RTX 3080 | 2 TB SSD | CM NF200P | Corsair SF600

PermalÀnk
Datavetare ★
●

Dag: 12
SprÄk: Python

def parse_condition_records(input): records = [] for line in input: (record, groupsString) = line.split() groups = tuple([int(group) for group in groupsString.split(",")]) records.append((record, groups)) return records def arrangements(record, groups, memoize): key = (record, groups) result = memoize.get(key) if result is not None: return result if record == "": return 1 if len(groups) == 0 else 0 if record[0] == ".": return arrangements(record[1:], groups, memoize) n = 0 if record[0] == "?": n += arrangements(record[1:], groups, memoize) if len(groups) > 0: groupLen = groups[0] if not "." in record[:groupLen] and record[groupLen] != "#": n += arrangements(record[groupLen+1:], groups[1:], memoize) memoize[key] = n return n def sum_arrangements(records): return sum([arrangements(record+".", group, {}) for (record, group) in records]) def unfold(records): return [("?".join([record]*5), group*5) for (record, group) in records] def solve(input): records = parse_condition_records(input) print(sum_arrangements(records)) print(sum_arrangements(unfold(records))) if __name__ == "__main__": solve(open("input/day12.txt").readlines())

Dold text
Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

PermalÀnk
●

Dag 12 ger jag upp för i kvÀll. Jag har en lösning som borde funka men som inte gör det.

PermalÀnk
Medlem ★
●

Dag: 11
SprÄk: Rust
Lösning: Github
Körtid: 61/61 ms (del 1/2)

Blev inget igÄr sÄ ligger nu en dag efter, började lÀsa 12an precis men vet inte om jag orkar börja pÄ den nu. Fick iaf. klart 11 sÄ jag har chans att komma ikapp igen.

Började med riktig expandering och astar i del 1 och sÄklart blev det att tÀnka om i del 2. Eftersom den riktiga lösningen var sÄ pass enkel och del 1/2 bara Àr en parameter kastade jag del 1 och ÄteranvÀnde del 2 precis innan commit, innan lÄg del 1 precis över sekunden.

Dold text
PermalÀnk
Medlem
●

Dag 12 (Del 1 & 2)
SprÄk: Java
GitHub

Helvete.
Kan inte sÀga att jag inte kollade efter.. hjÀlp..inspiration.. eller nÄgonting som funkade idag.
Det var hemskt.

PermalÀnk
Medlem ★
●

Dag: 12, del 1
SprÄk: Rust
Lösning: Github
Körtid: 0.1 ms (del 1)

Vem försökte jag lura, kunde sÄklart inte slÀppa det sÄ började pÄ dag 12. Del 2 tar dock för mycket tid sÄ fÄr sluta för idag.

Har fortfarande inte ens lyckats köra igenom rad 2 i exemplet, misstÀnker att det Àr .multi_cartesian_product() som Àr en totalt ohÄllbar lösning. Har funderat pÄ om jag kan flytta checken för att alla # Àr med innan den, för att Ätminstone skÀra ner explosionen av varianter, men Àr för trött för att hitta pÄ nÄgot just nu.

Dold text
PermalÀnk
Medlem ★
●
Skrivet av Yoshman:

Dag: 12
SprÄk: Python

def parse_condition_records(input): records = [] for line in input: (record, groupsString) = line.split() groups = tuple([int(group) for group in groupsString.split(",")]) records.append((record, groups)) return records def arrangements(record, groups, memoize): key = (record, groups) result = memoize.get(key) if result is not None: return result if record == "": return 1 if len(groups) == 0 else 0 if record[0] == ".": return arrangements(record[1:], groups, memoize) n = 0 if record[0] == "?": n += arrangements(record[1:], groups, memoize) if len(groups) > 0: groupLen = groups[0] if not "." in record[:groupLen] and record[groupLen] != "#": n += arrangements(record[groupLen+1:], groups[1:], memoize) memoize[key] = n return n def sum_arrangements(records): return sum([arrangements(record+".", group, {}) for (record, group) in records]) def unfold(records): return [("?".join([record]*5), group*5) for (record, group) in records] def solve(input): records = parse_condition_records(input) print(sum_arrangements(records)) print(sum_arrangements(unfold(records))) if __name__ == "__main__": solve(open("input/day12.txt").readlines())

Dold text

Jag har en lösning som Àr vÀldigt lik din, och dÀr jag efter lite för mÄnga timmar av trial and error som jag inte Àr sÄ stolt över ocksÄ kommit fram till att man behöver lÀgga till en avslutande punkt innan man skickar in vÀrdet i den rekursiva snurran. Varför behövs den..? (Eller snarare, varför fÄ man fel resultat utan den..?) Rekursion Àr smÄkul, men inte att debugga...

Den hÀr biten frÄn din kod:
results.append(analyze_list("?".join([line.split()[0]]*5)+".", tuple([int(i) for i in line.split()[1].split(",")*5])))
print(sum(results))

memoized = {} def analyze_list(str, groups): if (str, groups) in memoized: value = memoized[(str, groups)] return value if len(str) == 0: if len(groups) == 0: return 1 else: return 0 res = 0 if str[0] == ".": res += analyze_list(str[1:], groups) elif str[0] == "?": res += analyze_list("." + str[1:], groups) res += analyze_list("#" + str[1:], groups) elif str[0] == "#": if len(groups) > 0: i = 0 while i < len(str) and str[i] != ".": i+=1 if i >= groups[0] and len(str) > groups[0] and str[groups[0]] != "#": res += analyze_list(str[groups[0]+1:], groups[1:]) memoized[(str, groups)] = res return res with open('input.txt') as file: lines=file.read().splitlines() results = [] for line in lines: results.append(analyze_list(line.split()[0], tuple([int(i) for i in line.split()[1].split(",")]))) print(sum(results)) results = [] for line in lines: results.append(analyze_list("?".join([line.split()[0]]*5)+".", tuple([int(i) for i in line.split()[1].split(",")*5]))) print(sum(results))

Dold text
PermalÀnk
Datavetare ★
●
Skrivet av jaqob:

Jag har en lösning som Àr vÀldigt lik din, och dÀr jag efter lite för mÄnga timmar av trial and error som jag inte Àr sÄ stolt över ocksÄ kommit fram till att man behöver lÀgga till en avslutande punkt innan man skickar in vÀrdet i den rekursiva snurran. Varför behövs den..? (Eller snarare, varför fÄ man fel resultat utan den..?) Rekursion Àr smÄkul, men inte att debugga...

Den hÀr biten frÄn din kod:
results.append(analyze_list("?".join([line.split()[0]]*5)+".", tuple([int(i) for i in line.split()[1].split(",")*5])))
print(sum(results))

memoized = {} def analyze_list(str, groups): if (str, groups) in memoized: value = memoized[(str, groups)] return value if len(str) == 0: if len(groups) == 0: return 1 else: return 0 res = 0 if str[0] == ".": res += analyze_list(str[1:], groups) elif str[0] == "?": res += analyze_list("." + str[1:], groups) res += analyze_list("#" + str[1:], groups) elif str[0] == "#": if len(groups) > 0: i = 0 while i < len(str) and str[i] != ".": i+=1 if i >= groups[0] and len(str) > groups[0] and str[groups[0]] != "#": res += analyze_list(str[groups[0]+1:], groups[1:]) memoized[(str, groups)] = res return res with open('input.txt') as file: lines=file.read().splitlines() results = [] for line in lines: results.append(analyze_list(line.split()[0], tuple([int(i) for i in line.split()[1].split(",")]))) print(sum(results)) results = [] for line in lines: results.append(analyze_list("?".join([line.split()[0]]*5)+".", tuple([int(i) for i in line.split()[1].split(",")*5]))) print(sum(results))

Dold text

Rent strikt behövs inte den extra punkten, men det denna rad blir enklare dÄ man inte behöver hantera fallet att man indexerar beyond-end i "record" pÄ denna rad.

if not "." in record[:groupLen] and record[groupLen] != "#":

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

PermalÀnk
Medlem ★
●
Skrivet av Yoshman:

Rent strikt behövs inte den extra punkten, men det denna rad blir enklare dÄ man inte behöver hantera fallet att man indexerar beyond-end i "record" pÄ denna rad.

if not "." in record[:groupLen] and record[groupLen] != "#":

Jag hanterar det, sÄ bÄde fallet med och utan punkt exekverar, men utan punkten fÄr jag ett felaktigt, nÄgot lÀgre, svar. Men men, Àr vÀl bara att sÀtta sig och jÀmföra output

Tack för svaret!

if i >= groups[0] and len(str) > groups[0] and str[groups[0]] != "#":

Edit: Nu funkar det utan punkten, Àven om jag Àr lite osÀker pÄ exakt varför.

Dag 12
SprÄk Python

memoized = {} def analyze_list(str, groups): if (str, groups) in memoized: value = memoized[(str, groups)] return value if len(str) == 0: if len(groups) == 0: return 1 else: return 0 res = 0 if str[0] == ".": res += analyze_list(str[1:], groups) elif str[0] == "?": res += analyze_list("." + str[1:], groups) + analyze_list("#" + str[1:], groups) elif str[0] == "#": if len(groups) > 0: i = 0 while i < len(str) and len(str) >= groups[0] and str[i] != ".": i+=1 if i >= groups[0] and (len(str) == groups[0] or str[groups[0]] != "#"): res += analyze_list(str[groups[0]+1:], groups[1:]) memoized[(str, groups)] = res return res with open('input.txt') as file: lines=file.read().splitlines() results = [] for line in lines: results.append(analyze_list(line.split()[0], tuple([int(i) for i in line.split()[1].split(",")]))) print(sum(results)) results = [] for line in lines: results.append(analyze_list("?".join([line.split()[0]]*5), tuple([int(i) for i in line.split()[1].split(",")*5]))) print(sum(results))

Dold text
PermalÀnk
Hedersmedlem ★
●

Dag: 13
SprÄk: Python
Lösning: GitHub

Det tog en stund, framför allt del 2 dÀr jag hade ett fel i logiken som tog ett tag att hitta.

Visa signatur

Asus ROG STRIX B550-F / Ryzen 5800X3D / 48 GB 3200 MHz CL14 / Asus TUF 3080 OC / WD SN850 1 TB, Kingston NV1 2 TB + NAS / Corsair RM650x V3 / Acer XB271HU (1440p165) / LG C1 55"
Mobil: Moto G200

PermalÀnk
Datavetare ★
●

Dag: 13
SprÄk: Python

TÀnkte göra en liten annorlunda lösning, anvÀnder bitoperationer pÄ heltal dÀr satt bit Àr "#" och slÀckt bit Àr ".". Blev inte sÄ enkelt jag tÀnkt mig, nog mer "varför fungerar ens det hÀr" kÀnsla.

from copy import deepcopy def parse_pattern(pattern): width, height = len(pattern[0]), len(pattern) hs, vs = [0] * height, [0] * width for y, line in enumerate(pattern): for x, tile in enumerate(line): if tile == "#": hs[y] += 1 << x vs[x] += 1 << y return ((hs, (1 << width) - 1), (vs, (1 << height) - 1)) def parse_patterns(input): return [parse_pattern(pattern.split()) for pattern in input.split("\n\n")] def reflection(ns, mask, wantedMirrorDiff): ns = deepcopy(ns) ms, mmask = [0] * len(ns), 1 mirrorIndex = 1 while True: mask >>= 1 if mask == 0: return 0 mirrorDiff = 0 for i in range(len(ns)): ms[i] = (ms[i] << 1) + (ns[i] & 1) ns[i] >>= 1 mirrorDiff += ((ms[i] ^ ns[i]) & mask & mmask).bit_count() if mirrorDiff == wantedMirrorDiff: return mirrorIndex mmask = (mmask << 1) + 1 mirrorIndex += 1 def summarize(patterns, mirrorDiff=0): return sum( [ reflection(hs, hMask, mirrorDiff) + 100 * reflection(vs, vMask, mirrorDiff) for (hs, hMask), (vs, vMask) in patterns ] ) def solve(input): patterns = parse_patterns(input) print(summarize(patterns)) print(summarize(patterns, 1)) if __name__ == "__main__": solve(open("input/day13.txt").read())

Dold text
Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

PermalÀnk
Medlem ★
●

Dag: 13
SprÄk: Python

import numpy as np toggle = { '#' : '.', '.' : '#'} def fm(a): return [i + 1 for i in range(0, a.shape[0] // 2) if (a[0: i + 1] == np.flip(a[i + 1: (i + 1) * 2 ], 0)).all()] def find_mirrors(a): return fm(a) + list(map(lambda b: a.shape[0] - b, fm(np.flip(a, 0)))) def fs(a): for i in range(0, a.shape[0] // 2): ne = a[0: i + 1] != np.flip(a[i + 1: (i + 1) * 2 ], 0) if (ne).sum() == 1: pos = tuple(*zip(*np.where(ne))) a[pos] = toggle[a[pos]] return True def fix_smudge(a): return fs(a) or fs(np.flip(a, 0)) s1 = s2 = 0 for x in open("input13.txt").read().split('\n\n'): a = np.array([[c for c in l] for l in x.split('\n')]) m1 = list(map(lambda a: a * 100, find_mirrors(a))) + find_mirrors(a.T) fix_smudge(a) or fix_smudge(a.T) m2 = list(map(lambda a: a * 100, find_mirrors(a))) + find_mirrors(a.T) s1 += sum(set(m1)) s2 += sum(set(m2) - set(m1)) print(s1, s2)

Dold text