Inlägg

Inlägg som Ingetledigtnamn har skrivit i forumet
Av Ingetledigtnamn

S2 av The Tower på HBO. På Imdb har den bara 6.9 i betyg och det tycker jag är oförtjänt lågt. Åtminstone för S2 kan jag sträcka mig till en 8/10.

Av Ingetledigtnamn
Skrivet av OldComputer:

Utan HT? Man föreställer sig vad det innebär... Speciellt för Windows ...

Hyperthreading ser till att du får bättre användning, utlization, av din superskalära processors funktionsenheter. Kör man bara med en instruktionsström kommer det vara svårt för processorn att utnyttja alla möjligheter att exekvera instruktioner parallellt, men i normalfallet kommer ingen sakna hyperthreading. Numera finns det tillräckligt många kärnor att köra på. Det kommer att gå finfint i Windows. Du kommer tappa lite i Cinebench, men vem bryr sig?

Av Ingetledigtnamn
Skrivet av Erik_T:

Det är visserligen görbart att (i de flesta fall) identifiera en Bubblesort och byta mot en Quicksort, men det är inte en optimering en kompilator bör göra då algoritmerna inte har ekvivalenta resultat. Bubblesort är en stabil sorteringsalgoritm till skillnad från Quicksort, och i en hel del fall kan det spela roll.

Tyckte jag sade att det var en optimering som en komplator inte skulle göra. Att den inte är stabil är en anledning till att den definitivt inte får göra den då det ändrar funktionens resultat.

Av Ingetledigtnamn

Nu har jag sett en del uttalanden som jag känner att jag måste kommentera.

Skrivet av Perkoff:

Kompilatorn är faktiskt så smart att den transformerar om all din kod till att använda en optimal algoritm för ändamålet. Om du sätter optimeringsflaggan så kommer den t.ex. byta ut bubblesort mot quicksort, o.s.v.

Nej, det har jag svårt att tro. Kompilatorn har visserligen ganska mycket frihet att göra som den vill, bara den löser samma uppgift som den ursprungliga koden, men att byta en algoritm mot en annan är lite att ta i. Det finns gränser för hur mycket frihet kompilatorn har. Den genererade koden måste bete på samma sätt som den ursprungliga koden och om man skickar in "felaktiga" parametrar så skall den generade koden få fel på samma sätt. Att byta en Bubblesort mot en Quicksort är görbart, man kan mönstermatcha den inkommande koden och känna igen att det är en Bubblesort och stoppa in ett anrop till quicksort istället. Det kan tänkas att någon kompilatorskrivare tyckt det var ett cool hack och gjort det (på kul), men det ändrar på funktionens stackanvändning. I embeddedvärlden kan man ha en begränsad stack och valt en sämre sorteringsalgoritm just för att den använder lite stack. Då vill man inte att kompilatorn byter till en algoritm som resulterar i stack overflow.

Skrivet av talonmas:

Folk som faktiskt är i behov av att optimera, de tar tid på sina saker. Och ofta är det nån enstaka rutin det handlar om, och inte alltför sällan en databasläsning inblandad. Då har du SQL motorn att ta hänsyn till också.

Fast din fråga kanske var mer av akademisk karaktär och du är nyfiken på hur avancerade kompilatorer är idag?

Korta svaret är att inline assembler sällan gör det snabbare idag jämfört mot 20 år sedan då det användes frekvent. Att den byter ut hela algoritmer som nån ovan nämnde är jag mer skeptisk till, men läser gärna på om någon har info om det.

Du har helt rätt i att man skall mäta in innan börja handoptimera koden. Det spelar ingen roll om man snabbar upp en funktion 100x om man inte spederar mer än 1% av tiden i den. Om allt drunknar i databasoperationer kommer det inte att märkas på körtiden hur mycket du än filar på dina algoritmer. Då är det nog bättre att fundera på om man kan formulera om sina querys så de går fortare.

