🌟 Advent of Code (AoC) 2021 🌟

PermalÀnk
Hedersmedlem ★
●
Skrivet av SAFA:

Samma kod Àr det ju inte riktigt, men har skapat alla 5040 permutationer, men sen rÀcker det ju med att testa tills man hittar första siffran som inte Àr en korrekt 7-segment siffa.
Skapa permutationslistan Àr extra brute-force dÄ jag inte kom pÄ nÄtt bÀttre dÄ.

Galet 13 ms pÄ min dator (18 första gÄngen).
Jag blir sugen pÄ att skriva om min brute force-lösning sÄ nÀra som jag kan men i Rust och se hur det presterar dÀr. Vore ju helt galet om brute force i Rust hamnar nÀra en "smart" lösning i TypeScript, nÀr tidsskillnaden mellan de tvÄ i TS Àr över 900 gÄnger!

JavaScript verkar inte alls optimerat för att köra funktionella grejer som map/filter/reduce och liknande, eftersom det Àr mÄnga lÀgen dÀr hela arrayerna skapas, kopieras runt osv. Kör ju TypeScript enbart för att lÀra mig det, har aldrig hÄllt pÄ med JS/TS förut och har rent av ogillat dem.
Gillar dem lite mer nu, men i jÀmförelse med andra sprÄk sÄ nja... Skulle nog hellre köra Rust eller Python i lÀngden.

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

Ligger lite efter, hÀr kommer min dag 6 i Typescript

import { GetFileRows } from "./fileReader"; type FishCounter = { [key: number]: number }; const emptyFishCounter: FishCounter = { 0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, }; const countFishAfterNumberOfDays = (currentFish: FishCounter, days: number): number => { if (days === 0) { return Object.values(currentFish).reduce((prev, curr) => (prev += curr), 0); } let newDayFishCounter: FishCounter = { ...emptyFishCounter }; newDayFishCounter[0] = currentFish[1]; newDayFishCounter[1] = currentFish[2]; newDayFishCounter[2] = currentFish[3]; newDayFishCounter[3] = currentFish[4]; newDayFishCounter[4] = currentFish[5]; newDayFishCounter[5] = currentFish[6]; newDayFishCounter[6] = currentFish[0] + currentFish[7]; newDayFishCounter[7] = currentFish[8]; newDayFishCounter[8] = currentFish[0]; return countFishAfterNumberOfDays(newDayFishCounter, --days); }; const solve = (rows: string[]) => { const inputNumbers: number[] = rows[0].split(",").map((n) => parseInt(n)); let yesterdayFishCounter: FishCounter = inputNumbers.reduce<FishCounter>( (allFish, numberInArr) => { allFish[numberInArr] = ++allFish[numberInArr]; return allFish; }, { ...emptyFishCounter } ); console.log(countFishAfterNumberOfDays(yesterdayFishCounter, 80)); console.log(countFishAfterNumberOfDays(yesterdayFishCounter, 256)); }; const solveDay6 = async () => { const rows = await GetFileRows("./src/inputs/input-day6.txt"); solve(rows); };

Dold text
PermalÀnk
Medlem ★
●

Dag: 13
SprÄk: F#

Som alltid Àr min parsning tokful, men fungerande.

type Instruction = FoldX of int | FoldY of int let parse filename = let data = System.IO.File.ReadAllLines filename let parseInstruction (line:string) = let parts = line.Split " " |> Seq.last |> (fun x -> x.Split "=") match (parts |> Seq.head) with | "x" -> FoldX (parts |> Seq.item 1 |> int) | "y" -> FoldY (parts |> Seq.item 1 |> int) | _ -> failwithf "Strange input" let parseLine set (line:string) = let parts = line.Split(",") let pos = (Seq.item 0 parts |> int, Seq.item 1 parts |> int) Set.add pos set let map = data |> Seq.takeWhile ((<>) "") |> Seq.fold (parseLine) Set.empty let instructions = data |> Seq.skipWhile ((<>) "") |> Seq.skip 1 |> Seq.map parseInstruction |> List.ofSeq (map, instructions) let fold map instruction = let foldX pos map (x,y) = if x<pos then map else map |> Set.remove (x,y) |> Set.add (2*pos - x, y) let foldY pos map (x,y) = if y<pos then map else map |> Set.remove (x,y) |> Set.add (x, 2*pos - y) let folder = match instruction with | FoldY pos -> foldY pos | FoldX pos -> foldX pos map |> Set.fold folder map let task1 (map, instructions) = instructions |> List.head |> fold map |> Seq.length let task2 (map, instructions) = instructions |> List.fold (fold) map let print (map :(int*int) Set) = let maxX = map |> Seq.map fst |> Seq.max let maxY = map |> Seq.map snd |> Seq.max for y in 0..maxY do for x in 0..maxX do if map.Contains (x,y) then printf "##" else (printf " ") printfn "" let input = parse "input.txt" printfn "Task 1: %i" (input |> task1) input |> task2 |> print

Dold text
Visa signatur

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

PermalÀnk
Medlem
●

Dag: 13
SprÄk: Rust

#![feature(hash_drain_filter)] use std::collections::HashMap; const MARK: char = '█'; fn main() { let input = std::fs::read_to_string("input.txt").unwrap(); let mut lines = input.lines(); let mut map: HashMap<(u32, u32), char> = HashMap::new(); let mut instructions = Vec::new(); while let Some(f) = lines.next() { if f.is_empty() { break; } let (x, y) = f.split_once(',').unwrap(); map.insert((x.parse::<u32>().unwrap(), y.parse::<u32>().unwrap()), MARK); } while let Some(f) = lines.next() { instructions.push( f.split(' ') .last() .unwrap() .split_once('=') .map(|p| (p.0, p.1.parse::<u32>().unwrap())) .unwrap(), ); } run(&mut map, &instructions[..1]); println!("Part 1: {}", map.len()); // 710 run(&mut map, &instructions[1..]); print(&mut map); // Part 2: EPLGRULR } fn run(data: &mut HashMap<(u32, u32), char>, instructions: &[(&str, u32)]) { for instruction in instructions { match instruction.0 { "y" => fold_y(data, instruction.1), _ => fold_x(data, instruction.1), } } } fn print(data: &mut HashMap<(u32, u32), char>) -> Option<()> { let y_max = data.keys().map(|(_, y)| *y).max()?; let y_min = data.keys().map(|(_, y)| *y).min()?; let x_max = data.keys().map(|(x, _)| *x).max()?; let x_min = data.keys().map(|(x, _)| *x).min()?; for y in y_min..=y_max { for x in x_min..=x_max { print!("{}", data.get(&(x, y)).unwrap_or(&' ')); } println!(); } Some(()) } fn fold_y(data: &mut HashMap<(u32, u32), char>, y: u32) { let height = y * 2; let drained: Vec<_> = data.drain_filter(|(_, y1), _| y1 > &y).collect(); for ((x, y), _) in drained { data.insert((x, height - y), MARK); } } fn fold_x(data: &mut HashMap<(u32, u32), char>, x: u32) { let width = x * 2; let drained: Vec<_> = data.drain_filter(|(x1, _), _| x1 > &x).collect(); for ((x2, y), _) in drained { data.insert((width - x2, y), MARK); } }

Dold text
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: 13
SprÄk: Go

