🌟 Advent of Code (AoC) 2024 🌟

PermalÀnk
Medlem ★
●

Dag 20, C#

Kunde ÄteranvÀnda mycket frÄn dag 18.

using Position = (int x, int y); var lines = File.ReadAllLines("input.txt"); (int sumpart1, int sumpart2, int max) = (0, 0, lines.Length); HashSet<Position> obstacles = []; (Position start, Position end) = ((0, 0), (0, 0)); for (int y = 0; y < max; y++) for (int x = 0; x < max; x++) { if (lines[y][x] == '#') obstacles.Add((x, y)); else if (lines[y][x] == 'S') start = ((x, y)); else if (lines[y][x] == 'E') end = ((x, y)); } int initial_distance = navigate(obstacles, start, end, out var walkable); int aim_for = initial_distance - 100; walkable[end] = initial_distance; Parallel.ForEach(walkable, cheat_start => { foreach (var cheat_end in walkable.Where(c_end => c_end.Value > cheat_start.Value && manhattan(c_end.Key, cheat_start.Key) <= 20)) { int mdist = manhattan(cheat_end.Key, cheat_start.Key); int cost = (initial_distance - cheat_end.Value) + mdist + cheat_start.Value; if (cost <= aim_for) { if (mdist == 2) Interlocked.Increment(ref sumpart1); Interlocked.Increment(ref sumpart2); } } }); Console.WriteLine("Part 1: " + sumpart1); Console.WriteLine("Part 2: " + sumpart2); int navigate(HashSet<Position> obstacles, Position start, Position end, out Dictionary<Position, int> cost) { cost = []; LinkedList<(Position position, int cost)> list = []; HashSet<Position> seen = []; list.AddLast((start, 0)); for (var node = list.First; node != null; node = node.Next) { foreach (var n in neighbours(node.Value.position)) { if (seen.Contains(n)) continue; if (obstacles.Contains(n)) continue; if (n == end) return node.Value.cost + 1; seen.Add(n); cost[n] = node.Value.cost + 1; list.AddLast((n, node.Value.cost + 1)); } } return int.MaxValue; } IEnumerable<Position> neighbours(Position pos) { Position[] rel_pos = [(0, 1), (1, 0), (0, -1), (-1, 0)]; foreach (var (x, y) in rel_pos) { var new_pos = (pos.x + x, pos.y + y); if (inRange(new_pos)) yield return new_pos; } yield break; } bool inRange(Position pos) => (pos.x < max && pos.x >= 0 && pos.y < max && pos.y >= 0); int manhattan(Position pos1, Position pos2) => Math.Abs(pos1.x - pos2.x) + Math.Abs(pos1.y - pos2.y);

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: 20
SprÄk: Python (Numpy)

import numpy as np from itertools import product maze = np.array([list(l.strip()) for l in open("input20.txt").readlines()]) def find_path(maze): path = [(row, col) for row in range(len(maze)) for col in range(len(maze[0])) if maze[row][col] == 'S'] while maze[r := path[0][0]][c := path[0][1]] != 'E': for dir in [(0, 1), (1, 0), (0, -1), (-1, 0)]: if maze[r + dir[0]][c + dir[1]] in '.E' and (r + dir[0], c + dir[1]) not in path: path.insert(0, (r + dir[0], c + dir[1])) return path path_length = np.zeros_like(maze, dtype=int) for i, (r, c) in enumerate(find_path(maze)[::-1]): path_length[r][c] = i + 1 def create_distance_diamond(a, center, radius): r, c = np.ogrid[:a.shape[0], :a.shape[1]] dist = abs(r - center[0]) + abs(c - center[1]) mask = dist <= radius diamond = np.zeros_like(a, dtype=int) diamond[mask] = dist[mask] return diamond def cheats_in_radius(radius): count = 0 for rc in product(range(maze.shape[0]), range(maze.shape[1])): if path_length[rc] != 0: distance = create_distance_diamond(path_length, rc, radius) cheats = (np.abs((path_length - path_length[rc])) - distance)[(distance != 0) & (path_length != 0)] count += sum(cheats >= 100) return count // 2 print(*[cheats_in_radius(r) for r in [2, 20]])

Dold text
Tog bort dumheter
PermalÀnk
Medlem
●

Dag: 20
SprÄk: Java
Lösning: GitHub

PermalÀnk
Medlem
●

Day: 20
SprÄk: Scala

Blev lite mitt i natten programmering och koden ser ut dÀrefter. Inte riktigt typisk scala kod... ~3 ms för bÄda delarna.

object Day20: val path = """20.txt""" val data = Using.resource(Source.fromFile(path))(_.getLines().map(_.toCharArray).toArray) val nRows = data.length val nCols = data(0).length def parse(data: Array[Array[Char]]) = var sr, sc, er, ec = 0 val pr = Array.newBuilder[Int] val pc = Array.newBuilder[Int] var r = 0 while r < nRows do var c = 0 while c < nCols do if data(r)(c) != '#' then pr += r pc += c if data(r)(c) == 'S' then sr = r sc = c if data(r)(c) == 'E' then er = r ec = c c += 1 r += 1 (sr, sc, er, ec, pr.result(), pc.result()) def calcCosts(data: Array[Array[Char]], fromRow: Int, fromCol: Int, toRow: Int, toCol: Int) = val costs = Array.fill(nRows, nCols)(Int.MaxValue) var cr = fromRow var cc = fromCol var n = 0 while cr != toRow || cc != toCol do costs(cr)(cc) = n data(cr)(cc) = '#' if data(cr - 1)(cc) != '#' then cr -= 1 else if data(cr)(cc + 1) != '#' then cc += 1 else if data(cr + 1)(cc) != '#' then cr += 1 else if data(cr)(cc - 1) != '#' then cc -= 1 n += 1 costs(cr)(cc) = n costs val (sr, sc, er, ec, pr, pc) = parse(data) val costs = calcCosts(data, sr, sc, er, ec) def part1 = var count = 0 var i = 0 while i < pr.length do val r = pr(i) val c = pc(i) if r - 2 > 0 && costs(r)(c) - costs(r - 2)(c) >= 102 then count += 1 if c + 2 < nCols && costs(r)(c) - costs(r)(c + 2) >= 102 then count += 1 if r + 2 < nRows && costs(r)(c) - costs(r + 2)(c) >= 102 then count += 1 if c - 2 > 0 && costs(r)(c) - costs(r)(c - 2) >= 102 then count += 1 i += 1 count def countCheats(r: Int, c: Int) = var count = 0 var cr = -20 while cr <= 20 do var cc = -(20 - cr) while cc <= (20 - cr) do val len = Math.abs(cr) + Math.abs(cc) if len <= 20 && 0 < r + cr && r + cr < nRows && 0 < c + cc && c + cc < nCols && costs(r)(c) - costs(r + cr)( c + cc) >= 100 + len then count += 1 cc += 1 cr += 1 count def part2 = ParRange(0, pr.length, 1, false).map(i => countCheats(pr(i), pc(i))).sum def main(args: Array[String]): Unit = println(part1) println(part2)

Dold text
PermalÀnk
Medlem
●
Skrivet av Ingetledigtnamn:

Körde pÄ jobbet för att ha AVX512. Testade pÄ bÄde Cascade Lake och Sapphire Rapids och den optimerade versionen kör pÄ ca 55-60% av körtiden för originalversion. Körtiden varierar lite, men förhÄllandet Àr ungeför samma.

Vet inte om det Àr vÀrt att försöka putsa det hÀr mer. Allting lÀr ÀndÄ drunkna i tiden för att lÀsa in filen.

Dold text

Kan vara sÄ att jag tolkar rapporten man fÄr av llm-mca pÄ godbolt helt fel eftersom det inte Àr ett verktyg jag brukar anvÀnda men det ser ut som att skillnaden jag fick i ökning faktiskt kan bero pÄ amd/intel. JÀmförde -mcpu=sapphirerapids / znver4/5. AMD verkar ha en riktigt bra implementation av AVX512 (om man rÀknar bort compress store). Inte orkat sÀtta mig in i exakta skillnaderna eftersom man ÀndÄ inte har sÄ mycket att sÀga till om instruktionsval pÄ JVM.

Parsningen Àr vÀl pÄ sÀtt och viss ett mer intressant "real world" problem. T.ex. om man fÄr batchar med rapporter i det formatet över nÀtverk och sÄ snabbt som möjligt behöver göra en berÀkning och fatta ett beslut. Gillar inte att skriva parsers sÄ det var mest ett försök till nerd sniping för att se om man kunde lÀra sig nÄgra tricks.

Dold text
PermalÀnk
Datavetare ★
●

Dag: 20
SprÄk: Rust

del 1+2: 1.2ms (M3), 7.5ms (Orange Pi 5)