Här är verktyg som Intels VTune till stor hjälp. Det är lite tröskel att komma igång med VTune, men VTune kan mer än gamla vanliga profilers. Det kan vara värt att lägga lite tid på att lära sig.

Dock likställer du "optimering" med speed-optimering men kompilatorerna kan även optimera för size (-Os för GCC), dvs. generera så liten kod som möjligt. Det är viktigt inom embedded-industrin att hålla ner kodstorleken. Om koden sväller och inte ryms i den krets man valt är det problematiskt...

Lite förenklat kan vi se det som att valet står mellan att optimera mot ett så litet program som möjligt eller mot att exekvera så få instruktioner som möjligt. Oftast går speed och size hand i hand. Färre instruktioner tar kortare tid att köra. Klassiska optimeringar som

  • Dead Code Elimination - Kommer ingen använda resultatet av denna uträkning finns det ingen anledning att utföra den.

  • Constant Folding/Constant Propagation - Om kompilatorn vet att operanderna till en operation har konstanta värden kan man räkna ut resultatet vid compile time och slippa göra saker under runtime

  • Peephole Optimizations - Leta efter fall där det finns ett effektivare sätt att utföra en instruktionssekvens. Exempelvis adresserings-moder med pre- eller post-inkrement. Två flugor med en smäll om man kan göra inkrementet samtidigt som minnesaccessen.

handlar typiskt om att inte göra saker i onödan. Den onödiga instruktionen som kompilatorn lyckas optimera bort sparar både exekveringstid och kodstorlek.

En ren size-optimering är Unreachble Code Removal. Hittar kompilatorn kod som den bevisa att den aldrig kommer exekveras kan den ta bort den koden. Man kan tycka att det inte borde finnas onåbar kod i ett program. Ingen borde skriva kod efter return eller ta med en case-sats för värden som aldrig kommer förekomma, men efter att andra optimeringar gjort sitt jobb visar det sig ofta att kod blir onåbar.

Vi har andra optimeringar som är kodstorleksneutrala men syftar till att dynamiskt köra färre instruktioner. Exempel på en sådan är Loop-invariant code hosting. Om kompilatorn kan identifiera att (del-)uttyck i en loop inte beror på loop-variabeln kan man räkna ut dessa utanför loopen. Exempelvis i

int a[...][...]; for (int i = 0; i < x; ++i) { for (int j = 0; j < y; ++j) { a[i][j] = ... } }

är a[i] bara beroende av i och kan utföras utanför den innersta loopen:

int a[...][...]; for (int i = 0; i < x; ++i) { int *tmp = &a[i][0]; for (int j = 0; j < y; ++j) { tmp[j] = ... } }

(Denna optimering höjer registertrycket lite så om tmp tränger ut någon annan variabel från ett register är optimeringen inte helt kodstorleksneutral.)

Exempel på optimeringar som offrar size för speed är

  • Function Inlining - Här byter man ut funktionsanropet mot kroppen på den anropade funktionen. Detta möjliggör att funktionskroppen kan skräddarsys för de aktuella parametrarna. Om en del av parametrarna var konstanter kommer man kunna applicera Constant Folding, förenkla uttryck och kanske upptäcka att ett villkor blir sant/falskt och en halva av en if-else-sats blir unreachable. Om man tog adressen av en parametrarna kanske den inte längre har adresen tagen och man kan registerallokera variablen istället för att ha den på stacken.

  • Loop Unrolling - Vid loop unrolling lägger man flera kopior av loopkroppen efter varandra. Detta ger kompilatorn möjlighet att optimera mellan loopkropparna vilket kan ge utdelning ibland. Viktigare är dock att det ger en modern CPU med Out-of-Order-execution längre sammanhängande sektioner med rak kod.