type manual struct { markings map[int]position height, width int } type position struct { x, y int } func main() { lines, _ := helpers.ReadLines("input.txt") start := time.Now() man, index := getMarkings(lines) result := 0 for i, instruction := range lines[index:] { man.fold(instruction) if i == 0 { result = len(man.markings) } } duration := time.Since(start) fmt.Println(result) man.print() fmt.Println(duration) } func getMarkings(input []string) (manual manual, index int) { manual.markings = make(map[int]position) height, width := 0, 0 for i, line := range input { if line == "" { index = i + 1 break } values := strings.Split(line, ",") x, y := helpers.GetInt(values[0]), helpers.GetInt(values[1]) if x > width { width = x } if y > height { height = y } hash := helpers.Hash(x, y) manual.markings[hash] = position{x, y} } manual.height = height + 1 manual.width = width + 1 return } func (manual *manual) fold(instruction string) { args := strings.Split(strings.Split(instruction, " ")[2], "=") dir, index := args[0], helpers.GetInt(args[1]) if dir == "x" { manual.performFold(index+1, false) manual.width = index } else { manual.performFold(index+1, true) manual.height = index } } func (manual *manual) performFold(limit int, horizontal bool) { for key, mark := range manual.markings { if horizontal && mark.y >= limit { delete(manual.markings, key) index := 2*(limit-1) - mark.y hash := helpers.Hash(mark.x, index) mark.y = index manual.markings[hash] = mark } else if !horizontal && mark.x >= limit { delete(manual.markings, key) index := 2*(limit-1) - mark.x hash := helpers.Hash(index, mark.y) mark.x = index manual.markings[hash] = mark } } } func (manual manual) print() { fmt.Printf("height: %v, width: %v\n", manual.height, manual.width) for y := 0; y < manual.height; y++ { for x := 0; x < manual.width; x++ { if _, ok := manual.markings[helpers.Hash(x, y)]; ok { fmt.Print("#") } else { fmt.Print(".") } } fmt.Println() } }

Dold text
PermalÀnk
Hedersmedlem ★
●

Jag kunde inte lÄta bli, sÄ jag gjorde en tredje lösning till dag 8.
Ville testa om samma dÄliga kod översatt frÄn TypeScript till Rust skulle göra stor skillnad för prestandan, ffa med tanke pÄ att @SAFA kunde köra brute force pÄ under 20 ms i C, och min lösning som inte var brute force tog typ 6-7 ms i TypeScript.

Svaret Àr nej: brute force-koden jag hade Àr lÄngsam Àven i Rust, Àven om den Àr snabbare Àn TypeScript.

Fick ner TS-koden frÄn 5800 ms till 4350 ms med en Àndring, sen till 595-605 ms(!) med en optimering till som jag missat.
Motsvarande kod (alltsÄ efter optimeringarna) i Rust gÄr pÄ runt 180 ms i release-lÀge.

TypeScript:

import { Solution } from './solution.js'; import { Perf, readLines } from './common.js'; import { Permutation } from 'js-combinatorics'; const SEGMENT_MAP : Record<string, number> = { "abcefg": 0, "cf": 1, "acdeg": 2, "acdfg": 3, "bcdf": 4, "abdfg": 5, "abdefg": 6, "acf": 7, "abcdefg": 8, "abcdfg": 9 }; class Digit { segments: string; constructor(segments: string) { this.segments = segments.split('').sort().join(''); } // Map from invalid segments (e.g. dgb) to valid (e.g. acf, for 7) remap(conversionTable: Record<string, string>): Digit { this.segments = this.segments.split('') .map(c => conversionTable[c]) .sort() .join(''); return this; } // If these (actual) segments are lit, what digit is displayed? value(): number { return SEGMENT_MAP[this.segments]; } } export class Day8_TESTING implements Solution { ALL_MAPPINGS: Record<string, string>[] = []; calculateSegmentMap(patterns: string[]): Record<string, string> { const isValid = (mapping: Record<string, string>) => patterns.every(p => new Digit(p).remap(mapping).value() !== undefined); for (let mapping of this.ALL_MAPPINGS) { if (isValid(mapping)) return mapping; } return {}; } answer() { readLines("data/day8.txt", (data) => { let perf = new Perf(); // First, generate all possible segment mappings, once. for (let p of new Permutation("abcdefg")) { this.ALL_MAPPINGS.push({a: p[0], b: p[1], c: p[2], d: p[3], e: p[4], f: p[5], g: p[6]}); } let patterns : string[][] = []; let outputValues : string[][] = []; for (let line of data) { let [pattern, output] = line.split(" | "); patterns.push(pattern.split(" ")); outputValues.push(output.split(" ")); } let sum = 0; for (let i = 0; i < patterns.length; i++) { let mapping = this.calculateSegmentMap(patterns[i]); let outputDigits = outputValues[i].map(s => new Digit(s).remap(mapping).value()); let outputValue = parseInt(outputDigits.reduce((prev, curr) => prev + curr, "")); // Feeling lazy sum += outputValue; } console.log(`Day 8 Part 2: ${sum}`); perf.end(); }); } }

Dold text

Rust:

use std::fs::File; use std::io::Read; use std::collections::HashMap; use itertools::Itertools; use lazy_static::lazy_static; use phf::phf_map; use std::time::Instant; static SEGMENT_MAP: phf::Map<&'static str, i32> = phf_map! { "abcefg" => 0, "cf" => 1, "acdeg" => 2, "acdfg" => 3, "bcdf" => 4, "abdfg" => 5, "abdefg" => 6, "acf" => 7, "abcdefg" => 8, "abcdfg" => 9 }; struct Digit { segments: String } impl From<&String> for Digit { fn from(seg: &String) -> Self { Digit { segments: seg.clone() } } } impl Digit { fn remap(mut self, conversion_table: &HashMap<char, char>) -> Digit { self.segments = self.segments.chars() .map(|c| conversion_table[&c]) .sorted() .collect(); self } fn value(&self) -> Option<&i32> { SEGMENT_MAP.get(&self.segments) } } fn is_valid_map(patterns: &Vec<String>, mapping: &HashMap<char, char>) -> bool { patterns.iter().all(|p| Digit::from(p).remap(mapping).value().is_some()) } fn calculate_segment_map(patterns: &Vec<String>) -> &'static HashMap<char, char> { return ALL_MAPPINGS.iter() .filter(|m| is_valid_map(&patterns, m)) .next().unwrap(); } lazy_static! { static ref ALL_MAPPINGS: Vec<HashMap<char, char>> = { let mut all_maps = Vec::new(); for p in "abcdefg".chars().permutations(7).unique() { let mut map = HashMap::new(); map.insert('a', p[0]); map.insert('b', p[1]); map.insert('c', p[2]); map.insert('d', p[3]); map.insert('e', p[4]); map.insert('f', p[5]); map.insert('g', p[6]); all_maps.push(map); } assert!(all_maps.len() == 5040); all_maps }; } fn main() { let mut input = String::new(); let mut file = File::open("../../data/day8.txt").expect("Failed to open file"); file.read_to_string(&mut input).expect("Failed to read file"); let start = Instant::now(); let mut patterns: Vec<Vec<String>> = Vec::new(); let mut output_values: Vec<Vec<String>> = Vec::new(); for line in input.split("\r\n") { let mut parts = line.split(" | "); patterns.push(parts.next().unwrap().split(" ").map(str::to_string).collect()); output_values.push(parts.next().unwrap().split(" ").map(str::to_string).collect()); } let mut sum = 0; for i in 0..patterns.len() { let mapping = calculate_segment_map(&patterns[i]); let output_digits = output_values[i].iter().map(|s| Digit::from(s).remap(mapping).value().unwrap().to_string()); let output_value: i32 = output_digits.fold(String::new(), |prev, curr| prev + &curr).parse::<i32>().unwrap(); sum += output_value; } println!("Day 8 Part 2: {}", sum); println!("Time taken: {} us", start.elapsed().as_micros()); }

Dold text

BÄda gÄr förstÄs att förbÀttra ytterligare (utöver att lösa det utan brute force), men hela poÀngen hÀr var att se om motsvarande kod blir vÀldigt mycket snabbare i Rust. Drygt tre gÄnger snabbare Àr förstÄs inte illa pinkat, men det var ÀndÄ inte den galna skillnaden jag nÀstan rÀknat med.

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: 13
SprÄk: Carth

KĂ€nns som lugnet innan stormen nu...

(import std) (data Instruction (FoldX Nat) (FoldY Nat)) (define main (do io/bind (<- input (io/map unwrap! (read-file "inputs/day13.txt"))) (let1 [dots instrs] (map-two list/iter list/iter (parse! manual-parser input))) (display (str-append "Part 1: " (show-nat (set/count (fold-paper dots (iter/first! instrs)))))) (display (str-append "Part 2:\n" (draw-paper (foldl (<oo set/iter fold-paper) dots instrs)))))) (define (fold-paper dots instr) (let (([n map-dim] (match instr (case (FoldX x) [x map-car]) (case (FoldY y) [y map-cadr]))) ((mirror-relevant dot) (map-dim (fun (m) (if (> m n) (- (* (to-nat 2) n) m) m)) dot))) (set/collect cmp-pt (map mirror-relevant dots)))) (define (draw-paper dots) (let ((set (set/collect cmp-pt dots)) ([w h] (map-both (apps <o inc maximum list/iter) (unzip dots))) (w (inc w))) ((<o Str cadr) (array/build (fun (Unit i) [Unit (let ((x (rem i w)) (y (/ i w))) (if (= x (dec w)) ascii-newline (string/nth-byte! (to-nat 0) (if (set/member? cmp-pt [x y] set) "#" "."))))]) Unit (* w h))))) (define manual-parser (do parse/bind (<- dots ((<oo parse/many (parse/lift2 cons')) (parse/thenl parse/nat (parse/string ",")) (parse/thenl parse/nat (parse/string "\n")))) parse/space (<- instrs (parse/many (do parse/bind (parse/string "fold along ") (<- dim (parse/take-bytes (to-nat 1))) (parse/string "=") (<- n parse/nat) parse/space (parse/pure (match dim (case "x" (FoldX n)) (case _ (FoldY n))))))) (parse/pure [dots instrs]))) (define (cmp-pt [i1 j1] [i2 j2]) (match (num/cmp i1 i2) (case Eq (num/cmp j1 j2)) (case x x)))

Dold text
Visa signatur

Arbets- / Spelstation: Arch Linux - Ryzen 5 3600 - RX 7900 XT - 32G DDR4
Server: Arch Linux - Core i5-10400F - 16G DDR4

PermalÀnk
Medlem ★
●
Skrivet av Thomas:

Jag kunde inte lÄta bli, sÄ jag gjorde en tredje lösning till dag 8.
Ville testa om samma dÄliga kod översatt frÄn TypeScript till Rust skulle göra stor skillnad för prestandan, ffa med tanke pÄ att @SAFA kunde köra brute force pÄ under 20 ms i C, och min lösning som inte var brute force tog typ 6-7 ms i TypeScript.

Svaret Àr nej: brute force-koden jag hade Àr lÄngsam Àven i Rust, Àven om den Àr snabbare Àn TypeScript.

Fick ner TS-koden frÄn 5800 ms till 4350 ms med en Àndring, sen till 595-605 ms(!) med en optimering till som jag missat.
Motsvarande kod (alltsÄ efter optimeringarna) i Rust gÄr pÄ runt 180 ms i release-lÀge.

TypeScript:

import { Solution } from './solution.js'; import { Perf, readLines } from './common.js'; import { Permutation } from 'js-combinatorics'; const SEGMENT_MAP : Record<string, number> = { "abcefg": 0, "cf": 1, "acdeg": 2, "acdfg": 3, "bcdf": 4, "abdfg": 5, "abdefg": 6, "acf": 7, "abcdefg": 8, "abcdfg": 9 }; class Digit { segments: string; constructor(segments: string) { this.segments = segments.split('').sort().join(''); } // Map from invalid segments (e.g. dgb) to valid (e.g. acf, for 7) remap(conversionTable: Record<string, string>): Digit { this.segments = this.segments.split('') .map(c => conversionTable[c]) .sort() .join(''); return this; } // If these (actual) segments are lit, what digit is displayed? value(): number { return SEGMENT_MAP[this.segments]; } } export class Day8_TESTING implements Solution { ALL_MAPPINGS: Record<string, string>[] = []; calculateSegmentMap(patterns: string[]): Record<string, string> { const isValid = (mapping: Record<string, string>) => patterns.every(p => new Digit(p).remap(mapping).value() !== undefined); for (let mapping of this.ALL_MAPPINGS) { if (isValid(mapping)) return mapping; } return {}; } answer() { readLines("data/day8.txt", (data) => { let perf = new Perf(); // First, generate all possible segment mappings, once. for (let p of new Permutation("abcdefg")) { this.ALL_MAPPINGS.push({a: p[0], b: p[1], c: p[2], d: p[3], e: p[4], f: p[5], g: p[6]}); } let patterns : string[][] = []; let outputValues : string[][] = []; for (let line of data) { let [pattern, output] = line.split(" | "); patterns.push(pattern.split(" ")); outputValues.push(output.split(" ")); } let sum = 0; for (let i = 0; i < patterns.length; i++) { let mapping = this.calculateSegmentMap(patterns[i]); let outputDigits = outputValues[i].map(s => new Digit(s).remap(mapping).value()); let outputValue = parseInt(outputDigits.reduce((prev, curr) => prev + curr, "")); // Feeling lazy sum += outputValue; } console.log(`Day 8 Part 2: ${sum}`); perf.end(); }); } }

Dold text

Rust:

use std::fs::File; use std::io::Read; use std::collections::HashMap; use itertools::Itertools; use lazy_static::lazy_static; use phf::phf_map; use std::time::Instant; static SEGMENT_MAP: phf::Map<&'static str, i32> = phf_map! { "abcefg" => 0, "cf" => 1, "acdeg" => 2, "acdfg" => 3, "bcdf" => 4, "abdfg" => 5, "abdefg" => 6, "acf" => 7, "abcdefg" => 8, "abcdfg" => 9 }; struct Digit { segments: String } impl From<&String> for Digit { fn from(seg: &String) -> Self { Digit { segments: seg.clone() } } } impl Digit { fn remap(mut self, conversion_table: &HashMap<char, char>) -> Digit { self.segments = self.segments.chars() .map(|c| conversion_table[&c]) .sorted() .collect(); self } fn value(&self) -> Option<&i32> { SEGMENT_MAP.get(&self.segments) } } fn is_valid_map(patterns: &Vec<String>, mapping: &HashMap<char, char>) -> bool { patterns.iter().all(|p| Digit::from(p).remap(mapping).value().is_some()) } fn calculate_segment_map(patterns: &Vec<String>) -> &'static HashMap<char, char> { return ALL_MAPPINGS.iter() .filter(|m| is_valid_map(&patterns, m)) .next().unwrap(); } lazy_static! { static ref ALL_MAPPINGS: Vec<HashMap<char, char>> = { let mut all_maps = Vec::new(); for p in "abcdefg".chars().permutations(7).unique() { let mut map = HashMap::new(); map.insert('a', p[0]); map.insert('b', p[1]); map.insert('c', p[2]); map.insert('d', p[3]); map.insert('e', p[4]); map.insert('f', p[5]); map.insert('g', p[6]); all_maps.push(map); } assert!(all_maps.len() == 5040); all_maps }; } fn main() { let mut input = String::new(); let mut file = File::open("../../data/day8.txt").expect("Failed to open file"); file.read_to_string(&mut input).expect("Failed to read file"); let start = Instant::now(); let mut patterns: Vec<Vec<String>> = Vec::new(); let mut output_values: Vec<Vec<String>> = Vec::new(); for line in input.split("\r\n") { let mut parts = line.split(" | "); patterns.push(parts.next().unwrap().split(" ").map(str::to_string).collect()); output_values.push(parts.next().unwrap().split(" ").map(str::to_string).collect()); } let mut sum = 0; for i in 0..patterns.len() { let mapping = calculate_segment_map(&patterns[i]); let output_digits = output_values[i].iter().map(|s| Digit::from(s).remap(mapping).value().unwrap().to_string()); let output_value: i32 = output_digits.fold(String::new(), |prev, curr| prev + &curr).parse::<i32>().unwrap(); sum += output_value; } println!("Day 8 Part 2: {}", sum); println!("Time taken: {} us", start.elapsed().as_micros()); }

Dold text

BÄda gÄr förstÄs att förbÀttra ytterligare (utöver att lösa det utan brute force), men hela poÀngen hÀr var att se om motsvarande kod blir vÀldigt mycket snabbare i Rust. Drygt tre gÄnger snabbare Àr förstÄs inte illa pinkat, men det var ÀndÄ inte den galna skillnaden jag nÀstan rÀknat med.

Intessant! DÄ Àr det inte Typescript som gör den stora skillnaden utan algoritmen, trots att det Àr brute force.

PermalÀnk
●

Dag: 13
SprÄk: Python

from math import prod from typing import Generator, Tuple import numpy as np data = np.zeros((2000, 2000), dtype=bool) folds = [] max_i = 0 max_j = 0 for line in open("13.in"): line = line.rstrip() if "," in line: i, j = list(map(int, line.split(","))) data[j][i] = True max_i = max(max_i, j) max_j = max(max_j, i) elif "fold" in line: folds.append(line) data = data[: max_i + 1 + (max_i % 2), : max_j + 1 + (max_j % 2)] HEIGHT, WIDTH = data.shape def print_matrix(matrix): print("\n".join("".join("x" if c else " " for c in row) for row in matrix)) for f in folds: a, b = f.split(" ")[-1].split("=") HEIGHT, WIDTH = data.shape if a == "y": data = data[: HEIGHT // 2] | np.flip(data, axis=0)[: HEIGHT // 2] if a == "x": data = data[:, : WIDTH // 2] | np.flip(data, axis=1)[:, : WIDTH // 2] print_matrix(data)

Dold text
PermalÀnk
●

Dag: 14
SprÄk: Python

from collections import defaultdict, Counter start_string, unparsed_rules = open("14.in").read().split("\n\n") rules = dict(tuple(x.rstrip().split(" -> ")) for x in unparsed_rules.splitlines()) pairs = Counter(start_string[i : i + 2] for i in range(len(start_string) - 1)) char_count = Counter(start_string) def get_maximum_span() -> int: return max(char_count.values()) - min(char_count.values()) for i in range(40): if i == 10: print(get_maximum_span()) new_pairs = defaultdict(int) for pair, cur_count in pairs.items(): if pair in rules: c = rules[pair] new_pairs[pair[0] + c] += cur_count new_pairs[c + pair[1]] += cur_count char_count[c] += cur_count pairs = new_pairs print(get_maximum_span())

Dold text
PermalÀnk
Medlem
●

Dag: 14
SprÄk: C#

Som med fiskarna sÄ fungerade inte min initiala algoritm för del 2. IstÀllet för att konkatenera ihop hela strÀngen, sÄ blev det en lösning likt fiskarna dÀr jag istÀllet hÄller redan pÄ hur mÄnga antal det finns av varje "par".

internal class Puzzle14 : Puzzle<long> { protected override void Solve(string[] lines) { var rules = lines[2..].Select(x => x.Split(" -> ")).ToDictionary(x => x[0], x => x[1]); One = CountElems(rules, lines[0], 10); Two = CountElems(rules, lines[0], 40); } private static long CountElems(IDictionary<string, string> rules, string initTemplate, int times) { var pairCounts = initTemplate.Zip(initTemplate.Skip(1)) .Select(x => string.Concat(x.First, x.Second)) .GroupBy(x => x) .ToDictionary(x => x.Key, x => (long) x.Count()); var letterCounts = initTemplate .GroupBy(x => x) .ToDictionary(x => x.Key.ToString(), x => (long) x.Count()); foreach (var _ in Enumerable.Range(0, times)) { var newPairs = new Dictionary<string, long>(); foreach (var (pair, count) in pairCounts) { var elemToInsert = rules[pair]; var leftPair = pair[0] + elemToInsert; var rightPair = elemToInsert + pair[1]; newPairs[leftPair] = newPairs.GetValueOrDefault(leftPair, 0) + count; newPairs[rightPair] = newPairs.GetValueOrDefault(rightPair, 0) + count; letterCounts[elemToInsert] = letterCounts.GetValueOrDefault(elemToInsert, 0) + count; } pairCounts = newPairs.ToDictionary(x => x.Key, x => x.Value); } return letterCounts.Max(x => x.Value) - letterCounts.Min(x => x.Value); } }

Dold text
PermalÀnk
Medlem ★
●

Dag: 14
SprÄk: Python

import re from collections import Counter, defaultdict s, rules0 = open("input14").read().split("\n\n") rules = {(a,b) : c for a,b,c in re.findall("([A-Z])([A-Z]) -> ([A-Z])", rules0)} def steps(s, n): counts, elements = defaultdict(int), defaultdict(int) for i in range(len(s) - 1): counts[(s[i], s[i + 1])] += 1 for i in range(n): counts2 = defaultdict(int) for (a, c), i in counts.items(): b = rules[(a,c)] counts2[(a,b)] += i counts2[(b,c)] += i counts = counts2 elements[s[-1]] = 1 for (a, _), n in counts.items(): elements[a] += n return (max(elements.values()) - min(elements.values())) print(steps(s, 10), steps(s, 40))

Dold text
PermalÀnk
●

Dag: 14
SprÄk: Scala

object Day14 { val data = readLines("14/data.txt").iterator val template = (data.next() + " ").sliding(2).toSeq.groupMapReduce(identity)(_ => 1L)(_ + _) data.next() // skip line val rules = data.map { case s"$pair -> ${char(insert)}" => pair -> insert }.toMap def main(args: Array[String]): Unit = { def stepCount(from: Map[String, Long]) = { val res = from.toSeq.flatMap { case (pair, count) => rules.get(pair) match { case Some(insert) => Seq(s"${pair.head}$insert" -> count, s"$insert${pair.last}" -> count) case None => Seq(s"${pair.head} " -> 1L) } } res.groupMapReduce(_._1)(_._2)(_ + _) } def calcDiff(result: Map[String, Long]) = { val counts = result.groupMapReduce(_._1.head)(_._2)(_ + _).values counts.max - counts.min } // step 1 var polymer1 = template for(_ <- 0 until 10) { polymer1 = stepCount(polymer1) } println(calcDiff(polymer1)) // step 2 var polymer2 = template for(_ <- 0 until 40) { polymer2 = stepCount(polymer2) } println(calcDiff(polymer2)) } }

Dold text
PermalÀnk
Medlem ★
●

Dag 7 i TS, tar gÀrna emot tips hur jag kan göra pÄ del 2 utan att behöva berÀka 2 olika möjligheter. Annars Àr jag nöjd att jag lyckades identifiera den matematiska aspekten eftersom jag Àr vÀrdelös pÄ matte.

import { GetFileRowAsNumbers, GetFileRows } from "./fileReader"; const solve = (crabPositions: number[]) => { crabPositions.sort((a, b) => a - b); const median = crabPositions[crabPositions.length/2] const answerPart1 = crabPositions.filter(pos => pos !== median).reduce((acc, curr) => { acc = acc + Math.abs(curr-median); return acc }, 0) console.log(answerPart1) const sum = crabPositions.reduce((acc, curr) => acc+=curr, 0) const averages = [Math.floor(sum/crabPositions.length),Math.round(sum/crabPositions.length)] const answerPart2 = crabPositions.reduce((acc, curr) => { const steps = [Math.abs(curr-averages[0]), Math.abs(curr-averages[1])] //calculate factorial but with + instead of * using formula (n^2+n)/2 const factorialMenMedPlus = steps.map(s => (s*s+s)/2) //console.log(`pos: ${curr} fact: ${factorialMenMedPlus} steps: ${steps} avg: ${average}`) acc = {first: acc.first + factorialMenMedPlus[0], second: acc.second + factorialMenMedPlus[1]}; return acc }, {first: 0, second: 0}) console.log(Math.min(...Object.values(answerPart2))) }; const solveDay7 = async () => { const crabPositions = await GetFileRowAsNumbers("./src/inputs/input-day7.txt"); solve(crabPositions); }; export default solveDay7;

Dold text
PermalÀnk
Medlem
●

Dag: 14
SprÄk: C++

Jag fick ocksÄ gÄ den lÄnga vÀgen och skriva om koden för att klara del 2, dÄ det blev en lite för lÄng polymer att hÄlla reda pÄ. Tycker det blev rÀtt bra idag till slut, men det tog lite tid. Lyckades fÄ med en funktionstemplate idag för första gÄngen.

using namespace std; typedef unsigned long long ull; struct polymer { map<string,char> rules; map<char,ull> char_counts; map<string,ull> pair_counts; }; template <typename T> void add_inc(map<T,ull> &counts, T key, ull val) { pair<typename map<T,ull>::iterator,bool> ret; ret = counts.insert(pair<T,ull>(key,val)); if (!ret.second) { counts.at(key) += val; } } polymer parse(vector<string> str_data) { polymer p; string init_str = str_data[0]; int n_chars = init_str.size(); for (int i = 0; i < n_chars-1; i++) { string key = string() + init_str[i] + init_str[i+1]; add_inc(p.pair_counts, key, 1); } string regex_str = "^(\\w{2})\\s->\\s(\\w)$"; regex regex_obj(regex_str); smatch matches; for (int i = 2, n = str_data.size(); i < n; i++) { regex_search(str_data[i], matches, regex_obj); p.rules.insert(make_pair(matches.str(1),matches.str(2)[0])); } //add character counts for initial template for (int i = 0; i < n_chars; i++) { add_inc(p.char_counts, init_str[i], 1); } return p; } void evolve(polymer &p, int n_steps) { map<string,ull> old_pair_counts; for (int step = 0; step < n_steps; step++) { old_pair_counts = p.pair_counts; for (auto const& [key, val] : old_pair_counts) { if (val > 0) { char new_char = p.rules.at(key); string new_pair_1 = string() + key[0] + new_char; string new_pair_2 = string() + new_char + key[1]; add_inc(p.pair_counts, new_pair_1, val); add_inc(p.pair_counts, new_pair_2, val); add_inc(p.pair_counts, key, -val); add_inc(p.char_counts, new_char, val); } } } return; } ull solve(polymer &p, bool part2 = false) { int n_steps = part2? 30 : 10; evolve(p, n_steps); ull mn=p.char_counts.begin()->second, mx = mn; //c++ 17 for (auto const& [key, val] : p.char_counts) { if (val < mn) mn = val; if (val > mx) mx = val; } return mx-mn; } int main() { int day = 14; auto start = chrono::high_resolution_clock::now(); string filename = "../../input/day_" + to_string(day) + ".txt"; vector<string> string_data = read_file<string>(filename,false); polymer p = parse(string_data); auto parsed = chrono::high_resolution_clock::now(); ull part_1 = solve(p, false); ull part_2 = solve(p, true); auto solved = chrono::high_resolution_clock::now(); vector<chrono::high_resolution_clock::time_point> time_stamps{start , parsed, solved}; print_results<ull>(day, part_1, part_2, time_stamps); return 0; }

Dold text
PermalÀnk
Medlem
●

SprÄk: Carth
Dag: 14

Min approach för del 1 dog ju totalt för del 2, sÄ behövde tÀnka om lite.

Ursprungligen sÄ tog jag approachen att liksom besöka alla noder i trÀdet som bildas av alla divisioner. Det rÀckte bra för del 1, men storleken pÄ trÀdet vÀxer ju sÄklart exponentiellt i höjden, sÄ för del 2 körde den fast totalt.

TÀnkte tillbaks till dag 6 och fiskarna, och baserade min lösning pÄ att hÄlla koll pÄ antalet par av varje slag i en array. JÀklar vad fort det gick nu dÄ! Till och med med lÄngsamma Carth tog det bara ~20ms nu!

Dold text

(import std) (define main (do io/bind (<- input (io/map unwrap! (read-file "inputs/day14.txt"))) (let (([template ls] (next! (lines input))) (rules (array/set-multiple! (array/unsafe-uninit (to-nat (* 26 26))) (map parse-rule (skip 1 ls)))))) (display (str-append "Part 1: " (show-int (grow-polymer-from-template template rules 10)))) (display (str-append "Part 2: " (show-int (grow-polymer-from-template template rules 40)))))) (define (grow-polymer-from-template template rules nsteps) (define (nonzero-pair-counts pair-counts) (filter (<o (flip > 0) cadr) (enumerate (array/iter pair-counts)))) (define (divide [pair-ix n]) (let (([l1 l2] (ix-to-pair pair-ix)) (r (array/lookup! pair-ix rules))) (list/iter (list [(pair-to-ix [l1 r]) n] [(pair-to-ix [r l2]) n])))) (define (go nsteps pairs) (let ((pair-counts (array/unsafe-uninit (to-nat (* 26 26)))) (pair-counts (array/modify-multiple! pair-counts (map (map-cadr +) pairs)))) (if (= nsteps 0) pair-counts (go (dec nsteps) (flat-map divide (nonzero-pair-counts pair-counts)))))) (let ((template (array/map char-to-num (string/as-array template))) (first-elem (to-nat (array/first! template))) (last-elem (to-nat (array/last! template))) (pair-counts (go nsteps (zip (map (<o pair-to-ix array/first-two!) (array/windows (to-nat 2) template)) (repeat 1)))) (dup-single-counts (flat-map (fun ([i n]) ((uncurry iter/chain) (map-both (<o iter/once (flip cons' n)) (ix-to-pair i)))) (nonzero-pair-counts pair-counts))) (single-counts (apps |> (array/unsafe-uninit (to-nat 26)) (flip array/modify-multiple! (map (map-cadr +) dup-single-counts)) (array/modify! inc first-elem) (array/modify! inc last-elem) (array/map (flip / 2))))) (- (maximum (array/iter single-counts)) (minimum (filter (flip > 0) (array/iter single-counts)))))) (define (parse-rule s) (let ((l1 (string/nth-byte! (to-nat 0) s)) (l2 (string/nth-byte! (to-nat 1) s)) (r (string/nth-byte! (to-nat 6) s))) [(pair-to-ix [(char-to-num l1) (char-to-num l2)]) (char-to-num r)])) (define (char-to-num c) (- c ascii-A)) (define (pair-to-ix [n m]) (+ (* (to-nat 26) (to-nat n)) (to-nat m))) (define (ix-to-pair i) [(/ i (to-nat 26)) (rem i (to-nat 26))])

Dold text
Visa signatur

Arbets- / Spelstation: Arch Linux - Ryzen 5 3600 - RX 7900 XT - 32G DDR4
Server: Arch Linux - Core i5-10400F - 16G DDR4

PermalÀnk
Medlem ★
●
Skrivet av GLaDER:

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

Rolig uppgift, men det tog alldeles för lÄng tid att hitta uttrycket för det faktiska vikandet. SkÀms lite sÄhÀr i efterhand. Men men. NÀr jag vÀl hade det pÄ plats var resten enkel.

Dold text

Jag tÀnkte att det borde finnas nÄgot i numpy som flippar matriser, men det var inte vÀrt att ge sig ut pÄ jakt.

Dold text

Dag: 14
SprÄk: Python 3
Lösning: GitHub

Tycker ju att del 2 frÄn dag 6 borde ha uppenbarat sig i bakhuvudet, men det gjorde den inte, men efter en knuff i rÀtt riktning gick det vÀgen.

Dold text
Visa signatur

:(){ :|:& };:

đŸŠđŸ»â€â™‚ïž   đŸšŽđŸ»â€â™‚ïž   đŸƒđŸ»â€â™‚ïž   ☕

PermalÀnk
Medlem
●

För er som löst dag 13, testa gÀrna att köra med nedan input
https://pastebin.com/583RYNgW

PermalÀnk
Medlem ★
●

Dag:14
SprÄk: Go

type polymer struct { template polyTemplate pairOccurances map[string]int occurances map[string]int max, min int } type polyTemplate map[string]string func main() { lines, _ := helpers.ReadLines("input.txt") start := time.Now() polymer := initPolymerization(lines) polymer.performPolymerization(10) fmt.Printf("%v %v %v\n", polymer.min, polymer.max, polymer.max-polymer.min) polymer = initPolymerization(lines) polymer.performPolymerization(40) fmt.Printf("%v %v %v\n", polymer.min, polymer.max, polymer.max-polymer.min) duration := time.Since(start) fmt.Println(duration) } func initPolymerization(input []string) (polymer polymer) { polymer.occurances = make(map[string]int) polymer.pairOccurances = make(map[string]int) polymer.max = math.MinInt64 polymer.min = math.MaxInt64 for i := 0; i < len(input[0])-1; i++ { c1, c2 := string(input[0][i]), string(input[0][i+1]) pair := c1 + c2 polymer.pairOccurances[pair]++ } for i := 0; i < len(input[0]); i++ { polymer.occurances[string(input[0][i])]++ } polymer.template = make(polyTemplate) for _, line := range input[2:] { line = strings.ReplaceAll(line, " ", "") args := strings.Split(line, "->") instruction, result := args[0], args[1] polymer.template[instruction] = result } return } func (polymer *polymer) performPolymerization(times int) { for t := 0; t < times; t++ { newPairOccurances := make(map[string]int) for pair, value := range polymer.pairOccurances { newChar := polymer.template[pair] polymer.occurances[newChar] += value firstPair := string(pair[0]) + newChar secondPair := newChar + string(pair[1]) newPairOccurances[firstPair] += value newPairOccurances[secondPair] += value } polymer.pairOccurances = newPairOccurances } for _, val := range polymer.occurances { if val > polymer.max { polymer.max = val } else if val < polymer.min { polymer.min = val } } }

Dold text

kommentar

skrev en naiv lösning först för del 1 som jag fick kasta direkt nÀr jag sÄg del 2

Dold text
PermalÀnk
Hedersmedlem ★
●
Skrivet av Xenofonus:

Dag 7 i TS, tar gÀrna emot tips hur jag kan göra pÄ del 2 utan att behöva berÀka 2 olika möjligheter. Annars Àr jag nöjd att jag lyckades identifiera den matematiska aspekten eftersom jag Àr vÀrdelös pÄ matte.

Jag kör ocksÄ TS, verkar bara vara vi (som postar Ätminstone) tror jag?
Vet inte exakt hur du menar med att utan berÀkna tvÄ möjligheter, men min lösning ser ut sÄhÀr: day7.ts

Skrivet av hngl:

För er som löst dag 13, testa gÀrna att köra med nedan input
https://pastebin.com/583RYNgW

Haha, jÀvligt snyggt

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

Halkar ju efter lite men well...

Dag: 10
SprÄk: Dart
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
Datavetare ★
●

Dag: 13
SprÄk: Rust

Av nÄgon anledning hyfsat lÄngsam, tar ~640”s pÄ en M1

use crate::solution::Solution; use fnv::FnvHashSet; use std::cmp::max; type Pos = (u32, u32); #[derive(Clone, Copy)] enum Fold { Up(u32), Left(u32), } struct Day13 { dots: FnvHashSet<Pos>, folds: Vec<Fold>, } impl Solution for Day13 { fn part1(&mut self) -> String { fold_paper(self.folds[0], &self.dots) .len() .to_string() } fn part2(&mut self) -> String { draw_dots(&self.all_folds()) } } impl Day13 { fn all_folds(&self) -> FnvHashSet<Pos> { let mut dots = self.dots.clone(); for &fold_instr in &self.folds { dots = fold_paper(fold_instr, &dots); } dots } } fn fold_paper(fold_instr: Fold, dots: &FnvHashSet<Pos>) -> FnvHashSet<Pos> { dots .iter() .map(|&dot| fold_along(fold_instr, dot)) .collect() } fn fold_along(fold_instr: Fold, pos: Pos) -> Pos { match fold_instr { Fold::Left(x) if x < pos.0 => (2 * x - pos.0, pos.1), Fold::Up(y) if y < pos.1 => (pos.0, 2 * y - pos.1), _ => pos, } } fn draw_dots(dots: &FnvHashSet<Pos>) -> String { let (width, height) = canvas_size(dots); let mut canvas = String::new(); for y in 0..=height { canvas.push('\n'); for x in 0..=width { if dots.contains(&(x, y)) { canvas.push('█'); } else { canvas.push(' '); } } } canvas } fn canvas_size(dots: &FnvHashSet<Pos>) -> (u32, u32) { dots .iter() .fold((0, 0), |sz, dot| (max(sz.0, dot.0), max(sz.1, dot.1))) } pub fn new(input: &str) -> Box<dyn Solution> { let mut lines = input.lines(); let mut dots = FnvHashSet::default(); loop { let dot_desc = lines.next().unwrap(); if dot_desc.is_empty() { break; } let dot = scan_fmt!(dot_desc, "{d},{d}", u32, u32).expect("Invalid dot"); dots.insert(dot); } let mut folds = Vec::new(); for fold_desc in lines { let (axis, pos) = scan_fmt!(fold_desc, "fold along {}={d}", String, u32).expect("Invalid fold format"); folds.push(if axis == "x" { Fold::Left(pos) } else { Fold::Up(pos) }); } Box::new(Day13 { dots, folds }) }

Dold text

Dag: 14
SprÄk: Rust

Ca 80”s pÄ en M1, lÄngt ifrÄn den mest kompakta lösningen...

use crate::solution::Solution; use fnv::FnvHashMap; use itertools::{MinMaxResult, Itertools}; const ELEMENT_BITS: usize = 5; const DENSE_ARRAY_SZ: usize = 1 << ELEMENT_BITS; const SPARSE_ARRAY_SZ: usize = 1 << ELEMENT_BITS * 2; type Synthesises = [u8; SPARSE_ARRAY_SZ]; type ElementCount = [u64; DENSE_ARRAY_SZ]; struct Day14 { synthesises: Synthesises, step: usize, element_counts: ElementCount, element_pairs: FnvHashMap<(u8, u8), u64>, } impl Solution for Day14 { fn part1(&mut self) -> String { self.after_step(10).to_string() } fn part2(&mut self) -> String { self.after_step(40).to_string() } } impl Day14 { fn after_step(&mut self, n: usize) -> u64 { for _ in self.step..n { let mut next_elem_pairs = FnvHashMap::default(); next_elem_pairs.reserve(self.element_pairs.len()); for (&elem_pair, &count) in &self.element_pairs { // Each pair adds one new element to the polymer... let new_element = self.synthesises[pair_idx(elem_pair)]; self.element_counts[element_idx(new_element)] += count; // ...which produce two new target pairs per source pair *next_elem_pairs.entry((elem_pair.0, new_element)).or_default() += count; *next_elem_pairs.entry((new_element, elem_pair.1)).or_default() += count; } self.element_pairs = next_elem_pairs; } self.step = n; minmax_delta(self.element_counts.into_iter().filter(|&cnt| cnt > 0)) } } fn minmax_delta(cnts: impl Iterator<Item=u64>) -> u64 { match cnts.minmax() { MinMaxResult::MinMax(small, large) => large - small, _ => panic!("Unexpected argument"), } } fn element_idx(element: u8) -> usize { (element - 'A' as u8) as usize } fn pair_idx(p: (u8, u8)) -> usize { (element_idx(p.1) << ELEMENT_BITS) + element_idx(p.0) } pub fn new(input: &str) -> Box<dyn Solution> { let mut lines = input.lines(); let start_polymer = lines.next().unwrap().to_owned(); lines.next(); let mut synt = FnvHashMap::default(); for line in lines { let (from, to) = line.split_once(" -> ") .expect("Invalid data format"); let mut from_ch = from.chars(); synt.insert((from_ch.next().unwrap() as u8, from_ch.next().unwrap() as u8), to.chars().next().unwrap() as u8); } let mut synthesises = [0; SPARSE_ARRAY_SZ]; for (pair, elem) in synt { synthesises[pair_idx(pair)] = elem; } let mut element_counts = [0; DENSE_ARRAY_SZ]; for element in start_polymer.bytes() { element_counts[element_idx(element)] += 1; } let mut element_pairs = FnvHashMap::default(); for elem_pair in start_polymer.bytes().zip(start_polymer.bytes().skip(1)) { *element_pairs.entry(elem_pair).or_default() += 1; } Box::new(Day14{ synthesises, step: 0, element_counts, element_pairs, }) }

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

Dag: 14
SprÄk: TypeScript (med Node.js)
Lösning: https://github.com/exscape/AOC2021/blob/main/src/day14.ts

Runt 3.3 ms. Naiva lösningen tog 37 ms för del 1, och kom bara till typ 17-18 iterationer pÄ 5+ sekunder.
En av de svÄraste för mig, tog ett tag att sluta förvirra detta med antalet av varje element med uppdelningen i par. Det blev mycket enklare nÀr jag insÄg att en tillÀggs-operation alltid bara lÀgger till en av den bokstaven, och att alla andra Àr orörda

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 ★
●
Skrivet av GLaDER:

Dag: 14
SprÄk: Python 3
Lösning: GitHub

Tycker ju att del 2 frÄn dag 6 borde ha uppenbarat sig i bakhuvudet, men det gjorde den inte, men efter en knuff i rÀtt riktning gick det vÀgen.

Dold text

Dag: 15
SprÄk: Python 3
Lösning: GitHub

Dijkstra alltsÄ.... det tog alldeles för lÄng tid innan jag fick till algoritmen; och jag Àr fortfarande inte nöjd med exekveringstiden. PÄ Del 2 var min approach att Àndra input, istÀllet för att göra nÄgot "smart" med algoritmen. 12s att hitta en lösning.

Dold text
Visa signatur

:(){ :|:& };:

đŸŠđŸ»â€â™‚ïž   đŸšŽđŸ»â€â™‚ïž   đŸƒđŸ»â€â™‚ïž   ☕

PermalÀnk
Medlem ★
●

Dag: 15
SprÄk: Python 3

from heapq import heappush, heappop import numpy as np a= np.array([[int(i) for i in s.strip()] for s in open("input15").readlines()]) def neighbors(p, a): x, y = p if x > 0: yield (x - 1, y) if x < a.shape[0] - 1: yield (x + 1, y) if y > 0: yield (x, y - 1) if y < a.shape[1] - 1: yield (x, y + 1) def bfs(a): start, end = (0,0), (a.shape[0] - 1, a.shape[1] - 1) low = np.full(a.shape, 99999) low[start] = 0 paths = [] heappush(paths, (0, start)) while paths: risk, pos = heappop(paths) for n in neighbors(pos, a): if (newrisk := risk + a[n]) < low[n]: low[n] = newrisk heappush(paths, (newrisk, n)) return risk print(bfs(a)) b = np.concatenate([a, a + 1, a + 2 , a + 3, a + 4]) c = np.concatenate([b, b + 1, b + 2 , b + 3, b + 4], axis = 1) c = (c - 1) % 9 + 1 print(bfs(c))

Dold text
Suck, ibland gör man saker av gammal vana. Man behöver inte hÄlla reda pÄ vÀgen man tog sig till X, bara X. Tack Zlashy
PermalÀnk
Medlem
●

Dag: 15
SprÄk: C#

internal class Puzzle15 : Puzzle<int> { protected override void Solve(string[] lines) { var grid = Grid.CreateGrid(lines); One = GetLowestRisk(grid); Two = GetLowestRisk(ExpandGrid(grid)); } private static int[,] ExpandGrid(int[,] grid) { var newGrid = new int[grid.GetLength(0) * 5, grid.GetLength(1) * 5]; foreach (var i in Enumerable.Range(0, 25)) { var col = i % 5; var row = (i / 5); foreach (var (x, y) in Grid.Iterate(grid)) { var oldVal = grid[x, y] + col + row; if (oldVal > 9) { oldVal -= 9; } newGrid[x + (col * grid.GetLength(0)), y + (row * grid.GetLength(1))] = oldVal; } } return newGrid; } private static int GetLowestRisk(int[,] riskGrid) { var target = (x: riskGrid.GetLength(0) - 1, y: riskGrid.GetLength(1) -1); var queue = new PriorityQueue<(int x, int y), int>(); var totalRiskGrid = new int[riskGrid.GetLength(0), riskGrid.GetLength(1)]; totalRiskGrid[0, 0] = 0; queue.Enqueue((0, 0), 0); while (queue.Count > 0) { var p = queue.Dequeue(); foreach (var n in Grid.GetNeighbours(riskGrid, p, false)) { if (totalRiskGrid[n.x, n.y] == 0) { var totalRisk = totalRiskGrid[p.x, p.y] + riskGrid[n.x, n.y]; totalRiskGrid[n.x, n.y] = totalRisk; if (n == target) { break; } queue.Enqueue(n, totalRisk); } } } return totalRiskGrid[target.x, target.y]; } }

Dold text
PermalÀnk
Medlem ★
●

Jag blir inte riktigt klok pÄ del 2 pÄ dag 15. Jag har tillomed anvÀnt nÄgon annans lösning hÀr och fÄr ÀndÄ inte rÀtt svar.

PermalÀnk
Medlem ★
●

Dag 15
SprÄk C#
Kod:github

Som typ alla andra blev det dijkstras algoritm idag. multipliceringen i del 2 körde jag en lite mindre smart variant pÄ, antar jag... men sÄ Ät jag ju julbord emellan, sÄ hellre nÄt som funkar direkt som jag inte behöver lÀgga sÄ mycket tÀnkande pÄ.

Dold text
Visa signatur

The power of GNU compiles you!
"Often statistics are used as a drunken man uses lampposts -- for support rather than illumination."

PermalÀnk
Medlem
●

Dag: 15
SprÄk: Carth

Även efter att ha optimerat min implementation av prioritetskö (binomial heap) sĂ„ tar part 2 sĂ„ mycket som 4 sekunder att köra pĂ„ min dator. Galet mycket, om man tĂ€nker pĂ„ hur mycket liknande jobb en spelmotor mĂ„ste hinna med pĂ„ bara nĂ„gra millisekunder.

I grund och botten Àr problemet att i stort sett alla mina funktionsanrop resulterar i sophanterad heap-allokering. Jag har planerat optimeringar i Carths kodgenererare lÀnga för att ÄtgÀrda detta, men jag har en pÄgÄende refaktorering jag mÄste göra klart först. TyvÀrr har jag bara stundvis lust att jobba vidare pÄ refaktoreringen, sÄ optimeringarna dröjer. Men jag fÄr vÀl vara glad att det gÄr att lösa dom hÀr problemen i Carth över huvud taget!

Dold text
Klicka för mer information

(import std) (define main (do io/bind (<- input (io/map unwrap! (read-file "inputs/day15.txt"))) (let ((width (string/length-bytes (iter/first! (lines input)))) (flat-array (array/collect (map (flip - ascii-0) (flat-map string/bytes (lines input))))) (grid (array/collect (array/chunks width flat-array))))) (display (str-append "Part 1: " (show-nat (to-nat (dijkstra grid))))) (display (str-append "Part 2: " (show-nat (to-nat (part2 grid))))))) (define (part2 grid) (let ((dim (array/length grid)) (k (to-nat 5)) (big-dim (* k dim)) ((populate-big-ix ix) (let ((bi (/ ix big-dim)) (bj (rem ix big-dim)) (si (rem bi dim)) (sj (rem bj dim)) (delta (+ (/ bi dim) (/ bj dim)))) (inc (rem (dec (+ (cast delta) (array/lookup2d! [si sj] grid))) (cast 9))))) ([Unit flat] (array/build (fun (Unit ix) [Unit (populate-big-ix ix)]) Unit (square big-dim))) (grid' (array/collect (array/chunks (* (to-nat 5) dim) flat)))) (dijkstra grid'))) (define (dijkstra grid) (define dim (array/length grid)) (define end [(dec dim) (dec dim)]) (define (cmp [weight1 . _] [weight2 . _]) (num/cmp weight1 weight2)) (define (go risks pq) (let1 [[risk . pt] pq] (pq/delete-min! cmp pq) (if (cmp/= cmp-pt pt end) risk (if (< risk (array/lookup2d! pt risks)) (go (array/mutate2d! pt risk risks) (foldl (flip (pq/insert cmp)) pq (map (fun (ad) (let1 drisk (to-n16 (array/lookup2d! ad grid)) [(+ risk drisk) . ad])) (adjecents dim pt)))) (go risks pq))))) (go (array/map (array/map (const (to-n16 -1))) grid) (pq/singleton [(to-n16 0) . [(to-nat 0) (to-nat 0)]]))) (define (cmp-pt [i1 j1] [i2 j2]) (match (num/cmp i1 i2) (case Eq (num/cmp j1 j2)) (case x x))) (define (adjecents dim [i j]) (apps iter/chain (if (< i (dec dim)) (iter/once [(inc i) j]) iter/nil) (if (< j (dec dim)) (iter/once [i (inc j)]) iter/nil) (if (> i (to-nat 0)) (iter/once [(dec i) j]) iter/nil) (if (> j (to-nat 0)) (iter/once [i (dec j)]) iter/nil)))

Visa mer
Visa signatur

Arbets- / Spelstation: Arch Linux - Ryzen 5 3600 - RX 7900 XT - 32G DDR4
Server: Arch Linux - Core i5-10400F - 16G DDR4

PermalÀnk
Datavetare ★
●

Dag: 15
SprÄk: Rust

Har gjort 3 olika varianter, gÄtt frÄn ~50ms genom att helt sonika köra med Dijkstra frÄn pathfinding crate, till att implementera att egen variant av Dijkstra (en förenkling Àr ju att man inte behöver hÄlla reda pÄ vÀgen genom kartan) som tog det till ~30 ms, till ett rejÀlt hack som anvÀnder sig av bidirectional search Dijkstra som tog det hela till ~20 ms.

Helt OK, men lite nedslÄende att denna dag tar ungefÀr 4 gÄnger sÄ lÄng tid som det tar att lösa övriga 14 luckor totalt sett...

Dold text
Visa signatur

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