🌟 Advent of Code (AoC) 2020 🌟

PermalÀnk
Medlem
●
Skrivet av Ingetledigtnamn:

Dag 6, Python one-liner + Python, inte fullt sÄ komplex och med kommentarer.

Just ja, unions och intersections Àr bra. En Ànnu mindre lösning för dag 6 uppgift 2 i Scala, inspirerad av din lösning:

val groups = (read! pwd/"input.txt").split("\\n\\n").map(_.split("\\s+") groups.map(_.reduce(_ intersect _).size).sum

Irriterad pÄ att jag inte kommer pÄ hur man fÄr en referens till instansmetoder i Scala utan att ha en instans. I Kotlin eller Java 8 och framÄt skulle det varit exvis "String::intersect" (Edit: som Dave1080 visar snyggt exempel pÄ nedan.)

Lösningsförklaring: reduce tar en binÀr funktion som appliceras pÄ alla element i en collection parvis tills du har ett element kvar istÀllet för en collection. SÄ jag gjorde en lite kryptisk shorthand motsvarande typ

List("abc", "ab", "ac").reduce { (firstString, secondString) => firstString.intersect(secondString) } // Returnerar strÀngen "a" val intersectioncounts = intersectionStrings.map( (str) => str.size) val finalAnswer = intersectioncounts.sum // "sum" finns fördefinerad pÄ numeric collections som collection.reduce { (x,y) => x + y }

Dold text
Förklaring
PermalÀnk
Medlem ★
●
Skrivet av wgren:

Just ja, unions och intersections Àr bra. En Ànnu mindre lösning för dag 6 uppgift 2 i Scala, inspirerad av din lösning:

Tror nÀstan jag mÄste byta sprÄk. Att döma av lösningarna jag sett i dag Àr det ganska mÄnga som kör set-baserade lösningar och dÄ blir det ganska enkelt, men detta slÄr rekord.

PermalÀnk
Medlem ★
●

Roligaste uppgiften hittills. Rakt pÄ sak liksom. Sen blev jag riktigt nöjd med min lösning.

Dag: 6
SprÄk: Kotlin
Lösning: GitHub

Visa signatur

| Mobo: Gigabyte X570 GAMING X | CPU: AMD Ryzen 9 3900X + Dark Rock 4 | RAM: 32GB @ 3000MHz | GPU: Gigabyte RTX 3080 OC | PSU: Seasonic GX 850W | Chassi: NZXT S340 Elite Matte Black | M.2: Samsung 970 Evo 500GB & 1000GB | HDD: 4TB | Monitors: Acer Predator X34 GS & Acer XB270HU |

PermalÀnk
Medlem
●
Skrivet av Ingetledigtnamn:

Tror nÀstan jag mÄste byta sprÄk. Att döma av lösningarna jag sett i dag Àr det ganska mÄnga som kör set-baserade lösningar och dÄ blir det ganska enkelt, men detta slÄr rekord.

Kul att frÀlsa folk till mitt favoritsprÄk, men du har ju map, filter, reduce och dom andra pÄ collections i Python ocksÄ, sÄ tror nog att du kan fÄ till nÄgot liknande.

PermalÀnk
Medlem
●

Intressanta lösningar.

SjÀlv vet jag inte vad jag höll pÄ med nu nÀr man ser de hÀr praktexemplaren.

Det Àr inget ide att sprida dyngan som jag gjorde idag. Haha

Visa signatur

AMD Ryzen 3700X, Gigabyte Elite X570, 32GB Ballistix Sport, NH-D15S, SAPPHIRE NITRO+ RX 7900 XTX, Corsair AX760, LG OLED C2 42"

PermalÀnk
Medlem ★
●

Dag: 6
SprÄk: C#

Trodde aldrig jag skulle ha nytta av mÀngdlÀra igen. Fick mÄnga trÀffar pÄ google om HashSet<T> nÀr jag sökte efter intersect men kÀndes lite utanför min nivÄ sÄ körde pÄ nÄgot jag förstod

using System; using System.IO; using System.Collections.Generic; using System.Linq; namespace AoC6 { class Program { static void Main() { List<string> input = File.ReadAllText("C:\\Users\\willh\\AdventOfCode2020\\AoC6\\input.txt").Split(new string[] { "\r\n\r\n" }, StringSplitOptions.None).ToList(); int totalSum = 0; foreach (string group in input) { int groupSum = CountUnique(group); totalSum += groupSum; } int totalSumTwo = 0; foreach (string group in input) { int groupSum = CountEveryone(group); totalSumTwo += groupSum; } Console.WriteLine("Solution 1 = {0}", totalSum); Console.WriteLine("Solution 2 = {0}", totalSumTwo); Console.ReadKey(); } static int CountUnique(string input) { List<char> sanitizedInput = new List<char>(); foreach (char c in input) { if (!(c == '\r') && !(c == '\n')) { sanitizedInput.Add(c); } } List<char> uniqueInput = sanitizedInput.Distinct().ToList(); return uniqueInput.Count; } static int CountEveryone(string input) { List<string> sanitizedInput = input.Split(new string[] { "\r\n" }, StringSplitOptions.None).ToList(); IEnumerable<char> all = sanitizedInput[0].ToArray(); foreach (var candidate in sanitizedInput) { all = all.Intersect(candidate.ToArray()); } int count = 0; foreach (char c in all) { count += 1; } return count; } } }

Dold text

KÀnner hur hjÀrnan sakta blir fylld sÄhÀr efter 6 dagar. Jag har nu 12 stjÀrnor vilket Àr fler de 11 jag tog förra Äret. Allting fr.o.m. nu Àr sÄledes nytt rekord och det kÀnns ju ganska ok. Hoppas det inte kommer nÄgot monsterproblem och krossar mig imorgon.

Visa signatur

PrimÀr: R9 3900X | ASUS X570-F Gaming | NH-D15 | 64GB@3200MHz | RTX 3080 10GB | Seasonic 850W | Fractal Define R6 |
Gamla bettan: i5 750@3.8GHz | 8GB | HD5770 | Corsair VS 550W | FD R2 |

PermalÀnk
Medlem ★
●

Jag fortsĂ€tter min resa i ett sprĂ„k jag inte kan; F#. Än en gĂ„ng, Ă€r nĂ„gon en hejare pĂ„ sprĂ„ket i frĂ„ga tar jag gĂ€rna emot konstruktiv kritik!

open System open System.IO let task1 = Seq.filter (Char.IsLetter) >> Seq.distinct let task2 input = let passengerCount = input |> Seq.filter (fun x -> x = '\n') |> Seq.length |> (+) 1 input |> Seq.filter (Char.IsLetter) |> Seq.countBy id |> Seq.filter (fun (_,y) -> y = passengerCount) [<EntryPoint>] let main argv = let inputs = (File.ReadAllText "input.txt").Split (Environment.NewLine + Environment.NewLine) let summarize task = Seq.map (task >> Seq.length) >> Seq.sum printfn "Task 1: %i" (summarize task1 inputs) printfn "Task 2: %i" (summarize task2 inputs) 0

Visa signatur

Jag Àr en optimist; det Àr aldrig sÄ dÄligt sÄ att det inte kan bli sÀmre.

PermalÀnk
Medlem ★
●
Skrivet av Daz:

Dag: 6
SprÄk: C#

Trodde aldrig jag skulle ha nytta av mÀngdlÀra igen. Fick mÄnga trÀffar pÄ google om HashSet<T> nÀr jag sökte efter intersect men kÀndes lite utanför min nivÄ sÄ körde pÄ nÄgot jag förstod

using System; using System.IO; using System.Collections.Generic; using System.Linq; namespace AoC6 { class Program { static void Main() { List<string> input = File.ReadAllText("C:\\Users\\willh\\AdventOfCode2020\\AoC6\\input.txt").Split(new string[] { "\r\n\r\n" }, StringSplitOptions.None).ToList(); int totalSum = 0; foreach (string group in input) { int groupSum = CountUnique(group); totalSum += groupSum; } int totalSumTwo = 0; foreach (string group in input) { int groupSum = CountEveryone(group); totalSumTwo += groupSum; } Console.WriteLine("Solution 1 = {0}", totalSum); Console.WriteLine("Solution 2 = {0}", totalSumTwo); Console.ReadKey(); } static int CountUnique(string input) { List<char> sanitizedInput = new List<char>(); foreach (char c in input) { if (!(c == '\r') && !(c == '\n')) { sanitizedInput.Add(c); } } List<char> uniqueInput = sanitizedInput.Distinct().ToList(); return uniqueInput.Count; } static int CountEveryone(string input) { List<string> sanitizedInput = input.Split(new string[] { "\r\n" }, StringSplitOptions.None).ToList(); IEnumerable<char> all = sanitizedInput[0].ToArray(); foreach (var candidate in sanitizedInput) { all = all.Intersect(candidate.ToArray()); } int count = 0; foreach (char c in all) { count += 1; } return count; } } }

Dold text

KÀnner hur hjÀrnan sakta blir fylld sÄhÀr efter 6 dagar. Jag har nu 12 stjÀrnor vilket Àr fler de 11 jag tog förra Äret. Allting fr.o.m. nu Àr sÄledes nytt rekord och det kÀnns ju ganska ok. Hoppas det inte kommer nÄgot monsterproblem och krossar mig imorgon.

Jag baserade min VB-lösning pÄ HashSet, sÄ kolla gÀrna den om du vill ha ett exempel pÄ hur det kan anvÀndas. Förutom syntaxen funkar det pÄ exakt samma sÀtt i C#

För övrigt riktigt kul att se hur lösningarna pÄ samma problem i samma sprÄk kan bli sÄ olika varandra

PermalÀnk
Hedersmedlem ★
●

Dag: 6
SprÄk: C (med GCC-specifika grejer...)
KĂ€llkod: Godbolt Compiler Explorer

Den hÀr dagen valde jag att skriva min lösning i C först, eftersom hÀr fanns en intressant möjlighet att anvÀnda en CPU-instruktion i instruktionsuppsÀttningen (som enligt rykten Àr ett bestÀllningsjobb frÄn en signalspaningsmyndighet).

Mer detailer i spoiler-blocket, och Àr Àven vÀrt att lÀsa om du vill lÀra dig om binÀr aritmetik i C, samt Àven om en lite udda funktion i moderna CPU:er som kommer till sin rÀtt hÀr!

Den speciella instruktionen i frÄga Àr instruktionen POPCNT. (Sök efter 4-395 i denna PDF.) Detta Àr alltsÄ en hÄrdvaruinstruktion som rÀknar antalet bitar som Àr satta i en variabel i en enda instruktion. Rykten sÀger att det var NSA som bestÀllt att denna instruktion, och den Àr bl.a. anvÀndbar för kryptografi. Mer finns att lÀsa hÀr: https://vaibhavsagar.com/blog/2019/09/08/popcount/

Det finns lite olika sÀtt att se till att anropa denna funktion, och jag lekte och lÀrde mig en del om inline-ASM, men kom fram till att det bÀsta sÀttet var att anvÀnda GCC:s inbyggda funktion __builtin_popcount för detta. DÄ bör den nÀmligen bli portabel till andra processorer (bl.a. finns Àven en liknande instruktion pÄ ARM), Àven processorer som saknar POPCNT. För att faktiskt generera POPCNT-instruktionerna sÄ mÄste man kompilera med flaggan -mpopcnt i GCC, annars genereras bara en trÄkig loop för detta istÀllet.

Varför Àr denna instruktion sÀrskilt intressant för denna dags pussel? Jo, lÄt mig förklara!

Pusslet gÄr ut pÄ att man ska gÄ igenom ett antal gruppers ja/nej-svar. Man ska rÀkna ut hur mÄnga frÄgor som alla i en grupp svarat ja pÄ, och Àven hur mÄnga frÄgor minst en person i en grupp svarat ja pÄ.

Det finns 26 möjliga frÄgor, representerade som en bokstav frÄn a till z.

Det som dÄ ligger nÀra till hands Àr att spara den hÀr informationen, om vilka frÄgor man svarat ja eller nej pÄ genom bitar i ett 32-bitars heltal! Som i kodsnutten nedan:

c = getchar(); if (c >= 'a' && c <= 'z') { answer_mask_current |= 1 << (c - 'a');

(c - 'a') rÀknar alltsÄ ut en siffra frÄn 0 till 25 genom att ta ASCII-vÀrdet för bokstaven med svaret som passageraren svarat ja pÄ, och sedan dra bort ASCII-koden för A. T.ex. 'a'-'a' blir dÄ 0, och 'b'-'a' blir dÄ 1 etc.

1 << (c - 'a') tar vÀrdet 1 och "skiftar vÀnsterut med (c - 'a') steg. D.v.s. för 'e' sÄ blir 'e'-'a' till 4, och 1 << 4 blir 16 (eller 0b00010000, 1:an har hoppat 4 steg till vÀnster.)[/cmd]

answer_mask_current |= 1 << (c - 'a'); Gör en "bitwise or", vilket betyder att i det nya vÀrdet för answer_mask_current sÄ blev varje bit i detta vÀrde 1 om antingen biten redan var 1, ELLER om biten vi rÀknade fram nedan (som motsvarar svaret vi registerat) Àr 1. D.v.s. pÄ detta sÀtt kan vi slÄ pÄ den bit som motsvarar ja-svaret.

I slutet av raden sÄ har vi dÄ att answer_mask_current innehÄller ett bitfÀlt, dÀr varje 1-satt bit i vÀrdet representerar en frÄga som nÄgon svarat ja pÄ.

NÀr vi sedan nÄr slutet av raden kommer vi hit:

answer_mask_any |= answer_mask_current; answer_mask_all &= answer_mask_current; answer_mask_current = 0;

Första raden, samma sak, i answer_mask_any slĂ„r vi PÅ alla bitar dĂ€r den nuvarande passageraren svarat ja. Resultatet blir att i answer_mask_any sĂ„ blir en frĂ„gas bit 1 om minst en person i gruppen svarat ja pĂ„ frĂ„gan.

Andra raden blir lite klurigare. HÀr börjar vÀrdet som ~0 (eller alla bitar som 1:or), och istÀllet sÄ stÀnger denna rad AV bitar i answer_mask_all dÀr passageraren svarat nej! Resultatet blir att bitarna answer_mask_all bara Àr satta om ingen svarade nej pÄ frÄgorna (d.v.s. alla svarade ja).

Tredje raden nollstÀller answer_mask_current sÄ att vi kan kolla pÄ nÀsta rad.

Om vi kommer till slutet pÄ en rad (eller för all del till slut pÄ filen), och answer_mask_current Àr noll, dÄ vet vi att vi har fÄtt en tom rad (hade det funnits nÄgra svar sÄ hade minst 1 bit vart satt...). D.v.s. slut pÄ gruppen, och dags att rÀkna hur mÄnga frÄgor alla svarat ja pÄ, samt alla frÄgor minst en svarat ja pÄ.

Det Àr hÀr instruktionen POPCNT kommer in! Vi vill rÀkna hur mÄnga bitar i answer_mask_anyoch answer_mask_all som Àr satta till 1, och det Àr exakt vad popcount gör!

else if (c == '\n' || c == EOF) { if (answer_mask_current == 0) { part1 += __builtin_popcount(answer_mask_any); answer_mask_any = 0; part2 += __builtin_popcount(answer_mask_all); answer_mask_all = ~0; } else { /* ... */ } }

Efter att vi rÀknat bitarna nollstÀller vi answer_mask_anyoch answer_mask_all till dess utgÄngsvÀrde, sÄ att vi kan börja frÄn scratch i nÀsta grupp.

Dold text
PermalÀnk
●

Dag: 6
SprÄk: Haskell

import Data.List parseLines :: String -> String parseLines (x:[]) = [x] parseLines ('\n':'\n':xs) = "\n" ++ parseLines xs parseLines ('\n':xs) = " "++parseLines xs parseLines (x:xs) = [x] ++ parseLines xs main = do contents <- readFile "input.txt" let groups = lines $ parseLines contents putStr "1 or 2?\n" q <- getLine if q == "1" then return $ foldl (\acc val -> acc + val) 0 [length $ foldl (\acc word -> union acc word) "" (words x) | x <- groups] else return $ foldl (\acc val -> acc + val) 0 [length $ foldl (\acc word -> intersect acc word) (head (words x)) (tail (words x)) | x <- groups]

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

Dag: 6
SprÄk: C (med GCC-specifika grejer...)
KĂ€llkod: Godbolt Compiler Explorer

Den hÀr dagen valde jag att skriva min lösning i C först, eftersom hÀr fanns en intressant möjlighet att anvÀnda en CPU-instruktion i instruktionsuppsÀttningen (som enligt rykten Àr ett bestÀllningsjobb frÄn en signalspaningsmyndighet).

Mer detailer i spoiler-blocket, och Àr Àven vÀrt att lÀsa om du vill lÀra dig om binÀr aritmetik i C, samt Àven om en lite udda funktion i moderna CPU:er som kommer till sin rÀtt hÀr!

Den speciella instruktionen i frÄga Àr instruktionen POPCNT. (Sök efter 4-395 i denna PDF.) Detta Àr alltsÄ en hÄrdvaruinstruktion som rÀknar antalet bitar som Àr satta i en variabel i en enda instruktion. Rykten sÀger att det var NSA som bestÀllt att denna instruktion, och den Àr bl.a. anvÀndbar för kryptografi. Mer finns att lÀsa hÀr: https://vaibhavsagar.com/blog/2019/09/08/popcount/

Det finns lite olika sÀtt att se till att anropa denna funktion, och jag lekte och lÀrde mig en del om inline-ASM, men kom fram till att det bÀsta sÀttet var att anvÀnda GCC:s inbyggda funktion __builtin_popcount för detta. DÄ bör den nÀmligen bli portabel till andra processorer (bl.a. finns Àven en liknande instruktion pÄ ARM), Àven processorer som saknar POPCNT. För att faktiskt generera POPCNT-instruktionerna sÄ mÄste man kompilera med flaggan -mpopcnt i GCC, annars genereras bara en trÄkig loop för detta istÀllet.

Varför Àr denna instruktion sÀrskilt intressant för denna dags pussel? Jo, lÄt mig förklara!

Pusslet gÄr ut pÄ att man ska gÄ igenom ett antal gruppers ja/nej-svar. Man ska rÀkna ut hur mÄnga frÄgor som alla i en grupp svarat ja pÄ, och Àven hur mÄnga frÄgor minst en person i en grupp svarat ja pÄ.

Det finns 26 möjliga frÄgor, representerade som en bokstav frÄn a till z.

Det som dÄ ligger nÀra till hands Àr att spara den hÀr informationen, om vilka frÄgor man svarat ja eller nej pÄ genom bitar i ett 32-bitars heltal! Som i kodsnutten nedan:

c = getchar(); if (c >= 'a' && c <= 'z') { answer_mask_current |= 1 << (c - 'a');

(c - 'a') rÀknar alltsÄ ut en siffra frÄn 0 till 25 genom att ta ASCII-vÀrdet för bokstaven med svaret som passageraren svarat ja pÄ, och sedan dra bort ASCII-koden för A. T.ex. 'a'-'a' blir dÄ 0, och 'b'-'a' blir dÄ 1 etc.

1 << (c - 'a') tar vÀrdet 1 och "skiftar vÀnsterut med (c - 'a') steg. D.v.s. för 'e' sÄ blir 'e'-'a' till 4, och 1 << 4 blir 16 (eller 0b00010000, 1:an har hoppat 4 steg till vÀnster.)[/cmd]

answer_mask_current |= 1 << (c - 'a'); Gör en "bitwise or", vilket betyder att i det nya vÀrdet för answer_mask_current sÄ blev varje bit i detta vÀrde 1 om antingen biten redan var 1, ELLER om biten vi rÀknade fram nedan (som motsvarar svaret vi registerat) Àr 1. D.v.s. pÄ detta sÀtt kan vi slÄ pÄ den bit som motsvarar ja-svaret.

I slutet av raden sÄ har vi dÄ att answer_mask_current innehÄller ett bitfÀlt, dÀr varje 1-satt bit i vÀrdet representerar en frÄga som nÄgon svarat ja pÄ.

NÀr vi sedan nÄr slutet av raden kommer vi hit:

answer_mask_any |= answer_mask_current; answer_mask_all &= answer_mask_current; answer_mask_current = 0;

Första raden, samma sak, i answer_mask_any slĂ„r vi PÅ alla bitar dĂ€r den nuvarande passageraren svarat ja. Resultatet blir att i answer_mask_any sĂ„ blir en frĂ„gas bit 1 om minst en person i gruppen svarat ja pĂ„ frĂ„gan.

Andra raden blir lite klurigare. HÀr börjar vÀrdet som ~0 (eller alla bitar som 1:or), och istÀllet sÄ stÀnger denna rad AV bitar i answer_mask_all dÀr passageraren svarat nej! Resultatet blir att bitarna answer_mask_all bara Àr satta om ingen svarade nej pÄ frÄgorna (d.v.s. alla svarade ja).

Tredje raden nollstÀller answer_mask_current sÄ att vi kan kolla pÄ nÀsta rad.

Om vi kommer till slutet pÄ en rad (eller för all del till slut pÄ filen), och answer_mask_current Àr noll, dÄ vet vi att vi har fÄtt en tom rad (hade det funnits nÄgra svar sÄ hade minst 1 bit vart satt...). D.v.s. slut pÄ gruppen, och dags att rÀkna hur mÄnga frÄgor alla svarat ja pÄ, samt alla frÄgor minst en svarat ja pÄ.

Det Àr hÀr instruktionen POPCNT kommer in! Vi vill rÀkna hur mÄnga bitar i answer_mask_anyoch answer_mask_all som Àr satta till 1, och det Àr exakt vad popcount gör!

else if (c == '\n' || c == EOF) { if (answer_mask_current == 0) { part1 += __builtin_popcount(answer_mask_any); answer_mask_any = 0; part2 += __builtin_popcount(answer_mask_all); answer_mask_all = ~0; } else { /* ... */ } }

Efter att vi rÀknat bitarna nollstÀller vi answer_mask_anyoch answer_mask_all till dess utgÄngsvÀrde, sÄ att vi kan börja frÄn scratch i nÀsta grupp.

Dold text

Cool lösning, den lÀr med rÄge vara den snabbaste lösningen, d.v.s. tar kortast tid att köra, av alla som postas

Även ARM64 har en en speciell instruktion just för att rĂ€kna antalet bitar som Ă€r satt i ett register, cnt.

Man ser att den instruktionen anvÀnds om man bygger din lösning för ARM64, Godbolt igen med min indata.

kjonsson@bean:~/AoC/advent-of-code-2020/day6$ cat input.txt | sudo perf stat ./c_day6 part1: 6799 part2: 3354 Performance counter stats for './c_day6': 0,303161 task-clock (msec) # 0,594 CPUs utilized 0 context-switches # 0,000 K/sec 0 cpu-migrations # 0,000 K/sec 52 page-faults # 0,172 M/sec 1 229 027 cycles # 4,054 GHz 1 083 644 instructions # 0,88 insn per cycle 264 756 branches # 873,318 M/sec 8 789 branch-misses # 3,32% of all branches 0,000510089 seconds time elapsed kjonsson@bean:~/AoC/advent-of-code-2020/day6$ sudo perf stat ./.build/release/day6 🌟 Part 1 : 6799 🌟 Part 2 : 3354 Performance counter stats for './.build/release/day6': 18,126387 task-clock (msec) # 0,989 CPUs utilized 0 context-switches # 0,000 K/sec 0 cpu-migrations # 0,000 K/sec 725 page-faults # 0,040 M/sec 74 135 912 cycles # 4,090 GHz 150 084 143 instructions # 2,02 insn per cycle 30 432 321 branches # 1678,896 M/sec 193 483 branch-misses # 0,64% of all branches 0,018335341 seconds time elapsed

JÀmförelse i antal cykler att köra din lösning mot min i Swift (som Àven den tar relativt fÄ cykler mot scriptsprÄken)
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: 6
SprÄk: Go

func main() { answers := myIo() answersPart2 := myIoPart2() total := 0 for _, v := range answers { result := answeredYes(v) total += result } totalPart2 := 0 for _, v := range answersPart2 { result := answeredYesPart2(v) totalPart2 += result fmt.Println("String", v, "Result:", result) } println("Total score Part 1:", total, "Total score Part 2:", totalPart2) } func answeredYes(parsed string) int { a := "abcdefghijklmnopqrstuvwxyz" score := 0 for _, v := range a { if strings.Contains(parsed, string(v)) { score++ } } return score } func answeredYesPart2(parsed string) int { a := "abcdefghijklmnopqrstuvwxyz" split := strings.Split(parsed, ";") score := 0 for _, v := range a { temp := true for _, vv := range split { if len(vv) < 1 { continue } if !strings.Contains(vv, string(v)) { temp = false } } if temp { score++ } } return score } InlÀsning: for scanner.Scan() { temp += scanner.Text() temp += ";" if len(scanner.Text()) <= 0 { array = append(array, temp) temp = "" } }

Dold text
Visa signatur

AW3423DW QD-OLED - Ryzen 5800x - MSI Gaming Trio X 3090 - 64GB 3600@cl16 - Samsung 980 Pro 2TB/WD Black SN850 2TB

PermalÀnk
Hedersmedlem ★
●

Dag: 6
SprÄk: Powershell
Lösning: Github

Den hÀr lösningen kÀndes mest pliktskyldig för att jag tÀnkt mig att jag vill ha Powershell-lösningar för samtliga dagar, fast det mÀrks att den hÀr sortens problem Àr inte riktigt dÀr Powershell Àr det lÀmpligaste valet. MÀrkt att Powershell Àr ganska "clunky" nÀr det handlar om att manipulera enstaka tecken...

PermalÀnk
Hedersmedlem ★
●
Skrivet av Yoshman:

Cool lösning, den lÀr med rÄge vara den snabbaste lösningen, d.v.s. tar kortast tid att köra, av alla som postas

Även ARM64 har en en speciell instruktion just för att rĂ€kna antalet bitar som Ă€r satt i ett register, cnt.

Man ser att den instruktionen anvÀnds om man bygger din lösning för ARM64, Godbolt igen med min indata.

Jo, jag misstÀnkte att det skulle bli portabelt nÀr man körde med GCC:s builtins, sÄ det var ju bra att fÄ det berÀftat.

Skrivet av Yoshman:

kjonsson@bean:~/AoC/advent-of-code-2020/day6$ cat input.txt | sudo perf stat ./c_day6 part1: 6799 part2: 3354 Performance counter stats for './c_day6': 0,303161 task-clock (msec) # 0,594 CPUs utilized 0 context-switches # 0,000 K/sec 0 cpu-migrations # 0,000 K/sec 52 page-faults # 0,172 M/sec 1 229 027 cycles # 4,054 GHz 1 083 644 instructions # 0,88 insn per cycle 264 756 branches # 873,318 M/sec 8 789 branch-misses # 3,32% of all branches 0,000510089 seconds time elapsed kjonsson@bean:~/AoC/advent-of-code-2020/day6$ sudo perf stat ./.build/release/day6 🌟 Part 1 : 6799 🌟 Part 2 : 3354 Performance counter stats for './.build/release/day6': 18,126387 task-clock (msec) # 0,989 CPUs utilized 0 context-switches # 0,000 K/sec 0 cpu-migrations # 0,000 K/sec 725 page-faults # 0,040 M/sec 74 135 912 cycles # 4,090 GHz 150 084 143 instructions # 2,02 insn per cycle 30 432 321 branches # 1678,896 M/sec 193 483 branch-misses # 0,64% of all branches 0,018335341 seconds time elapsed

JÀmförelse i antal cykler att köra din lösning mot min i Swift (som Àven den tar relativt fÄ cykler mot scriptsprÄken)

Absolut blir ju detta snabbare Àn att gegga med datastrukturer! (Fast du hade egentligen inte behövt göra det ocksÄ, man kan ju lagra saker i arrayer/dictionarys ocksÄ, som min Powershell-lösning ovan.) Jag börjar faktiskt misstÀnka lite att de som gjort Advent of Code ibland tÀnkt ut nÄgon cool grej med bitmanipulation man kan göra, för det fanns ju en sÄdan lösning Àven pÄ Dag 5 (i min C-lösning sÄ lagrade jag ocksÄ lediga/upptagna stolar i ett bitfÀlt, och det gick rÀtt fort att hitta lediga stolar dÄ genom att leta efter rader (chars) som inte var 0xff...)

PermalÀnk
Datavetare ★
●
Skrivet av pv2b:

Jo, jag misstÀnkte att det skulle bli portabelt nÀr man körde med GCC:s builtins, sÄ det var ju bra att fÄ det berÀftat.

Absolut blir ju detta snabbare Àn att gegga med datastrukturer! (Fast du hade egentligen inte behövt göra det ocksÄ, man kan ju lagra saker i arrayer/dictionarys ocksÄ, som min Powershell-lösning ovan.) Jag börjar faktiskt misstÀnka lite att de som gjort Advent of Code ibland tÀnkt ut nÄgon cool grej med bitmanipulation man kan göra, för det fanns ju en sÄdan lösning Àven pÄ Dag 5 (i min C-lösning sÄ lagrade jag ocksÄ lediga/upptagna stolar i ett bitfÀlt, och det gick rÀtt fort att hitta lediga stolar dÄ genom att leta efter rader (chars) som inte var 0xff...)

GÄr absolut att skriva liknade i Swift. PoÀngen för mig Àr dock primÀrt att lÀra mig sprÄket, sÄ vill ha lösningar dÀr jag mÄste anvÀnda delar av standardbiblioteket. Noterade dock precis att Swift pÄ Linux inte Àr speciellt effektivt, kanske inte sÄ förvÄnande... Har gjort alla dagar pÄ en Ubuntu dator, mesta av gammal vana och har först nu orkat fÄ till Emacs pÄ Mac-datorn.

Tyckte ÀndÄ det tog lite vÀl mÄnga cykler i Swift-lösningen, tar lite mindre Àn 1/3 om man kör samma sak pÄ MacOS (i.o.f.s. pÄ en M1, men ska inte vara sÄ stor skillnad).

Lite tips om nÄgon kör C++. NÀmnde tidigare att det Àr lite segt att C++ lösningen för dag 5 spenderade en ansenligt del av raderna för att lÀra in filen, i kontext av prestandasnack: det absolut snabbaste sÀttet man kan lÀsa in en fil lÀr vara att minnesmappa den. GÄr att fÄ in innehÄllet i en fil i en std::vector<char> pÄ tvÄ rader (tre om man rÀknar #include)

#include <boost/iostreams/device/mapped_file.hpp> #include <cstdint> #include <cstdio> #include <vector> int main(int argc, char *argv[]) { uint32_t part1 = 0; uint32_t part2 = 0; uint32_t answer_mask_any = 0; uint32_t answer_mask_all = ~0; uint32_t answer_mask_current = 0; boost::iostreams::mapped_file input_mmap("input.txt", boost::iostreams::mapped_file::readonly); std::vector<char> input(input_mmap.const_data(), input_mmap.const_data() + input_mmap.size()); for (auto c: input) { if (c != '\n') { answer_mask_current |= 1 << (c - 'a'); } else { if (answer_mask_current == 0) { part1 += __builtin_popcount(answer_mask_any); answer_mask_any = 0; part2 += __builtin_popcount(answer_mask_all); answer_mask_all = ~0; } else { answer_mask_any |= answer_mask_current; answer_mask_all &= answer_mask_current; answer_mask_current = 0; } } } std::printf("part1: %d\n", part1); std::printf("part2: %d\n", part2); }

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 ★
●

Day 6 - Rust

pt1

input .split("\n\n") .map(|groups| { ('a'..='z') .filter(|&c| { groups .chars() .filter(|s| s.is_alphabetic()) .position(|d| d == c) .is_some() }) .count() }) .sum()

Dold text

pt2

input .split("\n\n") .map(|groups| { ('a'..='z') .filter(|&c| { groups .split_whitespace() .all(|group| group.chars().position(|d| c == d).is_some()) }) .count() }) .sum()

Dold text
Skrivet av Mordekai:

Dagens lösning exklusive FileIO tog nog 1ms oavsett sprÄk, lösning, processor men det vore kul att se exekveringstid exklusive FileIO pÄ lösningarna.

Day5 - Part1/(default) time: [53.012 us 53.354 us 53.687 us]
Day5 - Part2/(default) time: [78.111 us 80.985 us 84.051 us]

pt1

input .lines() .map(|rows| { rows.chars() .fold(0, |acc, c| acc * 2 + matches!(c, 'B' | 'R') as u32) }) .max() .unwrap()

Dold text

pt2

let mut seat_ids = input .lines() .map(|rows| { rows.chars() .fold(0, |acc, c| acc * 2 + matches!(c, 'B' | 'R') as u32) }) .collect::<Vec<u32>>(); seat_ids.sort(); seat_ids .array_windows::<2>() .find(|[a, b]| b - a != 1) .map(|[x, _]| x + 1) .unwrap()

Dold text
PermalÀnk
Medlem ★
●

Jag ligger efter
Dag: 5
SprÄk: Go

package main import ( "bufio" "fmt" "log" "os" "sort" "strconv" "strings" ) func check(e error) { if e != nil { panic(e) } } func main() { boardingPasses, err := readLines("day5.txt") if err != nil { log.Fatalf("readlines: %s", err) } binaryRows, binaryColumns := convertToBinary(boardingPasses) seatIDs := seatID(binaryRows, binaryColumns) maximum := max(seatIDs) sort.Ints(seatIDs) mySeat := missingValue(seatIDs) fmt.Printf("The largest seatID is: %d\n", maximum) fmt.Printf("My seat is : %d\n", mySeat) fmt.Println(seatIDs) } func readLines(path string) ([]string, error) { var bla []string file, err := os.Open(path) if err != nil { return bla, err } defer file.Close() scanner := bufio.NewScanner(file) var completeList []string for scanner.Scan() { lineStr := scanner.Text() if len(lineStr) != 0 { // The last line is \n completeList = append(completeList, lineStr) } } return completeList, scanner.Err() } func convertToBinary(boardingPasses []string) ([]string, []string) { var binaryrows []string var binarycolumns []string var temp string for i := 0; i < len(boardingPasses); i++ { temp = strings.ReplaceAll(boardingPasses[i][0:7], "F", "0") temp = strings.ReplaceAll(temp, "B", "1") binaryrows = append(binaryrows, temp) temp = strings.ReplaceAll(boardingPasses[i][7:10], "L", "0") temp = strings.ReplaceAll(temp, "R", "1") binarycolumns = append(binarycolumns, temp) } return binaryrows, binarycolumns } func seatID(rows []string, columns []string) []int { var row int64 var column int64 var seatIDs []int var seat int for i := 0; i < len(rows); i++ { row, _ = strconv.ParseInt(rows[i], 2, 32) column, _ = strconv.ParseInt(columns[i], 2, 32) // parseInt gives int64. seat = int(row)*8 + int(column) seatIDs = append(seatIDs, seat) } return seatIDs } func max(a []int) int { maximum := a[0] for _, value := range a { if value > maximum { maximum = value } } return maximum } // This assumes a sorted list. func missingValue(a []int) int { for i := 0; i < len(a)-1; i++ { if a[i]+1 != a[i+1] { return a[i] + 1 } } return 0 }

Dold text
PermalÀnk
Medlem ★
●

Ugh, nu börjar det kÀnnas som att awk har gjort sitt för i Är.

part1$ <in sed -E 's/([a-z]*) ([a-z]*) .*ain/\1\2,/;s/ ([0-9]*) ([a-z]*) ([a-z]*) bags?/\2\3,/g;s/\.$//' | awk -F, '{ for (i = 2; i <= NF; i++) { b[$1","$i] } } END { c["shinygold"] while (length(c) > l) { l = length(c) for (n in b) { split(n, r); if (r[2] in c) { c[r[1]] } } } print l - 1 }' part2$ <in sed -E 's/([a-z]*) ([a-z]*) .*ain/\1\2,/;s/([0-9]*) ([a-z]*) ([a-z]*) bags?/\2\3 \1/g' | awk -F, '{ for (i = 2; i <= NF; i++) { split($i, v, " "); b[$1","v[1]] = v[2] } } END { c["shinygold"] = 1 while (length(c)) { for (e in b) { split(e, v); if (v[1] in c) { a[v[2]] += c[v[1]] * b[e] } } delete c for (x in a) { c[x] = a[x]; r += a[x] } delete a } print r }'

Dold text
Visa signatur

"Some poor, phoneless fool is probably sitting next to a waterfall somewhere, totally unaware of how angry and scared he's supposed to be." - Duncan Trussell

PermalÀnk
Medlem ★
●

Dag 7, Python

Gissningsvis börjar problemen bli sÄ komplexa nu sÄ det blir svÄrt med oneliners i fortsÀttningen, men det blev ÀndÄ ganska enkla funktioner.

Lösningen bygger pÄ ett dict av dicts: fÀrg -> (fÀrg -> antal). Lambdat byter plats pÄ elementen i tupeln för att kunna bygga ett dict av resultatet frÄn findall, men annars Àr det vÀl inga konstigheter. Vid utskriften subtraheras 1 för annars skulle Àven 'shiny gold'-vÀskan rÀknas och inte bara de vÀskor den innehÄller.

contains = {} for l in [l.strip() for l in open('input', 'r')]: m = l.split(' bags contain ') contains[m[0]] = dict(map(lambda v: (v[1],v[0]), re.findall(r' ?(\d+) (.+?) bags?\.?,?', m[1]))) def can_hold(color1, wanted): return (wanted in contains[color1] or any([can_hold(color2, wanted) for color2 in contains[color1]])) def bags(color1): return 1 + sum([int(contains[color1][color2]) * bags(color2) for color2 in contains[color1]]) print(sum([can_hold(color, 'shiny gold') for color in contains]), bags('shiny gold') - 1)

Dold text
Meningsbyggnad
PermalÀnk
Medlem
●
Skrivet av gibbon_:

Ugh, nu börjar det kÀnnas som att awk har gjort sitt för i Är.

ÄndĂ„ fascinerad hur mycket du lyckats lösa pĂ„ det spĂ„ret, och imponerad av hur snyggt det ofta blev. Snyggt jobbat!

PermalÀnk
Medlem
●

Inte nöjd med dagens insats eller lösning. Först stötte jag pÄ en bugg, nÀr jag körde ScalaTest med "sbt test" sÄ kastade allt anvÀndande av regex matchers en Java nullpointer exception oavsÀtt input. Men körde jag det som ett standalone program eller via Ammonite REPL funkade identisk kod klockrent. Förmodligen nÄgon versionskonflikt av senaste versionerna av OpenJDK Java + Scala + sbt + ScalaTest som orsakar. Orkar jag grÀva i det och submitta en buggrapport eller en eventuell open source fix...?

Sen slösade jag jÀttemycket tid pÄ

att försöka bygga upp en weighted graph med fold till en custom Tree klass, ville triumfera med snygg oneliner igen. Men blev soppa av allt, sÀrskilt som jag inte kunde skriva unit tester. Och tiden drog ivÀg sÄ slutade med att jag gjorde rekursiv lookup pÄ map. KÀnns hackigt, men tröstar mig med att Ingetledigtnamn Àr inne pÄ liknande spÄr. Och att nÀr jag tÀnker efter sÄ Àr det ju en utmÀrkt weighted graph struktur som jag gjorde med min Map, sÄ behöver inte skriva nÄgon egen klass. Jag behövde bara komma pÄ hur man traverserade den rÀtt.

val BAG_MATCHER = " ?(\\d+) (.*) bag.*".r case class Bag(weight: Int, color: String) def contentToList(s: String): List[Bag] = { s.split(",").toList.flatMap { case BAG_MATCHER(number, color) => List(Bag(number.toInt, color)) case default => List() // "no other bags" och ev andra strÀngar = tom vÀska } } def lineToTuple(s: String): Tuple2[String, List[Bag]] = { val color::content = s.split("bags contain ").map(_.trim).toList (color, contentToList(content.last)) } val bags = (read.lines! pwd/"input.txt").map(lineToTuple).toMap def totalWeight(color: String): Int = { bags(color) match { case List() => 1 case list => (list.map { bag => bag.weight * totalWeight(bag.color) }.sum) + 1 } } totalWeight("shiny gold") - 1

Dold text
Indentering
PermalÀnk
●

Dag: 7
SprÄk: Nim
Lösning: Github

KÀnns som mina lösningar blir hackigare och lÀngre för var dag som gÄr (:

PermalÀnk
Medlem
●

Dag: 7
SprÄk: Golang
Lösning:

Nu börjar det bli för svÄrt för mig.

package main import ( "bufio" "fmt" "os" "strconv" "strings" ) type Bag struct { Childs map[string]map[string]int Parents map[string][]string } func getBags(rows []string) Bag { childs := map[string]map[string]int{} parents := map[string][]string{} separatorVal := " bags contain " for _, row := range rows { parentEnd := strings.Index(row, separatorVal) parentName := row[:parentEnd] row := row[len(separatorVal)+parentEnd:] fields := strings.Split(row, "bag") for _, field := range fields { field = strings.Replace(field, "s.", "", 1) field = strings.Replace(field, "s, ", "", 1) field = strings.Replace(field, ", ", "", 1) field = strings.Replace(field, ".", "", 1) if len(field) == 0 || strings.Contains(field, "no other") { continue } numberEnd := strings.Index(field, " ") count, _ := strconv.Atoi(field[:numberEnd]) childName := strings.TrimSpace(field[numberEnd+1:]) if _, ok := childs[parentName]; !ok { childs[parentName] = map[string]int{} } childs[parentName][childName] = count parents[childName] = append(parents[childName], parentName) } } return Bag{ Childs: childs, Parents: parents, } } func getParents(bag Bag, childName string, matches map[string]bool) int { result := 0 for _, parentName := range bag.Parents[childName] { if _, found := matches[parentName]; !found { matches[parentName] = false result += 1 + getParents(bag, parentName, matches) } } return result } func getChildCount(bag Bag, parentName string) int { result := 0 if _, ok := bag.Childs[parentName]; ok { for childName, count := range bag.Childs[parentName] { result += count + count*getChildCount(bag, childName) } } return result } func getRows(filename string) []string { file, _ := os.Open(filename) defer file.Close() scanner := bufio.NewScanner(file) var rows []string for scanner.Scan() { rows = append(rows, scanner.Text()) } return rows } func main() { rows := getRows("../input.txt") fmt.Println("PartOne", getParents(getBags(rows), "shiny gold", map[string]bool{})) fmt.Println("PartTwo", getChildCount(getBags(rows), "shiny gold")) }

Dold text
Optimerat lite
PermalÀnk
Medlem ★
●
Skrivet av wgren:

KÀnns hackigt, men tröstar mig med att Ingetledigtnamn Àr inne pÄ liknande spÄr, och att nÀr jag tÀnker efter sÄ Àr det ju en weighted graph struktur som jag gjorde med min Map. Jag behövde bara komma pÄ hur man traverserade den rÀtt.
[code]

Dold text

För dessa uppgifter prioriterar jag kodstorlek/elegans före effektivitet. Om jag gjorde detta pÄ riktigt skulle jag ha nÄgon form av cache för att slippa traversera samma deltrÀd flera gÄnger.

En lockande tanke vore att rÀkna ut saker medan man lÀser in, men alla fÀrger som behövs Àr kanske inte inlÀsta Àn och samtidigt gör vi jobb som vi kanske inte kommer ha nytta av.

Dold text
PermalÀnk
Medlem ★
●

Dag: 7
SprÄk: c#

Orkade verkligen inte bry mig idag...

Regex regex1 = new Regex(@"(\w.+?)(\s)?bag(s?)(\s)?(contain)?"), regex2 = new Regex(@"(\d+)\s?(.+)");

void Main()
{
var input = File.ReadAllText(Path.Combine(Util.CurrentQuery.Location, "day-07.txt")).Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries).Select(x => regex1.Matches(x)).Select(x => x.OfType<Match>().Select(y => y.Groups[1].Value).ToArray()).ToArray();
var part1 = Part1("shiny gold", input).ToArray().Distinct().Count();
var part2 = Part2("shiny gold", input).ToArray().Count() - 1;
new { part1, part2 }.Dump();
}

IEnumerable<string> Part1(string a, string[][] input) {
foreach (var b in input.Where(x => x.Skip(1).Any(y => y.EndsWith(a))).Select(x => x.First())) {
yield return b;
foreach (var c in Part1(b, input)) {
yield return c; } } }

IEnumerable<string[]> Part2(string a, string[][] input) {
foreach (var b in input.Where(x => x.First() == a)) {
yield return b;
foreach (var c in b.Skip(1)) {
var m = regex2.Match(c);
if (m.Success) {
for (int i = 0; i < int.Parse(m.Groups[1].Value); i++) {
foreach (var d in Part2(m.Groups[2].Value, input)) {
yield return d; } } } } } }

Edit; Tog bort lite whitespace :)
PermalÀnk
Medlem ★
●
Skrivet av wgren:

ÄndĂ„ fascinerad hur mycket du lyckats lösa pĂ„ det spĂ„ret, och imponerad av hur snyggt det ofta blev. Snyggt jobbat!

Man tackar! Du har verkligen gjort ett bra case för Scala med dina lösningar med.

Haha det verkar som att inte nÄgon Àr sÀrskilt nöjd idag. SjÀlv har jag inte hÀngt pÄ sÄhÀr lÀnge sen 2016, och dÄ slutade jag pÄ dag 8. Ska bli intressant att se vad som kommer imorgon.

Visa signatur

"Some poor, phoneless fool is probably sitting next to a waterfall somewhere, totally unaware of how angry and scared he's supposed to be." - Duncan Trussell

PermalÀnk
Medlem ★
●
Skrivet av gibbon_:

Man tackar! Du har verkligen gjort ett bra case för Scala med dina lösningar med.

Haha det verkar som att inte nÄgon Àr sÀrskilt nöjd idag. SjÀlv har jag inte hÀngt pÄ sÄhÀr lÀnge sen 2016, och dÄ slutade jag pÄ dag 8. Ska bli intressant att se vad som kommer imorgon.

Jag Àr ocksÄ impad av att du orkat sÄ lÀnge. Fyndigt att göra summeringen med wc -l

PermalÀnk
Medlem ★
●
Skrivet av Sajox:

Intressanta lösningar.

SjÀlv vet jag inte vad jag höll pÄ med nu nÀr man ser de hÀr praktexemplaren.

Det Àr inget ide att sprida dyngan som jag gjorde idag. Haha

Det intressanta Àr vad du gör nu. GÄr du hem och deppar över att du Àr kass pÄ programmering eller ser du det som ett tillfÀlle att lÀra dig nÄgot nytt och bli bÀttre? Programmering handlar vÀl till viss del om fallenhet, men mycket Àr ren rutin. Ju fler problem du löser desto fler verktyg fÄr du i din mentala verktygslÄda. NÀsta gÄng du ser ett problem som liknar nÄgot du löst kan du tÀnka att det ser ut ungefÀr som det dÀr problemet och det löste du genom att... Det kanske kan vara ett bra angreppssÀtt hÀr ocksÄ.

Nu nÀr du sett att det finns snyggare lösningar Àn din "dynga" Àr det lÀge att försöka igen. Inte kopiera. Du skall sjÀlv skriva en lösning som anvÀnder en liknande metod. Det kanske fanns en funktion i standardbibilioteket som gjorde en del av det du gjorde, kanske ett regexp fixar parsningen av indata. Det kanske fanns en annan algoritm som gjorde det hela lite enklare. SjÀlv löste jag söndagens uppgift tre gÄnger nÀr jag sÄg klurigheter i andras lösningar.

PermalÀnk
Medlem ★
●
Skrivet av gibbon_:

Haha det verkar som att inte nÄgon Àr sÀrskilt nöjd idag. SjÀlv har jag inte hÀngt pÄ sÄhÀr lÀnge sen 2016, och dÄ slutade jag pÄ dag 8. Ska bli intressant att se vad som kommer imorgon.

Intresset för AoC har verkligen svalnat idag

FÄr folk prestationsÄngest eller nÄtt? Jag lÀgger sÄ lite tid som möjligt pÄ mina lösningar...

PermalÀnk
●

Dag: 7
SprÄk: Haskell

Löste med grafer o dfs, blev lite klurigare Àn vÀntat i Haskell.

import Data.List import Data.Maybe (fromJust) import Data.List.Split import Data.Char import Data.Function data Node = Node { label :: String , adjacent :: [(Int, Node)] } deriving (Show,Eq) data Graph = Graph [Node] deriving (Show) mkGraph :: [(String, [String])] -> Graph mkGraph links = Graph $ map snd nodeLookupList where mkNode (lbl, adjacent) = (lbl, Node lbl $ map (\(x:y) -> (digitToInt x, lookupNode y)) adjacent) nodeLookupList = map mkNode links lookupNode lbl = fromJust $ lookup lbl nodeLookupList findNode :: Graph -> String -> Maybe Node findNode (Graph []) _ = Nothing findNode (Graph (Node n s:ns)) l | n == l = Just (Node n s) | otherwise = findNode (Graph ns) l bagCount :: [(Int, Node)] -> Int bagCount [] = 1 bagCount ((i,n):xs) = i * (bagCount $ adjacent n) + (bagCount xs) fitsIn :: [(Int, Node)] -> [String] fitsIn [] = [] fitsIn ((i,x):xs) = nub ([label x] ++ (fitsIn $ adjacent x) ++ (fitsIn xs)) main = do contents <- readFile "input.txt" let bags = lines $ contents let l = [init $ splitOn "," $ concat [if isInfixOf "bag" z then "," else z | z <- words bag, z /= "contain"] | bag <- bags] let cMap = [(head q, if isDigit (head $ head $ tail q) then map (\x -> x) (tail q) else [])| q <- l] let pMap = map (\x -> (fst $ head x, foldl (\acc y -> acc ++ snd y) [] x)) $ groupBy ((==) `on` fst) $ sort $ concatMap (\(x,y) -> (x,[]) : map (\z -> (tail z,["0"++x])) y) cMap let g1 = mkGraph pMap let g2 = mkGraph cMap return (length $ fitsIn $ adjacent $ fromJust $ findNode g1 "shinygold", bagCount (adjacent $ fromJust $ findNode g2 "shinygold") - 1)

Dold text