Man kan även offra speed för size. Exempelvis genom att hitta likadana instruktionssekvenser på olika ställen i koden. Om det är i slutet av ett antal funktioner, där man typiskt skall poppa ett antal värden från stacken och returnera, kan man helt enkelt byta ut den sekvensen mot ett hopp rakt in i en annan funktion som kör samma instruktionenssekvens. Om instruktionssekvensen är tillräckligt stor kan dett vara värt att bryta ut den till en separat subrutin och göra funktionsanrop.

Skrivet av riche:

I embedded värden är det vanligt att inte köra med allt för mycket optimering.
De lägre optimerings flaggorna till gcc kan till och med göra assemblern läsbar *hint*

De högre kan göra väldigt mysko saker...

Du har lite issues i den där koden, några har påpekats.

Japp, den optimerade koden har ofta förvandlats till något som inte alls ser ut som källkoden, men beroende på vilken kompilator du kör finns det ofta kommentarer insprängda i den genererade koden som "pekar tillbaka" till källkoden. Det är dock inte säkert att hjälper när man försöker förstå vad som egentligen händer

Om du tillhör "embeddedvärlden" rekommenderar jag att du kör med size-optimering påslaget. Man kör i princip alla optimeringar utom de som offrar size för speed. De klassiska kompilatoroptimeringarna ger ofta märkbar förbättring av både kodstorlek och exekeringstid.

Skrivet av heretic16:

En liten svår fråga. Men vi säger att jag har en kod som kopierar samma array 100 gånger, än fast det behövs bara en gång. Om jag sätter en optimeringsflagga, kommer då koden ta bort all onödiga iterationer eller kodrader då?

Vi kan ta detta exempel. Här är två kodsnuttar. Dom gör exakt samma sak. Skillnaden är att en är mer optimerad. Dock så visar Godbolt att angleanalysis2 genererar mindre assemblerkod än angleanalysis1.

Jag vet att man ska prioritera att skriva läsbar kod, istället för superavancerad som är optimerad. Man ska alltså låta kompilator sköta denna del. Men ibland så kan det vara bra att optimera för hand också igenom att minska på antalet iterationer.

Och nu till TS fråga: Hur mycket optimerar en kompilator? En modern kompilator optimerar mycket. Du skall dock ha realistiska förväntningar. Kompilatorn måste hålla sig till språkstandarden och vara beredd på att en variabel kan innehålla vilka värden som helst. Du som programmerare vet nästan alltid mer än kompilatorn. Du vet saker som att värdena kommer hålla sig i en viss range och att a alltid kommer vara mindre än b och c. Detta gör att man kanske förväntar sig att kompilatorn skall optimera saker som den inte får göra om den skall hålla sig till språkstandarden och kunna hantera alla randvärden korrekt.

Kompilatorn kommer inte att byta ut en kass algoritm mot en bättre.

Dina två exempel gör inte exakt samma sak. Detta är ett exempel på när du vet mer än kompilatorn. Finns anglevector i en annan modul vet inte kompilatorn något om den funktionen annat än den info som finns i prototypen.
Kompilatorn kan tänkas upptäcka att saker du gör i en inre loop är invariant och lyfta ut detta ut loopen men det kan bara ske om den kan bevisa att anglevector inte ändrar i minnesblocket vector_A pekar på. Annars måste memcpy(vector_A, ...); utföras för att samma värden skall skickas in till anglevector. Svaret på din fråga är alltså: det beror på. Har du sagt restrict i prototypen? Är det pekare till const-data? Du får helt enkelt testa och se vilken kod som den kompilator genererar.

Men som @talonmas så klokt påpekade, har du mätt och konstaterat att detta är ett problem? Om det inte är tidskritiskt, skriv så enkel och lättläst kod som möjligt.

För den som är intresserad av kompilatoroptimeringar finns mycket mer på Wikipedia.

Vill ni pröva på lite lågnivåprogrammering rekommenderar jag Human Resource Machine. Man skall skriva små program som styr en arbetare (CPU). Har för mig att det var ett femtiotal uppgifter att lösa och det finns både speed- och size-challenges. Kostar en 50-lapp på Steam och är väl värt sina pengar.