use rayon::prelude::*; use std::{collections::VecDeque, fs::read_to_string}; pub const INPUT_FILE: &str = "input.txt"; type Vec2D = (i16, i16); pub fn read_map(path: &str) -> (Vec<u8>, usize, usize, Vec2D) { let content = read_to_string(path).expect("Failed to read the file"); let lines: Vec<&str> = content.split('\n').collect(); let mut map = Vec::new(); let mut end_pos = (0, 0); let border_thickness = 20; for (y, line) in lines.iter().enumerate() { for (x, ch) in line.chars().enumerate() { if ch == 'E' { end_pos = ((x + border_thickness) as i16, (y + border_thickness) as i16); } map.push(ch as u8); } } let width = lines[0].len(); ( add_border(map, width, border_thickness), width + 2 * border_thickness, border_thickness + 1, end_pos, ) } fn add_border(grid: Vec<u8>, width: usize, border_thickness: usize) -> Vec<u8> { let height = grid.len() / width; let new_width = width + 2 * border_thickness; let new_height = height + 2 * border_thickness; let mut bordered_grid = vec![b'#'; new_width * new_height]; for y in 0..height { for x in 0..width { bordered_grid[(y + border_thickness) * new_width + (x + border_thickness)] = grid[y * width + x]; } } bordered_grid } pub fn solve( map: &[u8], width: usize, border_thickness: usize, end_pos: Vec2D, min_save: i16, ) -> (u32, u32) { let mut steps_to_end = vec![i16::MAX; map.len()]; let mut queue = VecDeque::new(); let mut race_distance = 0; queue.push_front((end_pos, 0)); steps_to_end[end_pos.0 as usize + end_pos.1 as usize * width] = 0; while let Some(((x, y), steps)) = queue.pop_back() { let next_steps = steps + 1; for (dx, dy) in [(0, 1), (1, 0), (0, -1), (-1, 0)] { let next_pos = (x + dx, y + dy); let i = next_pos.0 as usize + next_pos.1 as usize * width; let tile = map[i]; if tile != b'#' && steps_to_end[i] > next_steps { steps_to_end[i] = next_steps; queue.push_front((next_pos, next_steps)); if tile == b'S' { race_distance = next_steps; } } } } (border_thickness..(map.len() / width - border_thickness)) .into_par_iter() // Parallel iteration over y-axis .map(|y| { let mut local_num_2_ps_cheats = 0; let mut local_num_20_ps_cheats = 0; for x in border_thickness..(width - border_thickness) { let steps_left = steps_to_end[x + y * width]; if steps_left > race_distance { continue; } for dy in -20..=20i16 { let max_dx = 20 - dy.abs(); for dx in -max_dx..=max_dx { let cheat_length = dy.abs() + dx.abs(); if cheat_length < 2 { continue; } let cheat_pos = (x as i16 + dx, y as i16 + dy); let i = cheat_pos.0 as usize + cheat_pos.1 as usize * width; let cheat_steps_left = steps_to_end[i]; if steps_left - cheat_steps_left >= min_save + cheat_length { local_num_20_ps_cheats += 1; if cheat_length == 2 { local_num_2_ps_cheats += 1; } } } } } (local_num_2_ps_cheats, local_num_20_ps_cheats) }) .reduce(|| (0, 0), |a, b| (a.0 + b.0, a.1 + b.1)) } fn main() { let (map, width, border_thickness, end_pos) = read_map(INPUT_FILE); let (num_2_ps_cheats, num_20_ps_cheats) = solve(&map, width, border_thickness, end_pos, 100); println!("part 1: {}", num_2_ps_cheats); println!("part 2: {}", num_20_ps_cheats); }

Dold text
Visa signatur

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

PermalÀnk
Medlem
●

Dag: 20 (2nd ed)
SprÄk: Scala

Nattens kod för dag 20 var inte tillrĂ€ckligt hemsk och olĂ€sbar sĂ„ jag gav mig pĂ„ ett försök att göra den Ă€nnu vĂ€rre eftersom jag inte orkade med beskrivningen för dag 21. Under 200ÎŒs nu iaf.

Ersatta parallell collections med en CountedCompleter för att slippa dependencies, lite mindre branching, bort med bounds checks, simd för inre loopen i del 2.

object Day20faster: val path = """20.txt""" val data = Using.resource(Source.fromFile(path))(_.getLines().map(_.toCharArray).toArray) val nRows = data.length val nCols = data(0).length def parse(data: Array[Array[Char]]) = var sr, sc, er, ec = 0 val pr = Array.newBuilder[Int] val pc = Array.newBuilder[Int] var r = 0 while r < nRows do var c = 0 while c < nCols do if data(r)(c) != '#' then pr += r + 20 pc += c + 20 if data(r)(c) == 'S' then sr = r sc = c if data(r)(c) == 'E' then er = r ec = c c += 1 r += 1 (sr, sc, er, ec, pr.result(), pc.result()) def calcCosts(data: Array[Array[Char]], fromRow: Int, fromCol: Int, toRow: Int, toCol: Int) = val costs = Array.fill(nRows + 40, nCols + 52)(Int.MaxValue) var cr = fromRow var cc = fromCol var n = 0 while cr != toRow || cc != toCol do costs(cr + 20)(cc + 20) = n data(cr)(cc) = '#' if data(cr - 1)(cc) != '#' then cr -= 1 else if data(cr)(cc + 1) != '#' then cc += 1 else if data(cr + 1)(cc) != '#' then cr += 1 else if data(cr)(cc - 1) != '#' then cc -= 1 n += 1 costs(cr + 20)(cc + 20) = n costs val (sr, sc, er, ec, pr, pc) = parse(data) val costs = calcCosts(data, sr, sc, er, ec) def part1 = var count = 0 var i = 0 while i < pr.length do val r = pr(i) val c = pc(i) count += (if costs(r)(c) - costs(r - 2)(c) >= 102 then 1 else 0) count += (if costs(r)(c) - costs(r)(c + 2) >= 102 then 1 else 0) count += (if costs(r)(c) - costs(r + 2)(c) >= 102 then 1 else 0) count += (if costs(r)(c) - costs(r)(c - 2) >= 102 then 1 else 0) i += 1 count private val isp = IntVector.SPECIES_512 private val offsets = Array.tabulate(48)(x => Math.abs(x - 20)) private val ov0 = IntVector.fromArray(isp, offsets, 0) private val ov1 = IntVector.fromArray(isp, offsets, 16) private val ov2 = IntVector.fromArray(isp, offsets, 32) def countCheats(r: Int, c: Int) = val cv = IntVector.broadcast(isp, costs(r)(c)) var acc = IntVector.broadcast(isp, 0) var cr = -20 while cr <= 20 do val absCr = Math.abs(cr) val lv0 = ov0.add(absCr) val m0 = cv.sub(IntVector.fromArray(isp, costs(r + cr), c - 20)).compare(GE, lv0.add(100)).and(lv0.compare(LE, 20)) acc = acc.add(1, m0) val lv1 = ov1.add(absCr) val m1 = cv.sub(IntVector.fromArray(isp, costs(r + cr), c - 4)).compare(GE, lv1.add(100)).and(lv1.compare(LE, 20)) acc = acc.add(1, m1) val lv2 = ov2.add(absCr) val m2 = cv.sub(IntVector.fromArray(isp, costs(r + cr), c + 12)).compare(GE, lv2.add(100)).and(lv2.compare(LE, 20)) acc = acc.add(1, m2) cr += 1 acc.reduceLanes(ADD) final class Part2 private (parent: Part2 | Null, lo: Int, hi: Int, pending: Int) extends CountedCompleter[Int](parent, pending): def this() = this(null, 0, pr.length, Part2.initialLeaves(pr.length)) private final val subs = Array.ofDim[Part2](pending) private var res = 0 def compute(): Unit = var pend = pending var n = hi - lo while pend > 0 do val half = n >>> 1 pend -= 1 val sub = Part2(this, lo + half, lo + n, pend) subs(pend) = sub sub.fork() n = half var i = lo while i < lo + n do res += countCheats(pr(i), pc(i)) i += 1 tryComplete() override def onCompletion(caller: CountedCompleter[?]): Unit = var i = 0 while i < subs.length do res += subs(i).res i += 1 override def getRawResult: Int = res object Part2: private final val TargetLeaves = Runtime.getRuntime.availableProcessors() << 2 private final val MinSizeLeaves = 1000 private def initialLeaves(size: Int): Int = val leaves = TargetLeaves min (size / MinSizeLeaves) if leaves == 0 then 0 else 31 - Integer.numberOfLeadingZeros(leaves) def part2 = Part2().invoke() def main(args: Array[String]): Unit = println(part1) println(part2)

Dold text
PermalÀnk
Medlem ★
●

Första gÄngen jag skriver hÀr, men wow, dagens var en utmaning. Nog min favorit hittills ocksÄ. Jag skriver i C# i Är, sÄ hÄll till godo om nÄn Àr nyfiken. Vill vÀldigt gÀrna se andras lösningar ocksÄ, dela med er!

Dag: 21
SprÄk: C#
Lösning: GitHub
Körtid del 2: 33ms

Visa signatur

Louqe Ghost S1 MK3 | Asus ROG Strix B660-I Gaming WiFi | Intel Core i7 12700K | nVidia RTX 2070 Super FE | Corsair 64GB (2x32GB) DDR5 5600MHz CL40 Vengeance | Samsung 980 PRO M.2 NVMe SSD 2TB | Corsair SF750 750W 80+ Platinum | Noctua NH-L12 Ghost S1 edition | Kablar frÄn pslate customs | 2 stk Dell Ultrasharp 3014 | Logitech MX Keys | Logitech MX Anywhere

PermalÀnk
Medlem ★
●

Dag: 21
SprÄk: Python

Oboy, i dag körde jag i diket ordentligt. Det tog tid att hitta en elegant lösning i dag...

from itertools import pairwise order = "0123456789A^v<>" pad = [ ['A' , '^<A' , '^A' , '^>A' , '^^<A' , '^^A' , '>^^A' , '^^^<A' , '^^^A' , '^^^>A' , '>A' , '' , '' , '' , '' ], # 0 ['>vA' , 'A' , '>A' , '>>A' , '^A' , '^>A' , '^>>A' , '^^A' , '^^>A' , '^^>>A' , '>>vA' , '' , '' , '' , '' ], # 1 ['vA' , '<A' , 'A' , '>A' , '^<A' , '^A' , '^>A' , '^^<A' , '^^A' , '^^>A' , 'v>A' , '' , '' , '' , '' ], # 2 ['v<A' , '<<A' , '<A' , 'A' , '^<<A' , '^<A' , '^A' , '<<^^A' , '<^^A' , '^^A' , 'vA' , '' , '' , '' , '' ], # 3 ['>vvA' , 'vA' , 'v>A' , 'v>>A' , 'A' , '>A' , '>>A' , '^A' , '^>A' , '^>>A' , '>>vvA' , '' , '' , '' , '' ], # 4 ['vvA' , 'v<A' , 'vA' , 'v>A' , '<A' , 'A' , '>A' , '^<A' , '^A' , '^>A' , 'vv>A' , '' , '' , '' , '' ], # 5 ['<vvA' , 'v<<A' , 'v<A' , 'vA' , '<<A' , '<A' , 'A' , '^<<A' , '^<A' , '^A' , 'vvA' , '' , '' , '' , '' ], # 6 ['>vvvA' , 'vvA' , 'vv>A' , 'vv>>A' , 'vA' , 'v>A' , 'v>>A' , 'A' , '>A' , '>>A' , '>>vvvA', '' , '' , '' , '' ], # 7 ['vvvA' , 'vv<A' , 'vvA' , 'vv>A' , 'v<A' , 'vA' , 'v>A' , '<A' , 'A' , '>A' , 'vvv>A' , '' , '' , '' , '' ], # 8 ['vvv<A' , '<<vvA' , 'vv<A' , 'vvA' , 'v<<A' , 'v<A' , 'vA' , '<<A' , '<A' , 'A' , 'vvvA' , '' , '' , '' , '' ], # 9 ['<A' , '^<<A' , '^<A' , '^A' , '^^<<A' , '^^<A' , '^^A' , '^^^<<A', '<^^^A' , '^^^A' , 'A' , '<A' , '<vA' , 'v<<A' , 'vA' ], # A ['' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '>A' , 'A' , 'vA' , 'v<A' , 'v>A' ], # ^ ['' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '^>A' , '^A' , 'A' , '<A' , '>A' ], # v ['' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '>>^A' , '>^A' , '>A' , 'A' , '>>A' ], # < ['' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '^A' , '<^A' , '<A' , '<<A' , 'A' ], # > ] def expand2(s, depth, memo = {}): if depth < 0: return len(s) if (t := (s, depth)) in memo: return memo[t] memo[t] = sum(expand2(pad[order.index(a)][order.index(b)], depth - 1) for a, b in pairwise("A" + s)) return memo[t] print(*[sum(expand2(l, d) * int(l[:-1]) for l in open("input21.txt").read().splitlines()) for d in [2, 25]])

Dold text
PermalÀnk
Medlem ★
●

Dag 21 Del 1 (WIP) | SprÄk: HTML+CSS+JS

Dag: 21 Del 1 (WORK IN PROGRESS, dvs., ej klar Ànnu - se spoilerbild nedan)
SprÄk: HTML-fil med CSS & JS inbakat i filen.

Jag blev lite smÄtt sugen trots allt och tÀnkte att jag kan nog lösa den genom att faktiskt tillÄta mig sjÀlv fÄ simulera knapptryckandet:

Bilden ovan visar hur jag nu i första steget kunna matat in i exakt samma följd som i beskrivningen. Notera dock att de markerade knapparna för Robot 1 och Robot 2 ej har rört sig Ànnu.

Nu ska jag fÄ till sÄ att vad jag egentligen styr Àr robot 1 som sedan styr robot 2 och som i sin tur styr knapparna i den stora knappsatsen vilket nu styrs av "USER NAVIGATION".

Snacka om "over-engineered"-lösning men skoj med lite sidoprojekt eller vad man ska sÀga sÄ hÀr dags innan Julafton!

Dold text

FrÄga jag har sÄ att jag tolkat Dag 21 Del 1 korrekt nu:

Tanken Àr att nÀr jag trycker pÄ en knapp sÄ registreras den, exempelvis LEFT (<) och detta ska dÄ flytta första roboten (Robot 1) till "UP"-knappen och nÀr jag sedan trycker pÄ "A" i min "USER NAVIGATION" sÄ kommer ROBOT 1 att trycka pÄ "UP" vilket försöker föra upp markören för Robot 2 vilket kommer misslyckas eftersom det Àr utanför knappsatsen i robot 2:s fall?

AlltsÄ:

Jag trycker nÄgot men inte "A" -> flytt markör hos Robot 1.
Jag trycker "A" -> tryck pÄ knappsats hos Robot 1 -> flytta markör hos Robot 2.
Jag trycker "A" -> och den trycker pÄ "A" hos Robot 1 -> tryck pÄ knappats hos Robot 2.

Och knapptryck som ska lagras (se mellersta grÄrutan frÄn bilden) Àr nÀr jag trycker pÄ min knappsats och nÀr en knappsats registrerats i Robot 1 via min "A"-knapptryck frÄn min knappsats och nÀr "A"-knapptryck registreras hos Robot 1:s "A"-knapptryck tack vare mitt "A"-knapptryck och samma veva för nÀr "A"-knapptryck skedde via mitt "A" -> Robot 1:s "A" -> Robot 2:s knapptryck dÀr markören stÄr?

Det Àr just alla dessa knapptryckssteg som fick mig att vilja visualisera lösningen istÀllet för abstrakt bara koda den!

Dold text

Mvh,
WKF.

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

PermalÀnk
Medlem ★
●

Dag: 22
SprÄk: Python

from collections import Counter from functools import reduce def secret_number(sn): sn = ((sn << 6) ^ sn) & 0xffffff sn = ((sn >> 5) ^ sn) sn = ((sn << 11) ^ sn) & 0xffffff return sn def part1(numbers): def run(sn): for i in range(2000): sn = secret_number(sn) return sn return sum(run(int(sn)) for sn in numbers) def part2(numbers): def find_sequences(sn): sequences, diffs = Counter(), [99,99,99,99] last_price = sn % 10 for i in range(2000): sn = secret_number(sn) price = sn % 10 diff = price - last_price diffs = (diffs + [diff])[-4:] if tuple(diffs) not in sequences and 99 not in diffs: sequences[tuple(diffs)] = price last_price = price return sequences return reduce(lambda x, y: x + y, [find_sequences(sn) for sn in numbers]).most_common(1) numbers = [int(l) for l in open("input22.txt").read().splitlines()] print(part1(numbers), part2(numbers))

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

Det Àr just alla dessa knapptryckssteg som fick mig att vilja visualisera lösningen istÀllet för abstrakt bara koda den!

Dold text

Kul att du fortfarande hÀnger med och kollar pÄ uppgifterna, men var beredd pÄ att den hÀr var ganska knepig. Av egen erfarenhet kan jag sÀga att det Àr bra att tÀnka efter innan man kastar sig in i kodningen av denna uppgift

Ja, jag tror du fattat saker rÀtt. Att trycka pÄ "A" ger ett knapptryck pÄ "nÀsta" nivÄs tangentbord.

Min postade lösning Àr i stort sett samma lösning som mitt första försök, men den gav jag upp pÄ nÀr den fick fel svar pÄ det sista av exemplen (379A). Sedan gick jag vilse i allt krÄngligare lösningar.

Att mitt första försök inte fungerade visade sig bero pÄ att knappar som har olika vÀgar mellan sig, exempelvis 3 och 7, kommer att resultera i olika lÄnga knapptryckningssekvenser nÀr man kommer till andra roboten, beroende pÄ vilken vÀg man gick. Se till att vÀlja rÀtt om du hÄrdkodar saker...

Försök inte att expandera alla möjliga teckenstrÀngar som sekvensen 379A kan producera för att vÀlja ut den kortaste. Se till att bryta ner det i mindre bitar sÄ att du fÄr fÀrre kombinationer att hantera.

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

Kul att du fortfarande hÀnger med och kollar pÄ uppgifterna, men var beredd pÄ att den hÀr var ganska knepig. Av egen erfarenhet kan jag sÀga att det Àr bra att tÀnka efter innan man kastar sig in i kodningen av denna uppgift

Ja, jag tror du fattat saker rÀtt. Att trycka pÄ "A" ger ett knapptryck pÄ "nÀsta" nivÄs tangentbord.

Min postade lösning Àr i stort sett samma lösning som mitt första försök, men den gav jag upp pÄ nÀr den fick fel svar pÄ det sista av exemplen (379A). Sedan gick jag vilse i allt krÄngligare lösningar.

Att mitt första försök inte fungerade visade sig bero pÄ att knappar som har olika vÀgar mellan sig, exempelvis 3 och 7, kommer att resultera i olika lÄnga knapptryckningssekvenser nÀr man kommer till andra roboten, beroende pÄ vilken vÀg man gick. Se till att vÀlja rÀtt om du hÄrdkodar saker...

Försök inte att expandera alla möjliga teckenstrÀngar som sekvensen 379A kan producera för att vÀlja ut den kortaste. Se till att bryta ner det i mindre bitar sÄ att du fÄr fÀrre kombinationer att hantera.

Dold text

Tjo igen!

Jag har nu kommit vidare sÄ att nÀr jag trycker pÄ UP, DOWN, LEFT, RIGHT eller A pÄ tangentbordet sÄ registreras knapptryck. Jag antar att det Àr bara dessa som spelar roll.

Jag kan nu navigera för ROBOT 1 och sedan kan jag trycka pÄ "A" som USER vilket dÄ trycker pÄ samma slags knappsats för ROBOT 1 för att förflytta sig i knappsatsen för ROBOT 2 (se min tidigare bild).

Och det Àr Robot 2 som ska röra den faktiska numerÀra knappsatsen? Och nÀr Robot 1 dÄ trycker pÄ "A" i sin knappsats sÄ betyder det att en knapp i Robot 2 ska tryckas vilket dÄ antingen kommer lyckas eller inte att röra sig inuti numerÀra knappsatsen och/eller trycka pÄ en knapp dÀr?

SÄ lÀnge USER:s knapptryck Àr giltiga hela vÀgen (dvs., kan röra sig i Robot 1 -> som kan röra sig i Robot 2 -> som kan röra sig i NumerÀra knappsatsen) sÄ ska det rÀknas som ett knapptryck av slaget <,>,^,v eller A?

Dold text

Som sagt var kommer min Dag 21 Del 1 lösning att vara "spelbar" i ens webblÀsare sÄ lösningen ska gÄ att spela fram. FÄr se hur lÄngt det gÄr. Kan jag replikera likt exemplen sÄ bör det nog gÄ vÀgen.

I princip kommer du att kunna trycka dig fram och den nekar att rÀkna in ogiltiga knapptryck sÄ kanske jag (och andra) kan "spela" oss fram till lösningen!

I skrivande stund gÄr det nu Àntligen att "navigera" via alla led frÄn en och samma "navigeringsmeny"!

Dold text

Mvh,
WKF.

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

PermalÀnk
Medlem ★
●

Dag 21 Del 1 (PoC) | SprÄk: HTML+CSS+JS

Dag 21 Del 1 (Proof-of-Concept - dvs., exempeldatan ger exakt rÀtt resultat sÄ nu ska jag manuellt "spela" igenom rÀtt - Du kan ocksÄ prova!)
SprÄk: HTML-fil med CSS & JS inbakat i filen.

21.html - Dag 21 Del 1 endast utan kommentarer.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Advent of Code Day 21 - WebbkodsFrilansaren ©2024</title> </head> <style> .pressedNumpadKeys, .countPressedKeys { display: flex; justify-content: center; align-items: center; height: 50px; width: 300px; background-color: #f0f0f0; border-radius: 5px; word-break: break-all; } .pressedKeys { display: flex; justify-content: center; align-items: center; height: 50px; background-color: #f0f0f0; border-radius: 5px; width: 300px; height: 300px; padding: 10px; margin-top: 20px; word-break: break-all; } .numpad { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; width: 200px; margin-top: 20px; } .numpad > div { display: flex; justify-content: center; align-items: center; height: 50px; background-color: #f0f0f0; border-radius: 5px; } .keysToCalculate { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 10px; background-color: #f0f0f0; border-radius: 5px; margin-top: 20px; word-break: break-all; } .numpad div:nth-child(10) { grid-column: 2; } .numpad div:nth-child(11) { grid-column: 3; } .currentlyHoveringRobot1Key, .currentlyHoveringRobot2Key, .currentlyHoveringNumpadKey { border: 3px solid black; } .directionalpad_user { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; width: 200px; margin: 0 auto; margin-top: 10px; } #UP_USER, #UP_ROBOT1, #UP_ROBOT2 { grid-column: 2; grid-row: 1; } #A_USER, #A_ROBOT1, #A_ROBOT2 { grid-column: 3; grid-row: 1; } #LEFT_USER, #LEFT_ROBOT1, #LEFT_ROBOT2 { grid-column: 1; grid-row: 2; } #DOWN_USER, #DOWN_ROBOT1, #DOWN_ROBOT2 { grid-column: 2; grid-row: 2; } #RIGHT_USER, #RIGHT_ROBOT1, #RIGHT_ROBOT2 { grid-column: 3; grid-row: 2; } .userpad { display: flex; justify-content: center; align-items: center; height: 50px; width: 200px; background-color: #f0f0f0; border-radius: 5px; margin: 0 auto; margin-top: 20px; word-break: break-all; } .row2 { display: flex; justify-content: center; gap: 20px; margin: 0 auto; } .row3 { display: flex; justify-content: center; gap: 20px; margin: 0 auto; } </style> <script> function addPressedNumpadKeys(key) { const pressedNumpadKeys = document.querySelector(".pressedNumpadKeys"); pressedNumpadKeys.textContent += key; } function increaseValidKeyPresses(key) { const pressedKeys = document.querySelector(".pressedKeys"); const countPressedKeys = document.querySelector(".countPressedKeys"); const keyToDisplay = { UP: "^", DOWN: "v", LEFT: "<", RIGHT: ">", A: "A", }; pressedKeys.textContent += keyToDisplay[key]; countPressedKeys.textContent = "Keys Pressed: " + pressedKeys.textContent.length; } function animateKeyPress(key, color) { const keyElement = document.getElementById(key); keyElement.style.backgroundColor = color; setTimeout(() => { keyElement.style.backgroundColor = "#f0f0f0"; }, 100); } function handleAPressRobot1() { const pressedNavigationkeyForRobot1 = document.querySelector( ".currentlyHoveringRobot1Key" ); const currentlyHoveringRobot2Key = document.querySelector( ".currentlyHoveringRobot2Key" ); const [buttonId] = pressedNavigationkeyForRobot1.id.split("_"); console.log("Button ID (Robot 1): " + buttonId); if (buttonId == "A") { if (handleAPressRobot2()) { return true; } else { return false; } } if (moveRobotKey(currentlyHoveringRobot2Key, buttonId, "2")) { console.log(`VALID ${buttonId} Press From User to Robot 1 to Robot 2`); animateKeyPress(`${buttonId}_ROBOT1`, "green"); return true; } console.log(`INVALID ${buttonId} Press From User to Robot 1 to Robot 2`); animateKeyPress(`${buttonId}_ROBOT1`, "red"); return false; } function handleAPressRobot2() { const pressedNavigationkeyForRobot2 = document.querySelector( ".currentlyHoveringRobot2Key" ); const currentSelectedNumpadKey = document.querySelector( ".currentlyHoveringNumpadKey" ); const [robotButtonId] = pressedNavigationkeyForRobot2.id.split("_"); console.log("Button ID (Robot 2): " + robotButtonId); if (robotButtonId == "A") { console.log("A button pressed from USER To Robot 1 To Robot 2"); animateKeyPress("A_ROBOT2", "green"); addPressedNumpadKeys(currentSelectedNumpadKey.textContent.trim()); return true; } if (moveNumpadKey(currentSelectedNumpadKey, robotButtonId)) { console.log(`VALID ${robotButtonId} Press From User to Robot 2`); animateKeyPress(`${robotButtonId}_ROBOT2`, "green"); return true; } else { console.log(`INVALID ${robotButtonId} Press From User to Robot 2`); return false; } } function moveRobotKey(currentSelectedRobotKey, direction, robotnumber) { const currentCoords = currentSelectedRobotKey.getAttribute( "data-coords-robot" + robotnumber ); let newCoords = ""; let [x, y] = currentCoords.split(",").map(Number); if (direction == "UP") { y = y - 1; } else if (direction == "DOWN") { y = y + 1; } else if (direction == "LEFT") { x = x - 1; } else if (direction == "RIGHT") { x = x + 1; } newCoords = `${x},${y}`; const newRobotKey = document.querySelector( `[data-coords-robot${robotnumber}="${newCoords}"]` ); if (newRobotKey) { currentSelectedRobotKey.classList.remove( `currentlyHoveringRobot${robotnumber}Key` ); newRobotKey.classList.add(`currentlyHoveringRobot${robotnumber}Key`); console.log(`VALID KEY MOVE (ON ROBOT ${robotnumber} FROM USER)`); return true; } console.log(`INVALID KEY MOVE (ON ROBOT ${robotnumber} FROM USER)`); return false; } function moveNumpadKey(currentSelectedNumpadKey, direction) { const currentCoords = currentSelectedNumpadKey.getAttribute("data-coords"); let newCoords = ""; let [x, y] = currentCoords.split(",").map(Number); if (direction == "UP") { y = y - 1; } else if (direction == "DOWN") { y = y + 1; } else if (direction == "LEFT") { x = x - 1; } else if (direction == "RIGHT") { x = x + 1; } newCoords = `${x},${y}`; const newNumpadKey = document.querySelector( `[data-coords="${newCoords}"]` ); if (newNumpadKey) { currentSelectedNumpadKey.classList.remove("currentlyHoveringNumpadKey"); newNumpadKey.classList.add("currentlyHoveringNumpadKey"); console.log("VALID KEY MOVE (ON NUMPAD FROM ROBOT 2)"); return true; } console.log("INVALID KEY MOVE (ON NUMPAD FROM ROBOT 2)"); return false; } document.addEventListener("DOMContentLoaded", () => { document.addEventListener("keydown", (event) => { if (event.key === "ArrowUp") { event.preventDefault(); if ( moveRobotKey( document.querySelector(".currentlyHoveringRobot1Key"), "UP", 1 ) ) { console.log("UP pressed from ROBOT 1"); animateKeyPress("UP_USER", "green"); increaseValidKeyPresses("UP"); } else { animateKeyPress("UP_USER", "red"); } } else if (event.key === "ArrowDown") { event.preventDefault(); if ( moveRobotKey( document.querySelector(".currentlyHoveringRobot1Key"), "DOWN", 1 ) ) { console.log("DOWN pressed from ROBOT 1"); animateKeyPress("DOWN_USER", "green"); increaseValidKeyPresses("DOWN"); } else { animateKeyPress("DOWN_USER", "red"); } } else if (event.key === "ArrowLeft") { event.preventDefault(); if ( moveRobotKey( document.querySelector(".currentlyHoveringRobot1Key"), "LEFT", 1 ) ) { console.log("LEFT pressed from ROBOT 1"); animateKeyPress("LEFT_USER", "green"); increaseValidKeyPresses("LEFT"); } else { animateKeyPress("LEFT_USER", "red"); } } // IF KEY IS RIGHT from USER else if (event.key === "ArrowRight") { event.preventDefault(); if ( moveRobotKey( document.querySelector(".currentlyHoveringRobot1Key"), "RIGHT", 1 ) ) { console.log("RIGHT pressed from ROBOT 1"); animateKeyPress("RIGHT_USER", "green"); increaseValidKeyPresses("RIGHT"); } else { animateKeyPress("RIGHT_USER", "red"); } } else if (event.key === "a") { event.preventDefault(); if (handleAPressRobot1()) { animateKeyPress("A_USER", "green"); console.log("A button pressed from USER To Robot 1"); increaseValidKeyPresses("A"); } else { animateKeyPress("A_USER", "red"); console.log("INVALID A Press From User to Robot 1"); } } }); const listenBtnClicks = document.getElementById("listenBtnClicks"); listenBtnClicks.addEventListener("click", (event) => { if ( event.target.tagName === "BUTTON" && event.target.id.includes("calc") ) { const buttonId = event.target.id; const sequence = document.getElementById( buttonId.replace("calc", "seq") ); const result = document.getElementById( buttonId.replace("calc", "result") ); const pressedKeys = parseInt( document .querySelector(".countPressedKeys") .textContent.split(": ")[1] ); const numbers = parseInt(sequence.textContent); result.textContent = `Result: ${pressedKeys * numbers}`; } else if ( event.target.tagName === "BUTTON" && event.target.id.includes("totalsum") ) { const results = document.querySelectorAll( ".keysToCalculate p[id^='result']" ); const total = document.getElementById("total"); let sum = 0; results.forEach((result) => { sum += parseInt(result.textContent.split(": ")[1]); }); total.textContent = `Total: ${sum}`; } }); document.getElementById("reset").addEventListener("click", () => { document.querySelector(".pressedKeys").textContent = ""; document.querySelector(".countPressedKeys").textContent = "Keys Pressed:"; document.querySelector(".pressedNumpadKeys").textContent = "Numpad Keys Pressed:"; document .querySelector(".currentlyHoveringNumpadKey") .classList.remove("currentlyHoveringNumpadKey"); document .querySelector(".currentlyHoveringRobot1Key") .classList.remove("currentlyHoveringRobot1Key"); document .querySelector(".currentlyHoveringRobot2Key") .classList.remove("currentlyHoveringRobot2Key"); document .querySelector("#A_NUMPAD") .classList.add("currentlyHoveringNumpadKey"); document .querySelector("#A_ROBOT1") .classList.add("currentlyHoveringRobot1Key"); document .querySelector("#A_ROBOT2") .classList.add("currentlyHoveringRobot2Key"); }); }); document.addEventListener("paste", (event) => { event.preventDefault(); const text = event.clipboardData.getData("text"); for (let i = 0; i < text.length; i++) { if (text[i] === "<") { document.dispatchEvent( new KeyboardEvent("keydown", { key: "ArrowLeft" }) ); } else if (text[i] === ">") { document.dispatchEvent( new KeyboardEvent("keydown", { key: "ArrowRight" }) ); } else if (text[i] === "^") { document.dispatchEvent( new KeyboardEvent("keydown", { key: "ArrowUp" }) ); } else if (text[i] === "v") { document.dispatchEvent( new KeyboardEvent("keydown", { key: "ArrowDown" }) ); } else if (text[i] === "A") { document.dispatchEvent(new KeyboardEvent("keydown", { key: "a" })); } } const pressedKeys = parseInt( document.querySelector(".countPressedKeys").textContent.split(": ")[1] ); const pressedNumpadKeys = parseInt( document.querySelector(".pressedNumpadKeys").textContent.split(":")[1] ); alert( `Result (SAVE THIS TO SUM MANUALLY!): ${pressedKeys} * ${pressedNumpadKeys} = ${ pressedKeys * pressedNumpadKeys }` ); }); </script> <body> <div class="row2"> <button id="reset">RESET All Except Multiplied Sums</button> <div class="countPressedKeys">Keys Pressed:</div> <div class="pressedNumpadKeys">Numpad Keys Pressed:</div> </div> <div class="row2"> <div class="numpad"> <div id="7" data-coords="0,0">7</div> <div id="8" data-coords="1,0">8</div> <div id="9" data-coords="2,0">9</div> <div id="4" data-coords="0,1">4</div> <div id="5" data-coords="1,1">5</div> <div id="6" data-coords="2,1">6</div> <div id="1" data-coords="0,2">1</div> <div id="2" data-coords="1,2">2</div> <div id="3" data-coords="2,2">3</div> <div id="0" data-coords="1,3">0</div> <div id="A_NUMPAD" class="currentlyHoveringNumpadKey" data-coords="2,3"> A </div> </div> <div class="pressedKeys"></div> </div> <div class="row3"> <div> <div class="userpad">USER NAVIGATION</div> <div class="directionalpad_user"> <button id="UP_USER">UP</button> <button id="A_USER">A</button> <button id="DOWN_USER">DOWN</button> <button id="LEFT_USER">LEFT</button> <button id="RIGHT_USER">RIGHT</button> </div> </div> <div> <div class="userpad">ROBOT 1</div> <div class="directionalpad_user"> <button id="UP_ROBOT1" data-coords-robot1="1,0">UP</button> <button id="A_ROBOT1" class="currentlyHoveringRobot1Key" data-coords-robot1="2,0"> A </button> <button id="DOWN_ROBOT1" data-coords-robot1="1,1">DOWN</button> <button id="LEFT_ROBOT1" data-coords-robot1="0,1">LEFT</button> <button id="RIGHT_ROBOT1" data-coords-robot1="2,1">RIGHT</button> </div> </div> <div> <div class="userpad">ROBOT 2</div> <div class="directionalpad_user"> <button id="UP_ROBOT2" data-coords-robot2="1,0">UP</button> <button id="A_ROBOT2" class="currentlyHoveringRobot2Key" data-coords-robot2="2,0"> A </button> <button id="DOWN_ROBOT2" data-coords-robot2="1,1">DOWN</button> <button id="LEFT_ROBOT2" data-coords-robot2="0,1">LEFT</button> <button id="RIGHT_ROBOT2" data-coords-robot2="2,1">RIGHT</button> </div> </div> </div> <div id="listenBtnClicks" class="row3" style="flex-wrap: wrap; width: 600px"> <div class="keysToCalculate"> <p id="seq1">286A</p> <button id="calc1">Multiply Pressed with Sum</button> <p id="result1"></p> </div> <div class="keysToCalculate"> <p id="seq2">480A</p> <button id="calc2">Multiply Pressed with Sum</button> <p id="result2"></p> </div> <div class="keysToCalculate"> <p id="seq3">140A</p> <button id="calc3">Multiply Pressed with Sum</button> <p id="result3"></p> </div> <div class="keysToCalculate"> <p id="seq4">413A</p> <button id="calc4">Multiply Pressed with Sum</button> <p id="result4"></p> </div> <div class="keysToCalculate"> <p id="seq5">964A</p> <button id="calc5">Multiply Pressed with Sum</button> <p id="result5"></p> </div> <div class="keysToCalculate"> <p id="totalseq">TOTAL SUM</p> <button id="totalsum">SUM ALL RESULTS</button> <p id="total"></p> </div> </div> </body> </html>

Dold text

Nu ska jag alltsÄ manuellt anvÀnda "styrningen". Alla testexempel fungerar om du vill bara copy & pastea direkt inuti HTML-filen sÄ kör den igenom allt automatiskt och ger dig rÀtt enligt testexemplen. Upp till bevis nu!

Se bilder i spoilers som rÀknar rÀtt med testdata (jag har redan provat all testdata och det fungerar):

Dold text

EDIT: Viktigt! Reset-funktionen ÄterstÀller inte en viss placering vilket gör att copy&pastea av testexemplen blir felaktiga sÄ dÄ mÄste hela webbsidan laddas om. Nu hÄller jag pÄ med första av fem i inmatningsdatan - manuellt!
EDIT2: Möjligen Àr Reset-funktionen fixad för manullt "spelande" av Dag 21 Del 1 nu.

Mvh,
WKF.

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

PermalÀnk
Medlem ★
●

Dag 21 Del 1 (PoC -> Success?!) | SprÄk: HTML+CSS+JS
FrÄga: NÄgon som kan kolla i första inmatningsfÀltet för Dag 21 Del 1 om Du fick samma slutvÀrde sÄ att jag vet att jag manuellt gjorde rÀtt? Annars sÄ inser jag att jag "manuellt" inte kommer att kunna "spela" fram till rÀtt resultat i denna och dÄ var det roligt sÄ lÀnge det vara!

Paste-hÀndelsen (ersÀtt hela det kodblocket i tidigare massiva kodblock) har nu animering (50 ms fördröjning) sÄ kan Ätminstone nÄgonting se "coolt" ut!

document.addEventListener("paste", (event) => { event.preventDefault(); const text = event.clipboardData.getData("text"); const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); sendKeystrokesWithDelay(text); async function sendKeystrokesWithDelay(text) { for (let i = 0; i < text.length; i++) { if (text[i] === "<") { document.dispatchEvent( new KeyboardEvent("keydown", { key: "ArrowLeft" }) ); } else if (text[i] === ">") { document.dispatchEvent( new KeyboardEvent("keydown", { key: "ArrowRight" }) ); } else if (text[i] === "^") { document.dispatchEvent( new KeyboardEvent("keydown", { key: "ArrowUp" }) ); } else if (text[i] === "v") { document.dispatchEvent( new KeyboardEvent("keydown", { key: "ArrowDown" }) ); } else if (text[i] === "A") { document.dispatchEvent(new KeyboardEvent("keydown", { key: "a" })); } await delay(50); } const pressedKeys = parseInt( document.querySelector(".countPressedKeys").textContent.split(": ")[1] ); const pressedNumpadKeys = parseInt( document.querySelector(".pressedNumpadKeys").textContent.split(":")[1] ); alert( `Result (SAVE THIS TO SUM MANUALLY!): ${pressedKeys} * ${pressedNumpadKeys} = ${ pressedKeys * pressedNumpadKeys }` ); } });

Dold text

Jag har nu provkört mitt eget Proof-of-concept:

286A
Jag har manuellt tryckt in dessa i 21.html-filen i webblÀsaren och sedan sparade jag dem sÄ att jag kunde fortsÀtta frÄn lyckat nummer om jag tryckte fel (via Copy&paste-funktionen):

2 = <v<A>^>A<vA<A>^>AvAA^<A>A (25 presses)
28 = <v<A>^>A<vA<A>^>AvAA^<A>A<v<A>^>AAvA^A (38 presses)
286 = <v<A>^>A<vA<A>^>AvAA^<A>A<v<A>^>AAvA^A<vA<A>^>AvA^A<A>A (55 presses)
286A = <v<A>^>A<vA<A>^>AvAA^<A>A<v<A>^>AAvA^A<vA<A>^>AvA^A<A>A<v<A>A^>AA<A>vA^A (72 presses)

72*286 = 20592

Det vill sÀga, stÀmmer det att kortaste sekvensen för 286A Àr 72 eller Àr det fÀrre?

Dold text

Mvh,
WKF.

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

PermalÀnk
Medlem ★
●
Skrivet av WebbkodsFrilansaren:

EDIT: Viktigt! Reset-funktionen ÄterstÀller inte en viss placering vilket gör att copy&pastea av testexemplen blir felaktiga sÄ dÄ mÄste hela webbsidan laddas om. Nu hÄller jag pÄ med första av fem i inmatningsdatan - manuellt!

Du fÄr pluspoÀng för att du löst detta, men problemstÀllningen var ju Ät andra hÄllet, sÄ att sÀga. Du skall alltsÄ hitta den kortaste sekvens av knapptryckingar pÄ "user" som matar in en given kod pÄ det numeriska tangentbordet. Kanske inte helt lÀmpat för manuellt experimenterande.

Du borde nog angripa problemet frÄn input-strÀngen och vilka tryckningar som krÀvs pÄ första robotens tangentbord för att

  1. flytta frÄn A (startposition) till 0, trycka pÄ knappen

  2. flytta frÄn 0 till 2, trycka pÄ knappen

  3. flytta frÄn 2 till 9, trycka pÄ knappen

  4. flytta frÄn 9 till A, trycka pÄ knappen

och sedan vilka tryckningar som krÀvs pÄ den andra robotens tangentbord för att Ästadkomma den första robotens knapptryck...

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

Du fÄr pluspoÀng för att du löst detta, men problemstÀllningen var ju Ät andra hÄllet, sÄ att sÀga. Du skall alltsÄ hitta den kortaste sekvens av knapptryckingar pÄ "user" som matar in en given kod pÄ det numeriska tangentbordet. Kanske inte helt lÀmpat för manuellt experimenterande.

Du borde nog angripa problemet frÄn input-strÀngen och vilka tryckningar som krÀvs pÄ första robotens tangentbord för att

  1. flytta frÄn A (startposition) till 0, trycka pÄ knappen

  2. flytta frÄn 0 till 2, trycka pÄ knappen

  3. flytta frÄn 2 till 9, trycka pÄ knappen

  4. flytta frÄn 9 till A, trycka pÄ knappen

och sedan vilka tryckningar som krÀvs pÄ den andra robotens tangentbord för att Ästadkomma den första robotens knapptryck...

Dold text

AngÄende Dag 21 Del 1:

Detta Àr vad jag "manuellt" fick fram för antal knapptryck genom att "spela". DessvÀrre gav det för högt slutresultat enligt Dag 21 Del 1:

286A 2 = <v<A>^>A<vA<A>^>AvAA^<A>A (25 presses) 28 = <v<A>^>A<vA<A>^>AvAA^<A>A<v<A>^>AAvA^A (38 presses) 286 = <v<A>^>A<vA<A>^>AvAA^<A>A<v<A>^>AAvA^A<vA<A>^>AvA^A<A>A (55 presses) 286A = <v<A>^>A<vA<A>^>AvAA^<A>A<v<A>^>AAvA^A<vA<A>^>AvA^A<A>A<v<A>A^>AA<A>vA^A (72 presses) 72*286 = 20592 480A 4 = <v<A>^>AA<vA<A>^>AAvAA^<A>A (27 presses) 48 <v<A>^>AA<vA<A>^>AAvAA^<A>A<v<A>^>AvA<A^>A<A>A (46 presses) 480 = <v<A>^>AA<vA<A>^>AAvAA^<A>A<v<A>^>AvA<A^>A<A>A<vA<A>^>AAA<A>vA^A (64 presses) 480A = <v<A>^>AA<vA<A>^>AAvAA^<A>A<v<A>^>AvA<A^>A<A>A<vA<A>^>AAA<A>vA^Av<A>^A<A>A (74 presses) 74*480 = 35520 140A 1 = <v<A>^>A<vA<A>^>AAvAA^<A>A (26 presses) 14 = <v<A>^>A<vA<A>^>AAvAA^<A>A<v<A>^>AvA^A (38 presses) 140 = <v<A>^>A<vA<A>^>AAvAA^<A>A<v<A>^>AvA^A<vA^>A<v<A>^>AAvA^<A>A (60 presses) 140A = <v<A>^>A<vA<A>^>AAvAA^<A>A<v<A>^>AvA^A<vA^>A<v<A>^>AAvA^<A>A<vA^>A<A>A (70 presses) 70*140 = 9800 413A 4 = <v<A>^>AA<vA<A>^>AAvAA^<A>A (27 presses) 41 = <v<A>^>AA<vA<A>^>AAvAA^<A>A<vA<A>^>A<A>vA^A (43 presses) 413 = <v<A>^>AA<vA<A>^>AAvAA^<A>A<vA<A>^>A<A>vA^A<vA^>AA<A>A (54 presses) 413A = <v<A>^>AA<vA<A>^>AAvAA^<A>A<vA<A>^>A<A>vA^A<vA^>AA<A>A<vA<A>^>A<A>vA^A (70 presses) 70*413 = 28910 964A 9 = <v<A>^>AAAvA^A (14 presses) 96 = <v<A>^>AAAvA^A<vA<A>^>AvA^<A>A (30 presses) 964 =<v<A>^>AAAvA^A<vA<A>^>AvA^<A>A<vA<AA>^>AAvAA^<A>A (49 presses) 964A =<v<A>^>AAAvA^A<vA<A>^>AvA^<A>A<vA<AA>^>AAvAA^<A>Av<A^>AA<v<A>^>AAvA^<A>A (72 presses) 72*964 = 69408 TOTAL SUM = 20592+35520+9800+28910+69408 = 164230

Vart det sĂ€ker brister Ă€r hur jag ofta jag vĂ€ljer att navigera till LEFT-tangenterna eftersom de Ă€r lĂ€ngst bort frĂ„n A-knapparna.đŸ€”

Ett giltigt knapptryck i min lösning Ă€r nĂ€r du trycker pĂ„ VÄNSTER, NER, UPP, HÖGER eller A och Ă€r det A sĂ„ kontrolleras om VÄNSTER, HÖGER, NER, UPP, A Ă€r giltigt i Robot 1 och sedan i Robot 2 om det Ă€r Robot 1:s A som trycks via anvĂ€ndaren. Robot 2:s "knapptryck" kontrolleras Ă€ven i nummerknapparna sĂ„ att det inte gĂ„r att gĂ„ "out of bounds".

Dold text

NÄja, det var kul sÄ lÀnge det vara!

Btw (för den som orkar Ä har lust kring Dag 21 Del 1):

Om nÄgon har de olika korrekta knapptryckningarna för de olika [\d]+A alltsÄ: "<>^vA" för Dag 21 Del 1 sÄ tar jag gÀrna emot dem bara för att testköra dem i webbappen sÄ vet jag iaf att webbappen programmet fortfarande fungerar med rÀtt steg att följa sÄ gjorde jag iaf nÄgot med det hela och fick nöta lite JS pÄ vÀgen!

Alternativt fÄr Du gÀrna prova sjÀlv och bara rapportera. Bara Copy&pastea av de olika <>^vA-stegen för varje [\d]+A.

Dold text

Mvh,
WKF.

Visa signatur

(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming

PermalÀnk
Datavetare ★
●

Day: 21
SprÄk: Rust

Min initiala approach var att anvÀnda en tabell likt vad @Ingetledigtnamn gjorde (hade i.o.f.s. tvÄ separata tabeller). Det fungerade lysande för exemplet, men gav fel svar för min input... Testade att köra din lösning @Ingetledigtnamn, Àven den ger fel svar (för högt resultat för bÄde del 1 och del 2).

SÄ Àndrade till att generera alla tÀnkbara permutationer för att gÄ frÄn X->Y och vÀljer den kortaste, det fungerade!

del 1: 5”s (M3), 11”s (Orange Pi 5)
del 2: 53”s(M3), 118”s (Orange Pi 5)

use ahash::{AHashMap, AHashSet}; use std::fs::read_to_string; pub const INPUT_FILE: &str = "input.txt"; pub const NUMERIC_KEYPAD: &[(char, Vec2D)] = &[ ('7', (0, 0)), ('8', (1, 0)), ('9', (2, 0)), // --- ('4', (0, 1)), ('5', (1, 1)), ('6', (2, 1)), // --- ('1', (0, 2)), ('2', (1, 2)), ('3', (2, 2)), // --- // (0, 3) invalid ('0', (1, 3)), ('A', (2, 3)), ]; pub const DIRECTIONAL_KEYPAD: &[(char, Vec2D)] = &[ // (0, 0) invalid ('^', (1, 0)), ('A', (2, 0)), // --- ('<', (0, 1)), ('v', (1, 1)), ('>', (2, 1)), ]; pub type Pin = Vec<char>; pub type Vec2D = (i8, i8); pub type PadMap = AHashMap<(char, char), Vec<Vec<char>>>; pub fn read_codes(path: &str) -> Vec<Pin> { read_to_string(path) .expect("Failed to read the file") .lines() .map(|line| line.chars().collect()) .collect() } pub fn part1(codes: &[Pin], num_map: &PadMap, dir_map: &PadMap) -> u64 { solve(codes, 3, num_map, dir_map) } pub fn part2(codes: &[Pin], num_map: &PadMap, dir_map: &PadMap) -> u64 { solve(codes, 26, num_map, dir_map) } fn solve(codes: &[Pin], robots: u32, num_map: &PadMap, dir_map: &PadMap) -> u64 { let mut memoize = AHashMap::new(); codes .iter() .map(|code| { numeric_pad_presses(code, robots, num_map, dir_map, &mut memoize) * numeric_part_of_code(code) }) .sum() } fn numeric_pad_presses( code: &Pin, robots: u32, num_map: &PadMap, dir_map: &PadMap, memoize: &mut AHashMap<(u32, char, char), u64>, ) -> u64 { let mut code_from_a = vec!['A']; code_from_a.extend(code); calculate_presses(&code_from_a, robots, num_map, dir_map, memoize) } fn direction_pad_presses( path: &Vec<char>, robots: u32, dir_map: &PadMap, memoize: &mut AHashMap<(u32, char, char), u64>, ) -> u64 { if robots == 0 { return path.len() as u64; } let mut path_from_a = vec!['A']; path_from_a.extend(path); calculate_presses(&path_from_a, robots, dir_map, dir_map, memoize) } fn calculate_presses( sequence: &Vec<char>, robots: u32, num_map: &PadMap, dir_map: &PadMap, memoize: &mut AHashMap<(u32, char, char), u64>, ) -> u64 { let mut presses = 0; for pair in sequence.windows(2) { let (from, to) = (pair[0], pair[1]); let key = (robots, from, to); if let Some(&best) = memoize.get(&key) { presses += best; } else { let mut best = u64::MAX; for path in num_map.get(&(from, to)).unwrap() { let cnt = direction_pad_presses(path, robots - 1, dir_map, memoize); best = best.min(cnt); } memoize.insert(key, best); presses += best; } } presses } pub fn generate_keypad_map(positions: &[(char, Vec2D)]) -> PadMap { let valid_positions = positions .iter() .fold(AHashSet::new(), |mut set, &(_, pos)| { set.insert(pos); set }); let mut map = PadMap::new(); for &(from_btn, from_pos) in positions { for &(to_btn, to_pos) in positions { let delta = (to_pos.0 - from_pos.0, to_pos.1 - from_pos.1); let mut paths = generate_paths(delta, from_pos, &valid_positions); for path in paths.iter_mut() { path.push('A'); } map.insert((from_btn, to_btn), paths); } } map } fn generate_paths(delta: Vec2D, start: Vec2D, valid_positions: &AHashSet<Vec2D>) -> Vec<Vec<char>> { if delta == (0, 0) { return vec![vec![]]; } let mut stack = vec![((delta.0, delta.1), start, Vec::new())]; let mut paths = Vec::new(); let append = |path: &Vec<char>, ch: char| -> Vec<char> { let mut clone = path.clone(); clone.push(ch); clone }; while let Some(((dx, dy), pos, path)) = stack.pop() { if !valid_positions.contains(&pos) { continue; } if dx == 0 && dy == 0 { paths.push(path.clone()); } else { if dx < 0 { stack.push(((dx + 1, dy), (pos.0 - 1, pos.1), append(&path, '<'))); } if dx > 0 { stack.push(((dx - 1, dy), (pos.0 + 1, pos.1), append(&path, '>'))); } if dy < 0 { stack.push(((dx, dy + 1), (pos.0, pos.1 - 1), append(&path, '^'))); } if dy > 0 { stack.push(((dx, dy - 1), (pos.0, pos.1 + 1), append(&path, 'v'))); } } } paths } fn char_to_digit(c: char) -> u8 { match c { '0'..='9' => c as u8 - b'0', 'A' => 10, _ => panic!("Unexpected character"), } } fn numeric_part_of_code(code: &Pin) -> u64 { code.iter() .map(|&c| char_to_digit(c)) .filter(|&digit| digit != 0xa) .fold(0, |prod, digit| prod * 10 + digit as u64) } fn main() { let codes = read_codes(INPUT_FILE); let num_map = generate_keypad_map(&NUMERIC_KEYPAD); let dir_map = generate_keypad_map(&DIRECTIONAL_KEYPAD); println!("part 1: {}", part1(&codes, &num_map, &dir_map)); println!("part 2: {}", part2(&codes, &num_map, &dir_map)); }

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

Dag: 22
SprÄk: Rust

LÄngsammaste lösningen sÄ hÀr lÄngt... Förhoppningsvis tillrÀckligt för att ÀndÄ klara "alla dagarna i sekvens under 1s pÄ Orange Pi 5"

del 1: 738”s (M3), 1.6ms (Orange Pi 5)
del 2: 35ms (M3), 230ms (Orange Pi 5)

use ahash::AHashMap; use rayon::prelude::*; use std::fs::read_to_string; pub const INPUT_FILE: &str = "input.txt"; pub type Number = i64; pub fn read_initial_secrets(path: &str) -> Vec<Number> { read_to_string(path) .expect("Failed to read the file") .lines() .map(|n| n.parse().unwrap()) .collect() } pub fn part1(initial_secrets: &[Number]) -> Number { initial_secrets .par_iter() .map(|&initial_secret| generate_n(initial_secret, 2000)) .sum() } pub fn part2(initial_secrets: &[Number]) -> Number { let combined_profits = initial_secrets.par_iter().map(calculate_profits).reduce( || AHashMap::new(), |mut acc, local_profits| { for (key, value) in local_profits { *acc.entry(key).or_insert(0) += value; } acc }, ); *combined_profits.values().max().unwrap() } fn generate_n(initial_secret: Number, cnt: Number) -> Number { (0..cnt).fold(initial_secret, |secret, _| generate(secret)) } fn generate(initial_secret: Number) -> Number { let mut secret = initial_secret; secret = ((secret << 6) ^ secret) & 0xffffff; secret = (secret >> 5) ^ secret; secret = ((secret << 11) ^ secret) & 0xffffff; secret } fn calculate_profits(initial_secret: &Number) -> AHashMap<(i8, i8, i8, i8), Number> { let mut profits = AHashMap::new(); let mut seq = (0, 0, 0, 0); seq.0 = generate(*initial_secret); seq.1 = generate(seq.0); seq.2 = generate(seq.1); seq.3 = generate(seq.2); let mut diffs = ( (seq.0 % 10 - initial_secret % 10) as i8, (seq.1 % 10 - seq.0 % 10) as i8, (seq.2 % 10 - seq.1 % 10) as i8, (seq.3 % 10 - seq.2 % 10) as i8, ); for _ in 4..2000 { if !profits.contains_key(&diffs) { let price = seq.3 % 10; *profits.entry(diffs).or_default() += price; } (seq.0, seq.1, seq.2, seq.3) = (seq.1, seq.2, seq.3, generate(seq.3)); (diffs.0, diffs.1, diffs.2, diffs.3) = (diffs.1, diffs.2, diffs.3, (seq.3 % 10 - seq.2 % 10) as i8); } profits } fn main() { let secret_numbers = read_initial_secrets(INPUT_FILE); println!("part 1: {}", part1(&secret_numbers)); println!("part 2: {}", part2(&secret_numbers)); }

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

Day: 21
SprÄk: Rust

Min initiala approach var att anvÀnda en tabell likt vad @Ingetledigtnamn gjorde (hade i.o.f.s. tvÄ separata tabeller). Det fungerade lysande för exemplet, men gav fel svar för min input... Testade att köra din lösning @Ingetledigtnamn, Àven den ger fel svar (för högt resultat för bÄde del 1 och del 2).

SÄ Àndrade till att generera alla tÀnkbara permutationer för att gÄ frÄn X->Y och vÀljer den kortaste, det fungerade!

Dold text

Det visade spela roll vilken vÀg man valde nÀr man hade flera alternativa nÀrmsta vÀgar mellan tvÄ knappar. Jag förstod inte riktigt varför, men "<" ligger lÄngre bort frÄn "A" Àn "^" eller nÄt...

Min lösning funkade för exemplen i uppgiften och min input. FrÄn början körde jag alla vÀgar, men kunde stegvis klippa ner den till min slutliga lösning och fortfarande fÄ samma svar.

Uppenbarligen funkar den inte för allas skarpa input. DÄ kanske man behöver köra alla vÀgar för att hitta den kortaste, eller byta vÀgar mellan 3 och 7 eller 1 och 9 som jag vet spökade. Du hade nog tangentpar som jag inte testkört med.

Dold text
PermalÀnk
Medlem
●

Dag: 22
SprÄk: Java
Lösning: GitHub

PermalÀnk
Medlem
●

Dag: 22
SprÄk: Scala

Fick till en hyffsat snabb del ett men fick inte riktigt till det pĂ„ del tvĂ„ sĂ„ skrev om den till en enklare variant. ~70ÎŒs / ~14ms ~3ms (kom pĂ„ att jag iaf borde göra nĂ„n variant av flertrĂ„dning pĂ„ del tvĂ„)

object Day22: final class Part1 private (parent: Part1 | Null, data: Array[Int], lo: Int, hi: Int, pending: Int) extends CountedCompleter[Long](parent, pending): def this(data: Array[Int]) = this(null, data, 0, data.length, Part1.initialLeaves(data.length)) private def hash(from: Int, to: Int): Long = val isp = IntVector.SPECIES_PREFERRED val mod = IntVector.broadcast(isp, 0xffffff) var acc = 0L var idx = from while idx < to do var num = IntVector.fromArray(isp, data, idx, isp.indexInRange(idx, to)) var i = 0 while i < 2000 do num = num.lanewise(LSHL, 6).lanewise(XOR, num).and(mod) num = num.lanewise(LSHR, 5).lanewise(XOR, num) num = num.lanewise(LSHL, 11).lanewise(XOR, num).and(mod) i += 1 acc += num.reduceLanes(ADD) idx += isp.length acc private final val subs = Array.ofDim[Part1](pending) private var res = 0L def compute(): Unit = var pend = pending var n = hi - lo while pend > 0 do val half = n >>> 1 pend -= 1 val sub = Part1(this, data, lo + half, lo + n, pend) subs(pend) = sub sub.fork() n = half res += hash(lo, lo + n) tryComplete() override def onCompletion(caller: CountedCompleter[?]): Unit = var i = 0 while i < subs.length do res += subs(i).res i += 1 override def getRawResult: Long = res object Part1: private final val TargetLeaves = Runtime.getRuntime.availableProcessors() << 2 private final val MinSizeLeaves = 100 private def initialLeaves(size: Int): Int = val leaves = TargetLeaves min (size / MinSizeLeaves) if leaves == 0 then 0 else 31 - Integer.numberOfLeadingZeros(leaves) def part1(data: Array[Int]) = Part1(data).invoke() final class Part2 private ( parent: Part2 | Null, data: Array[Int], bananas: AtomicIntegerArray, lo: Int, hi: Int, pending: Int) extends CountedCompleter[Unit](parent, pending): def this(data: Array[Int], bananas: AtomicIntegerArray) = this(null, data, bananas, 0, data.length, Part2.initialLeaves(data.length)) private final val subs = Array.ofDim[Part2](pending) private val visited = Array.ofDim[Boolean](130321) private def calculateBananas(from: Int, to: Int) = inline def hash(secret: Int): Int = var s = secret s = ((s << 6) ^ s) & 0xffffff s = (s >> 5) ^ s ((s << 11) ^ s) & 0xffffff var idx = from while idx < to do var s = data(idx) var prev = s % 10 var lookupIdx = 0 var i = 0 while i < 2000 do s = hash(s) val curr = s % 10 val diff = curr - prev lookupIdx = lookupIdx % 6859 * 19 + diff + 9 if i >= 3 && !visited(lookupIdx) then visited(lookupIdx) = true bananas.addAndGet(lookupIdx, curr) prev = curr i += 1 ju.Arrays.fill(visited, false) idx += 1 def compute(): Unit = var pend = pending var n = hi - lo while pend > 0 do val half = n >>> 1 pend -= 1 val sub = Part2(this, data, bananas, lo + half, lo + n, pend) subs(pend) = sub sub.fork() n = half calculateBananas(lo, lo + n) tryComplete() object Part2: private final val TargetLeaves = Runtime.getRuntime.availableProcessors() << 2 private final val MinSizeLeaves = 100 private def initialLeaves(size: Int): Int = val leaves = TargetLeaves min (size / MinSizeLeaves) if leaves == 0 then 0 else 31 - Integer.numberOfLeadingZeros(leaves) def part2(data: Array[Int]) = val bananas = AtomicIntegerArray(130321) Part2(data, bananas).invoke() var max = 0 var i = 0 while i < bananas.length do max = Math.max(max, bananas.get(i)) i += 1 max def main(args: Array[String]): Unit = val path = """22.txt""" val data = Using.resource(Source.fromFile(path))(_.getLines().map(_.toInt).toArray) println(part1(data)) println(part2(data))

Dold text
PermalÀnk
Medlem ★
●

Dag: 23
SprÄk: Python

from collections import defaultdict connections = defaultdict(set) for x,y in [l.strip().split("-") for l in open("input23.txt", "r").readlines()]: connections[x].add(y) connections[y].add(x) def part1(connections): return len(set(tuple(sorted([node, n1, n2])) for node, neighbors in connections.items() for n1 in neighbors for n2 in connections[n1] if node.startswith("t") and node in connections[n2])) def part2(connections): clusters = set(tuple([n]) for n in connections.keys()) while True: next_clusters = set(tuple(sorted(c + (n,))) for c in clusters for n in set.intersection(*[connections[n] for n in c])) if not next_clusters: return ",".join(next(iter(clusters))) clusters = next_clusters print(part1(connections), part2(connections))

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

Dag: 21
SprÄk: Python

Oboy, i dag körde jag i diket ordentligt. Det tog tid att hitta en elegant lösning i dag...

from itertools import pairwise order = "0123456789A^v<>" pad = [ ['A' , '^<A' , '^A' , '^>A' , '^^<A' , '^^A' , '>^^A' , '^^^<A' , '^^^A' , '^^^>A' , '>A' , '' , '' , '' , '' ], # 0 ['>vA' , 'A' , '>A' , '>>A' , '^A' , '^>A' , '^>>A' , '^^A' , '^^>A' , '^^>>A' , '>>vA' , '' , '' , '' , '' ], # 1 ['vA' , '<A' , 'A' , '>A' , '^<A' , '^A' , '^>A' , '^^<A' , '^^A' , '^^>A' , 'v>A' , '' , '' , '' , '' ], # 2 ['v<A' , '<<A' , '<A' , 'A' , '^<<A' , '^<A' , '^A' , '<<^^A' , '<^^A' , '^^A' , 'vA' , '' , '' , '' , '' ], # 3 ['>vvA' , 'vA' , 'v>A' , 'v>>A' , 'A' , '>A' , '>>A' , '^A' , '^>A' , '^>>A' , '>>vvA' , '' , '' , '' , '' ], # 4 ['vvA' , 'v<A' , 'vA' , 'v>A' , '<A' , 'A' , '>A' , '^<A' , '^A' , '^>A' , 'vv>A' , '' , '' , '' , '' ], # 5 ['<vvA' , 'v<<A' , 'v<A' , 'vA' , '<<A' , '<A' , 'A' , '^<<A' , '^<A' , '^A' , 'vvA' , '' , '' , '' , '' ], # 6 ['>vvvA' , 'vvA' , 'vv>A' , 'vv>>A' , 'vA' , 'v>A' , 'v>>A' , 'A' , '>A' , '>>A' , '>>vvvA', '' , '' , '' , '' ], # 7 ['vvvA' , 'vv<A' , 'vvA' , 'vv>A' , 'v<A' , 'vA' , 'v>A' , '<A' , 'A' , '>A' , 'vvv>A' , '' , '' , '' , '' ], # 8 ['vvv<A' , '<<vvA' , 'vv<A' , 'vvA' , 'v<<A' , 'v<A' , 'vA' , '<<A' , '<A' , 'A' , 'vvvA' , '' , '' , '' , '' ], # 9 ['<A' , '^<<A' , '^<A' , '^A' , '^^<<A' , '^^<A' , '^^A' , '^^^<<A', '<^^^A' , '^^^A' , 'A' , '<A' , '<vA' , 'v<<A' , 'vA' ], # A ['' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '>A' , 'A' , 'vA' , 'v<A' , 'v>A' ], # ^ ['' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '^>A' , '^A' , 'A' , '<A' , '>A' ], # v ['' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '>>^A' , '>^A' , '>A' , 'A' , '>>A' ], # < ['' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '^A' , '<^A' , '<A' , '<<A' , 'A' ], # > ] def expand2(s, depth, memo = {}): if depth < 0: return len(s) if (t := (s, depth)) in memo: return memo[t] memo[t] = sum(expand2(pad[order.index(a)][order.index(b)], depth - 1) for a, b in pairwise("A" + s)) return memo[t] print(*[sum(expand2(l, d) * int(l[:-1]) for l in open("input21.txt").read().splitlines()) for d in [2, 25]])

Dold text

Dag: 21 igen, nu med rÀttad tabell. Nu Àr alla sifferkombinationer testade

order = "0123456789A^v<>" pad = [ ['A' , '^<A' , '^A' , '^>A' , '^^<A' , '^^A' , '>^^A' , '^^^<A' , '^^^A' , '^^^>A' , '>A' , '' , '' , '' , '' ], # 0 ['>vA' , 'A' , '>A' , '>>A' , '^A' , '^>A' , '^>>A' , '^^A' , '^^>A' , '^^>>A' , '>>vA' , '' , '' , '' , '' ], # 1 ['vA' , '<A' , 'A' , '>A' , '<^A' , '^A' , '^>A' , '<^^A' , '^^A' , '^^>A' , 'v>A' , '' , '' , '' , '' ], # 2 ['<vA' , '<<A' , '<A' , 'A' , '<<^A' , '<^A' , '^A' , '<<^^A' , '<^^A' , '^^A' , 'vA' , '' , '' , '' , '' ], # 3 ['>vvA' , 'vA' , 'v>A' , 'v>>A' , 'A' , '>A' , '>>A' , '^A' , '^>A' , '^>>A' , '>>vvA' , '' , '' , '' , '' ], # 4 ['vvA' , '<vA' , 'vA' , 'v>A' , '<A' , 'A' , '>A' , '<^A' , '^A' , '^>A' , 'vv>A' , '' , '' , '' , '' ], # 5 ['<vvA' , '<<vA' , '<vA' , 'vA' , '<<A' , '<A' , 'A' , '<<^A' , '<^A' , '^A' , 'vvA' , '' , '' , '' , '' ], # 6 ['>vvvA' , 'vvA' , 'vv>A' , 'vv>>A' , 'vA' , 'v>A' , 'v>>A' , 'A' , '>A' , '>>A' , '>>vvvA', '' , '' , '' , '' ], # 7 ['vvvA' , '<vvA' , 'vvA' , 'vv>A' , '<vA' , 'vA' , 'v>A' , '<A' , 'A' , '>A' , 'vvv>A' , '' , '' , '' , '' ], # 8 ['<vvvA' , '<<vvA' , '<vvA' , 'vvA' , '<<vA' , '<vA' , 'vA' , '<<A' , '<A' , 'A' , 'vvvA' , '' , '' , '' , '' ], # 9 ['<A' , '^<<A' , '<^A' , '^A' , '^^<<A' , '<^^A' , '^^A' , '^^^<<A', '<^^^A' , '^^^A' , 'A' , '<A' , '<vA' , 'v<<A' , 'vA' ], # A ['' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '>A' , 'A' , 'vA' , 'v<A' , 'v>A' ], # ^ ['' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '^>A' , '^A' , 'A' , '<A' , '>A' ], # v ['' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '>>^A' , '>^A' , '>A' , 'A' , '>>A' ], # < ['' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '^A' , '<^A' , '<A' , '<<A' , 'A' ], # > ] def expand(s, depth, memo = {}): if depth < 0: return len(s) if (t := (s, depth)) in memo: return memo[t] memo[t] = sum(expand(pad[order.index(a)][order.index(b)], depth - 1) for a, b in pairwise("A" + s )) return memo[t]

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

Dag: 21 igen, nu med rÀttad tabell. Nu Àr alla sifferkombinationer testade

order = "0123456789A^v<>" pad = [ ['A' , '^<A' , '^A' , '^>A' , '^^<A' , '^^A' , '>^^A' , '^^^<A' , '^^^A' , '^^^>A' , '>A' , '' , '' , '' , '' ], # 0 ['>vA' , 'A' , '>A' , '>>A' , '^A' , '^>A' , '^>>A' , '^^A' , '^^>A' , '^^>>A' , '>>vA' , '' , '' , '' , '' ], # 1 ['vA' , '<A' , 'A' , '>A' , '<^A' , '^A' , '^>A' , '<^^A' , '^^A' , '^^>A' , 'v>A' , '' , '' , '' , '' ], # 2 ['<vA' , '<<A' , '<A' , 'A' , '<<^A' , '<^A' , '^A' , '<<^^A' , '<^^A' , '^^A' , 'vA' , '' , '' , '' , '' ], # 3 ['>vvA' , 'vA' , 'v>A' , 'v>>A' , 'A' , '>A' , '>>A' , '^A' , '^>A' , '^>>A' , '>>vvA' , '' , '' , '' , '' ], # 4 ['vvA' , '<vA' , 'vA' , 'v>A' , '<A' , 'A' , '>A' , '<^A' , '^A' , '^>A' , 'vv>A' , '' , '' , '' , '' ], # 5 ['<vvA' , '<<vA' , '<vA' , 'vA' , '<<A' , '<A' , 'A' , '<<^A' , '<^A' , '^A' , 'vvA' , '' , '' , '' , '' ], # 6 ['>vvvA' , 'vvA' , 'vv>A' , 'vv>>A' , 'vA' , 'v>A' , 'v>>A' , 'A' , '>A' , '>>A' , '>>vvvA', '' , '' , '' , '' ], # 7 ['vvvA' , '<vvA' , 'vvA' , 'vv>A' , '<vA' , 'vA' , 'v>A' , '<A' , 'A' , '>A' , 'vvv>A' , '' , '' , '' , '' ], # 8 ['<vvvA' , '<<vvA' , '<vvA' , 'vvA' , '<<vA' , '<vA' , 'vA' , '<<A' , '<A' , 'A' , 'vvvA' , '' , '' , '' , '' ], # 9 ['<A' , '^<<A' , '<^A' , '^A' , '^^<<A' , '<^^A' , '^^A' , '^^^<<A', '<^^^A' , '^^^A' , 'A' , '<A' , '<vA' , 'v<<A' , 'vA' ], # A ['' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '>A' , 'A' , 'vA' , 'v<A' , 'v>A' ], # ^ ['' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '^>A' , '^A' , 'A' , '<A' , '>A' ], # v ['' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '>>^A' , '>^A' , '>A' , 'A' , '>>A' ], # < ['' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '^A' , '<^A' , '<A' , '<<A' , 'A' ], # > ] def expand(s, depth, memo = {}): if depth < 0: return len(s) if (t := (s, depth)) in memo: return memo[t] memo[t] = sum(expand(pad[order.index(a)][order.index(b)], depth - 1) for a, b in pairwise("A" + s )) return memo[t]

Dold text

Lysade!

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

Dag: 23
SprÄk: Rust

del 1+2: 640”s (M3), 1.7ms (Orange Pi 5)

use ahash::{AHashMap, AHashSet}; use itertools::Itertools; use std::fs::read_to_string; pub const INPUT_FILE: &str = "input.txt"; pub fn read_network_map(path: &str) -> Vec<(String, String)> { read_to_string(path) .expect("Failed to read the file") .lines() .map(|line| { let mut parts = line.split('-'); let from = parts.next().unwrap().to_string(); let to = parts.next().unwrap().to_string(); (from, to) }) .collect() } pub fn solve(network_map: &[(&str, &str)]) -> (usize, String) { let mut interconnections = AHashMap::new(); for &(comp1, comp2) in network_map { interconnections .entry(comp1) .or_insert_with(AHashSet::new) .insert(comp2); interconnections .entry(comp2) .or_insert_with(AHashSet::new) .insert(comp1); } // Part 1 let mut three_interconnection: AHashSet<Vec<&str>> = AHashSet::new(); for (comp_name, connections) in &interconnections { if comp_name.chars().next().unwrap() == 't' { for name_pairs in connections.iter().combinations(2) { let (name1, name2) = (name_pairs[0], name_pairs[1]); if interconnections.get(name1).unwrap().contains(name2) && interconnections.get(name2).unwrap().contains(name1) { let mut three_group = vec![*comp_name, *name1, *name2]; three_group.sort(); three_interconnection.insert(three_group); } } } } // Part 2 let mut max_computers = 1; let mut password = String::from(""); for (comp_name, connections) in &interconnections { for group_sz in (max_computers..=connections.len()).rev() { if max_computers > group_sz { break; } for group in connections.iter().combinations(group_sz) { if !all_connected(comp_name, &group, &interconnections) { continue; } max_computers = group_sz + 1; let mut names = group.iter().map(|s| s.to_string()).collect::<Vec<_>>(); names.push(comp_name.to_string()); names.sort(); password = names.join(","); } } } (three_interconnection.len(), password) } fn all_connected( name: &str, names: &[&&str], interconnections: &AHashMap<&str, AHashSet<&str>>, ) -> bool { for &&n in names { let ic = interconnections.get(n).unwrap(); if !ic.contains(name) || !names .iter() .all(|&&conn_name| conn_name == n || ic.contains(conn_name)) { return false; } } true } fn main() { let network_map = read_network_map(INPUT_FILE); let network_map_refs: Vec<(&str, &str)> = network_map .iter() .map(|(a, b)| (a.as_str(), b.as_str())) .collect(); let (num_three_comp, password) = solve(&network_map_refs); println!("part 1: {}", num_three_comp); println!("part 2: {}", password); }

Dold text
Visa signatur

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

PermalÀnk
Medlem ★
●

Dag: 24, Del 1
SprÄk: Python

Jag bad Copilot om en topological sort för gate-DAGen. Den var bra att ha för Del 2.

from operator import __and__, __or__, __xor__ from collections import defaultdict import heapq def topological_sort_gates(gates): # Create a graph and in-degree count graph = defaultdict(list) in_degree = defaultdict(int) all_vars = set() # Build the graph and in-degree count for res, v1, v2, op in gates: graph[v1].append((res, v1, v2, op)) graph[v2].append((res, v1, v2, op)) in_degree[res] += 2 # Each gate has two dependencies all_vars.update([res, v1, v2]) # Initialize the priority queue with nodes having zero in-degree priority_queue = [(v1, var) for var in all_vars if in_degree[var] == 0] heapq.heapify(priority_queue) sorted_gates = [] while priority_queue: _, var = heapq.heappop(priority_queue) for res, v1, v2, op in graph[var]: in_degree[res] -= 1 if in_degree[res] == 0: heapq.heappush(priority_queue, (v1, res)) # Find the gate corresponding to this result and add it to sorted_gates for gate in gates: if gate[0] == res: sorted_gates.append(gate) break return sorted_gates values, gates = open("input24.txt").read().split('\n\n') known = {var: int(val) for var, val in [l.split(': ') for l in values.split('\n')]} gates = [(res, v1, v2, op) for v1, op, v2, _, res in [g.strip().split(" ") for g in gates.strip().split('\n')]] gates = topological_sort_gates(gates) for res, v1, v2, op in gates: known[res] = eval(f"__{op.lower()}__({v1}, {v2})", globals(), known) print(sum([1 << i for i, v in enumerate([v for k, v in sorted(known.items()) if k.startswith('z')]) if v]))

Dold text

Del 2:

HÀr genererade jag en Python-funktion som evaluerade gate-nÀtet. Hela den funktionen tÀnkte jag bespara er, men den följde detta mönster:

def fun(x, y): x00 = (x >> 0) & 1 x01 = (x >> 1) & 1 ... x44 = (x >> 44) & 1 y00 = (y >> 0) & 1 y01 = (y >> 1) & 1 .... y44 = (y >> 44) & 1 z00 = __xor__(x00, y00) skt = __and__(y00, x00) kjn = __xor__(y01, x01) hth = __and__(y01, x01) nss = __and__(x02, y02) fvj = __xor__(x02, y02) ... ... z45 = __or__(jkn, gvk) z = (z00 << 0) z += (z01 << 1) z += (z02 << 2) ... z += (z45 << 45) return z

Med den kunde jag testa en bit i taget och var resultatet inte stÀmde. Att klura ut vilka variabler som bytt plats var mest okulÀr mönstermatchning i den genererade koden.

Dold text
PermalÀnk
Medlem
●

Dag: 24 (del 1)
SprÄk: Java
Lösning: GitHub

Del 1 Ätminstone - var rolig och enkel, del 2 Àr förvirrande - sÄ det fÄr vÀnta tills efter bakningen av lussekatter.

PermalÀnk
Medlem ★
●

Vad tusan var det hÀr för nÄgot. Hittade ingen vÀg alls idag (Dag 24) för del 2!

Dag: 24 (del 2)
SprÄk: Visuell inspektion

Kunde inte komma pÄ en bra algoritm för detta. Valde istÀllet att visa adderaren i Graphviz och sÄg konstigheter direkt kring Z-noderna. SÄ min plan blev följande

1. Exportera grafen frÄn kod
2. Fortfarande i kod, gÄ bakÄt i adderaren frÄn varje Z-nod och markera avvikande noder
3. Lös varje avvikelse manuellt

Det rÀckte att gÄ bakÄt i grafen tvÄ steg. I första steget sÄ bör Z-noden vara kopplad till en XOR och sedan, ett steg lÀngre upp till en XOR och en OR.

Hittade exakt sju avvikelser, varav tvÄ i början och en i slutet som förmodligen Àr korrekta. De fyra ÄterstÄende gick att lösa manuellt genom titta i grafen.

I mitt exempel nedan sÄ visar de gröna flödet förvÀntat beteendende (med XOR, XOR, och OR), medans det röda flödet har en AND gate istÀllet för en XOR. Vi fixar detta genom att "löda om" - byta outputs pÄ "jgt" och "mht"

Dold text
Visa signatur

Louqe Ghost S1 MK3 | Asus ROG Strix B660-I Gaming WiFi | Intel Core i7 12700K | nVidia RTX 2070 Super FE | Corsair 64GB (2x32GB) DDR5 5600MHz CL40 Vengeance | Samsung 980 PRO M.2 NVMe SSD 2TB | Corsair SF750 750W 80+ Platinum | Noctua NH-L12 Ghost S1 edition | Kablar frÄn pslate customs | 2 stk Dell Ultrasharp 3014 | Logitech MX Keys | Logitech MX Anywhere

PermalÀnk
Medlem
●
Skrivet av ViLue:

Dag: 24 (del 1)
SprÄk: Java
Lösning: GitHub

Del 1 Ätminstone - var rolig och enkel, del 2 Àr förvirrande - sÄ det fÄr vÀnta tills efter bakningen av lussekatter.

Dag: 24
SprÄk: Java
Lösning: GitHub

Ended up following the advice of smarter people and implemented rules according to how the adder would work:

- if the operation is XOR, the output has to be z to be valid (except if it is the last one z45)
- if the output is not z and the operation is XOR, the input cannot be x or y

These 2 rules give 6 faulty gates
The last 2 gates can be found with the rules (unless the input gates are x00 and y00):
- but if there is a XOR operation with x and y as input there must be another XOR gate with that gate as input (lookahead)
- for each AND gate, an OR gate must exist which uses that gate as an input (also lookahead)

That leaves (at least for me) 8 gates which are faulty

Dold text