Av Ingetledigtnamn

Dag: 16
Språk: Python

import numpy as np a = np.array([[c for c in l.strip()] for l in open("input16.txt").readlines()]) a = np.pad(a, 1, constant_values='#') E, W, S, N = 0, 1, 2, 3 xoffset = [1, -1, 0, 0] yoffset = [0, 0, 1, -1] def forward(x, y, dir, e): return x + xoffset[dir], y + yoffset[dir], dir def splitNS(x, y, dir, e): # | if dir in [N, S]: return forward(x, y, dir, e) follow(x, y + yoffset[N], N, e) return x, y + yoffset[S], S def splitEW(x, y, dir, e): if dir in [E, W]: return forward(x, y, dir, e) follow(x + xoffset[E], y, E, e) return x + xoffset[W], y, W def reflectNE(x, y, dir, e): return x + [ 0, 0, -1, 1][dir], y + [-1, 1, 0, 0][dir], [ N, S, W, E][dir] def reflectNW(x, y, dir, e): return x + [ 0, 0, 1, -1][dir], y + [ 1, -1, 0, 0][dir], [ S, N, E, W][dir] def follow(x, y, dir, e): while f := (forward, splitNS, splitEW, reflectNE, reflectNW, None)[".|-/\\#".find(a[y, x])]: if e[y, x] & (1 << dir): return e e[y, x] |= 1 << dir x, y, dir = f(x, y, dir, e) return e def beam(x, y, dir): return (follow(x, y, dir, np.zeros(a.shape, dtype=np.int_))[1:-1, 1:-1] != 0).sum() print(beam(1, 1, E), max(max([beam(1, i, E) for i in range(a.shape[0])]), max([beam(a.shape[1] - 2, i, W) for i in range(a.shape[0])]), max([beam(i, 1, S) for i in range(a.shape[1])]), max([beam(i, a.shape[0] - 2, N) for i in range(a.shape[1])])))

Dold text
Av Ingetledigtnamn

Dag: 15
Språk: Python

from functools import reduce from operator import itemgetter l = open("input15.txt").read().strip().split(',') def hash(s): return reduce(lambda a, b: (a + ord(b)) * 17 % 256, s, 0) def part1(l): return sum(map(hash, l)) def part2(l): boxes = [[] for _ in range(256)] for s in l: if s[-1] == '-': ndx, label = hash(s[:-1]), s[:-1] boxes[ndx] = list(filter(lambda a: a[0] != label, boxes[ndx])) else: ndx, label, lens = hash(s[:-2]), s[:-2], int(s[-1]) try: i= list(map(itemgetter(0), boxes[ndx])).index(label) boxes[ndx][i][1] = lens except ValueError: boxes[ndx].append([label, lens]) return sum([(i + 1) * (j + 1) * l for i,b in enumerate(boxes) for j, (_, l) in enumerate(b)]) print(part1(l), part2(l))

Dold text
Av Ingetledigtnamn

Dag: 14
Språk: Python

import numpy as np from itertools import groupby, filterfalse, pairwise, count a = np.array([[c for c in l.strip()] for l in open("input14.txt").readlines()]) a = np.pad(a, 1, constant_values='#') def tilt_east(a): """To the east, sorting order :)""" for l in a[1:-1]: for start, stop in pairwise(np.where(l == '#')[0]): l[start + 1: stop] = sorted(l[start + 1: stop]) return a def load(a): return np.where(np.flip(a, axis=0) == 'O')[0].sum() def spin_cycle(a): a = np.rot90(a, -1) for _ in range(4): a = np.rot90(tilt_east(a), -1) return np.rot90(a, 1) def part1(a): return load(np.rot90(tilt_east(np.rot90(a, -1)), 1)) def part2(a): history = dict() saved = [None] for i in count(1): t = tuple([tuple(l) for l in spin_cycle(a)]) saved.append(t) if cycle_start := history.get(t, 0): return load(np.array(saved[(1000000000 - cycle_start) % (i - cycle_start) + cycle_start])) history[t] = i print(part1(a), part2(a))

Dold text
Av Ingetledigtnamn

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
Av Ingetledigtnamn

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
Av Ingetledigtnamn

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
Av Ingetledigtnamn

Dag: 9
Språk: Python (lite numpy)

import numpy as np from functools import reduce def diffs(l): while (l[-1] != 0).any(): d = np.diff(l[-1]) l.append(d) return l differences = [diffs([np.fromiter(map(int, l.split()), dtype=np.int_)]) for l in open("input09.txt").readlines()] print(sum([sum(map(lambda a: int(a[-1]), ds)) for ds in differences]), sum(reduce(lambda a, b: b - a, list(map(lambda a: int(a[0]), ds))[::-1]) for ds in differences))

Dold text
Av Ingetledigtnamn

Dag: 8
Språk: Python

Uppgiften var snäll så till vida att cykellängden sammanföll med längden till första stoppnoden, så jag räknar ut den istället för längden på en cykel.

from math import gcd from functools import reduce instructions, maps = tuple(open("input08.txt").read().split('\n\n')) nodes = {l[0:3] : (l[7:10], l[12:15]) for l in maps.splitlines()} def walk(pos, done): steps = 0 while not done(pos): for direction in instructions: pos = nodes[pos]["LR".index(direction)] steps += 1 return steps print(walk('AAA', lambda x: x == 'ZZZ'), reduce(lambda a, b: (a * b) // gcd(a,b), map(lambda x: walk(x, lambda p: p.endswith('Z')), [x for x in nodes.keys() if x.endswith('A')])))

Dold text
Av Ingetledigtnamn

Dag: 7
Språk: Python

Ganska elegant i dag.

from collections import Counter hands = list(map(lambda l: (l[0], Counter(l[0]), int(l[1])), [line.strip().split() for line in open("input07.txt").readlines()])) def part1(e): return ("".join(map(str, sorted(e[1].values(), reverse=True))), tuple(map(lambda card: "23456789TJQKA".index(card), e[0]))) def part2(e): js = e[1].pop('J', 0) if l := sorted(e[1].values(), reverse=True): l[0] += js else: l = [5] return ("".join(map(str, l)), tuple(map(lambda card: "J23456789TQKA".index(card), e[0]))) print([sum(map(lambda h: (h[0] + 1) * h[1][2], enumerate(sorted(hands, key = sorter)))) for sorter in [part1, part2]])

Dold text
Av Ingetledigtnamn

Dag: 6
Språk: Python (One-liner)

Dagens uppgift var inte särskilt svår. Jag trodde jag skulle behöva intervallhalvera för att hitta punkterna där man började och slutade vinna, men det var inga som helst probelm att brute-force:a ens i Python.

import re from math import prod print([f(lambda t: [x for i in range(t[0]) if (x := i * (t[0] - i)) > t[1]]) for f in [lambda f: prod(map(len, map(f, zip(*[list(map(int, re.findall(r"\d+", line))) for line in open("input06.txt").readlines()])))), lambda f: len(f(tuple(map(int, ["".join(re.findall(r"\d+", line)) for line in open("input06.txt").readlines()]))))]])

Dold text
Av Ingetledigtnamn

Dag: 5
Språk: Python

Det blev ganska normal Python den här gången. Namngivna funktioner och variabler för tydlighetens skull

import re numbers = re.compile(r'\d+') blobs = open("input05.txt").read().split('\n\n') seeds = list(map(int, numbers.findall(blobs[0]))) tables = [[ns for line in blob.split('\n') if (ns := list(map(int, numbers.findall(line))))] for blob in blobs[1:]] def pointinrange(p, r): return r[0] <= p < r[0] + r[1] def rangeinrange(r1, r2): return pointinrange(r1[0], r2) and pointinrange(r1[0] + r1[1] - 1, r2) def lookuprange(r, table): rs, rl = r for d,s,l in table: r2 = (s,l) if rangeinrange(r, r2): return [(rs + (d - s), rl)] elif rangeinrange(r2, r): # split into three ret = [] if outside := s - rs: ret.extend(lookuprange((rs, outside), table)) ret.append((d, l)) if outside := rl - l - (s - rs): ret.extend(lookuprange((s + l, outside), table)) return ret elif pointinrange(rs, r2): end = s + l inside = end - rs outside = rl - inside return [(rs + (d - s), inside)] + lookuprange((end, outside), table) elif pointinrange(rs + rl - 1, r2): outside = s - rs return lookuprange((rs, outside), table) + [(d, rl - outside)] return [r] def lookupranges(ranges, tables): for t in tables: newkeys = [] for r in ranges: newkeys.extend(lookuprange(r, t)) ranges = newkeys return ranges print(min([min(lookupranges([(s,1)], tables)) for s in seeds])[0], min([min(lookupranges([p], tables)) for p in zip(seeds[0::2], seeds[1::2])])[0])

Dold text
Av Ingetledigtnamn

Dag: 4
Språk: Python

Blev ganska elegant i dag.

def collect_cards(winning_numbers): counts = [1] * len(winning_numbers) for i, win in enumerate(winning_numbers): for j in range(i + 1, i + 1 + win): counts[j] += counts[i] return sum(counts) winning_numbers = [len(set.intersection(*list(map(lambda ns: set(int(n) for n in ns.split(" ") if n), line.split(":")[1].split("|"))))) for line in open("input04.txt").readlines()] print(sum(map(lambda count: (1 << count) // 2, winning_numbers)), collect_cards(winning_numbers))

Dold text
Av Ingetledigtnamn

Dag: 3
Språk: Python (Ingen one-liner, men Numpy kan en hel del trix)

import numpy as np from functools import reduce from math import prod # Read file, add extra '.'s around it so we don't need to worry about indexing outside the array a = np.pad(np.array([list(line.strip()) for line in open("input03.txt").readlines()]), 1, constant_values='.') # Find the symbols and mark the elements around them adjacent = reduce(np.logical_and, [a != c for c in '.0123456789']) adjacent |= np.roll(adjacent, -1, axis = 0) | np.roll(adjacent, 1, axis = 0) adjacent |= np.roll(adjacent, -1, axis = 1) | np.roll(adjacent, 1, axis = 1) # Find the coords for each digit, gives a collect of x coordinates and collection of y coordinates digit_coords = np.where(np.char.isdigit(a)) # Find where a sequence of digits ends split_after = np.logical_or(np.diff(digit_coords[0]) != 0, np.diff(digit_coords[1]) != 1) # Convert slpit_after into indexes split_points = np.where(split_after == True) # Split the digit coordinates into chunks of sequential digits number_coords = np.split(np.array(digit_coords), split_points[0] + 1, axis = 1) # Set each cell to the value of the digit sequence it is a part of ratios = np.zeros(a.shape, dtype=np.int_) for nc in number_coords: ratios[tuple(nc)] = int("".join(a[tuple(nc)])) # If any of digits are adjacent to a symbol, include it in the sum print(sum([int("".join(a[tuple(nc)])) for nc in number_coords if np.any(adjacent[tuple(nc)])]), # Find all the numbers next to a '*'. If more than 1, include the product of the numbers in the sum sum([prod(s) for g in zip(*np.where(a == '*')) if len(s:= set([x for x in ratios[(g[0] + np.array([-1, -1, -1, 0, 0, 1, 1, 1]), g[1] + np.array([-1, 0, 1, -1, 1, -1, 0, 1]))] if x])) > 1]))

Dold text
Av Ingetledigtnamn

Dag: 2
Språk: Python (One-liner)

import re from functools import reduce print( (lambda f1, f2, l: (f1(l), f2(l))) (lambda l: sum([t[0] for t in l if t[1] <= 12 and t[2] <= 13 and t[3] <= 14]), lambda l: sum(t[1] * t[2] * t[3] for t in l), [reduce(lambda a,b : tuple(map(max, zip(*map(lambda v: map(lambda s: int('0' + str(s)), v), [a, b])))), m) for m in [[matches for matches in re.findall(r"Game (\d+)|(\d+) red|(\d+) green|(\d+) blue", line)] for line in open("input02.txt").readlines()]]) )

Dold text

Med kommentarer. Börja inifrån och läs dem i nummerordning.

print( # 13. Apply part 1 and part 2 on the list (lambda f1, f2, l: (f1(l), f2(l))) # 12. Part 1 Accumulate game (t[0]) if the element was possible (lambda l: sum([t[0] for t in l if t[1] <= 12 and t[2] <= 13 and t[3] <= 14]), # 13. Sum the power for each element in the list lambda l: sum(t[1] * t[2] * t[3] for t in l), # 4. Reduce "accumulates" a list by applying a function to the accumulator # and each element in the list. Here we want to collect the max of each # match in list to get the highest values. To compute the max of two # matches (a and b) we want to apply max to each pair of elements in a # and b. Max does work for strings, but unfortunately "5" is greater # than "15" so we have to convert the values to integers first. It gets # a bit messy. # # 11. Apply 10 to each element in the list to compute the max values for # game, red, green, and blue. The result is a list with all the max # values per line. # # 10. Apply max to each pair in (a[0], b[0]), # (a[1], b[1]),... [reduce(lambda a,b : tuple(map(max, # 9 Zip a and b together, now we get # (a[0], b[0]), (a[1], b[1]),... zip( # 8. The * operator converts the list # in zip([A, B]) to zip(A, B) # 7. Map the match conversion function # (6) to both a and b # 6: Map the conversion function # (5) to each game, red, green, # blue component in a match. Now # the red 6 match is on the # form [0, 6, 0, 0] *map(lambda v: # 5. Convert a value to an int. The # "0" part ensures '' gets the # value 0 and str(s) converts the # integer value in the accumulator # to a string so it can be # concateted with the '0'. Convert # the string to an int. map(lambda s: int('0' + str(s)), v), [a, b])))), m) # 3. Collect all the matches per line in m # 2: Per number in the input line the regex produces a match on the # form (game, red, gren, blue). All the non-matched entries are # empty strings so 'red 6' would generate ('', '6', '', ''). for m in [re.findall(r"Game (\d+)|(\d+) red|(\d+) green|(\d+) blue", line) # 1: Read all lines in the imput file for line in open("input02.txt").readlines()]]) )

Dold text
Av Ingetledigtnamn
Skrivet av woostie:

I guess the overlaps could have been done with more regex...

Dold text

oneightwoneightwone...

Dold text
Av Ingetledigtnamn

Dag: 1
Språk: Python 3 (One-liner, eller i alla fall ett uttryck)

Som så många andra sagt: ovanligt elak del två för att vara första dagen. Om man satsade på strängsubstitution fanns det många möjligheter att göra fel. Jag tror jag hittade alla
Lösning:

print([sum([(lambda line, numbers: (min([(i, d) for n,d in numbers if (i := line.find(n)) != -1])[1] * 10 + max([(line.rfind(n), d) for n,d in numbers])[1])) (line, [("1", 1),("2", 2),("3", 3),("4", 4),("5", 5), ("6", 6),("7", 7),("8", 8),("9", 9)] + n) for line in open("input01.txt").readlines()]) for n in [[],[("one", 1),("two", 2),("three", 3),("four", 4),("five", 5), ("six", 6),("seven", 7),("eight", 8),("nine", 9)]]])

Dold text