🌟 Advent of Code (AoC) 2021 🌟

PermalÀnk
Medlem ★
●

Dag: 12
SprÄk: Python (Iterativ)

from collections import defaultdict, deque, Counter reachable = defaultdict(list) for a, b in [s.rstrip().split("-") for s in open("input12").readlines()]: if not b == 'start': reachable[a].append(b) if not a == 'start': reachable[b].append(a) del reachable['end'] def keep(path, extra_visit): cs = Counter(path) l = [v for k,v in cs.items() if k.islower()] return sum(l) <= len(l) + extra_visit def bfs(extra_visit): paths, found = deque([['start']]), 0 while(paths): p = paths.popleft() found += p[-1] == 'end' paths.extend([np for next in reachable[p[-1]] if keep(np:= p + [next], extra_visit)]) return found print(bfs(0), bfs(1))

Dold text
PermalÀnk
●

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

Idag Àr jag faktiskt nöjd med min lösning, blev en elegant rekursion

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

Jag har svÄrt för det hÀr med rekursion. Jag ser ju direkt att en uppgift som denna lÀmpar sig vÀldigt vÀl för en rekursiv DFS, men trots det sitter jag lÀÀÀÀnge och försöker göra en iterativ variant. Tillslut fick jag ge upp och ge mig ut pÄ rekursionsjakt pÄ Internet. Aja. TillrÀckligt mÄnga sÄdana hÀr uppgifter sÄ kanske jag ger med mig och lÀr mig gilla rekursion.

Dold text

NÀr jag assade pÄ KTH var det Scheme som gÀllde och det betyder rekursion. TankesÀttet vi försökte lÀra eleverna kallades för Wishful Thinking. Med reservation för att detta exempel Àr typ 10000 gÄnger enklare Àn dagens uppgift sÄ hur skall man tÀnka för att, sÀg, kvadrera alla element i en lista?

Oj, oj, vad svÄrt. Hur skall vi nÄgonsin kunna producera en lista dÀr alla element Àr kvadrerade? Jag fattar ingenting...
LÄt oss börja med slutfallet. Den tomma listan Àr enkel:

def quad(l): if l == []: return l ...

OK, det var lÀtt, och en lista med ett element skulle ocksÄ vara lÀtt:

def quad(l): if l == []: return l if len(l) == 1: return [l[0] * l[0]] ...

men sen dÄ? OK, hur kan vi bryta ner det hÀr? Om vi tar det ett element i taget kanske? OK, vi vet vad som skall göras för ett element... Om vi hade en funktion som kunde kvadrera alla element i en lista kunde vi hantera det första elementet och sedan anropa den funktionen för att hantera resten av listan. Men vÀnta nu, vi hÄller ju pÄ och skriver en sÄdan funktion, vi kan anvÀnda den

def quad(l): if l == []: return l return [l[0] * l[0]] + quad([1:])

Som @survivalcode föreslog, börja i slutfallet, fundera pÄ vad du behöver göra för ett element och kom ihÄg att du har en funktion som tar hand om resten. Riktigt sÄ hÀr enkla Àr ju inte problemen som vi löser hÀr, men jag tycker det brukar hjÀlpa om man börjar frÄn slutfallet och bygger upp det dÀrifrÄn.

PermalÀnk
Medlem
●

Dag: 12
SprÄk: C#

internal class Puzzle12 : Puzzle<int> { public class Cave { public string Name { get; } public bool IsSmall { get; } public bool CanEnterTwice { get; set; } public List<Cave> Connections { get; } = new(); public Cave(string name, bool canEnterTwice = false) { Name = name; IsSmall = char.IsLower(name[0]); CanEnterTwice = canEnterTwice; } public int EnteredCount { get; set; } } protected override void Solve(string[] lines) { var caves = new Dictionary<string, Cave>(); Cave GetOrCreateCave(string caveStr) { if (!caves.TryGetValue(caveStr, out var cave)) { caves[caveStr] = cave = new Cave(caveStr); } return cave; } foreach (var line in lines) { var cavesStr = line.Split('-'); var from = GetOrCreateCave(cavesStr[0]); var to = GetOrCreateCave(cavesStr[1]); from.Connections.Add(to); to.Connections.Add(from); } var pathsFound = new HashSet<string>(); FindPaths(caves["start"], pathsFound); One = pathsFound.Count; pathsFound.Clear(); foreach (var c in caves.Values .Where(c => c.IsSmall && c.Name is not ("end" or "start"))) { foreach (var cave in caves.Values) { cave.EnteredCount = 0; cave.CanEnterTwice = false; } c.CanEnterTwice = true; FindPaths(caves["start"], pathsFound); } Two = pathsFound..Count; } private void FindPaths(Cave cave, HashSet<string> pathsFound, ISet<string>? visitedCaves = null, List<string>? currentPath = null) { visitedCaves ??= new HashSet<string>(); currentPath ??= new() { "start" }; if (cave.Name == "end") { pathsFound.Add(string.Join(",", currentPath)); return; } cave.EnteredCount++; visitedCaves.Add(cave.Name); foreach (var con in cave.Connections) { if (!con.IsSmall || !visitedCaves.Contains(con.Name) || (con.CanEnterTwice && con.EnteredCount < 2)) { currentPath.Add(con.Name); FindPaths(con, pathsFound, visitedCaves, currentPath); currentPath.RemoveAt(currentPath.FindLastIndex(x => x == con.Name)); } } cave.EnteredCount--; visitedCaves.Remove(cave.Name); } }

Dold text
PermalÀnk
Medlem
●

FrÄga pÄ dag 12 del 2:


Specifically, big caves can be visited any number of times, a single small cave can be visited at most twice, and the remaining small caves can be visited at most once.

Med "a single small cave" menas hÀr "one and only one small cave for a given path"?

Dold text
PermalÀnk
Medlem
●

Dag: 12
SprÄk: Carth

Min lösning pÄ del 2 tog ca. 20 sec att köra först, sÄ jag har suttit ett par timmar och profilerat och optimerat standardbibliotek. Nu Àr exekveringstiden nere pÄ 4 sekunder. Fortfarande mycket, men mycket bÀttre Àn sÄ tror jag inte det kommer bli utan att jag dyker ner och skriver om kompilatorns kodgenererare.

(import std) (define main (do io/bind (<- input (io/map unwrap! (read-file "inputs/day12.txt"))) (let ((edges-list (unwrap! (parse edges-parser input))) (edges (apps |> edges-list list/iter (flat-map (fun ([a b]) (iter/cons [a b] (iter/once [b a])))) (filter (apps <o not (str-eq "start") cadr)) (map (map-cadr array/singleton)) (map/collect-with str-cmp array/append))))) (display (array/show (show-two id (array/show id)) (array/collect (map/iter edges)))) (display (str-append "Part 1: " (show-nat (count (paths-from edges False set/nil "start"))))) (display (str-append "Part 2: " (show-nat (count (paths-from edges True set/nil "start"))))))) (define (paths-from edges double-dip? seen from) (define (continue double-dip?) (let1 seen (if (small? from) (set/insert str-cmp from seen) seen) (apps |> (map/lookup! str-cmp from edges) array/iter (flat-map (paths-from edges double-dip? seen)) (map (list/cons from))))) (if (str-eq from "end") (iter/once (list/singleton "end")) (if (set/member? str-cmp from seen) (if double-dip? (continue False) iter/nil) (continue double-dip?)))) (define edges-parser (define pcave (parse/take-bytes-while1 alphabetic-byte?)) (parse/sep-by1 parse/space1 (parse/lift2 cons' pcave (parse/thenr (parse/string "-") pcave)))) (define (small? s) (lowercase-byte? (string/nth-byte! (to-nat 0) s)))

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 gbroll:

FrÄga pÄ dag 12 del 2:


Specifically, big caves can be visited any number of times, a single small cave can be visited at most twice, and the remaining small caves can be visited at most once.

Med "a single small cave" menas hÀr "one and only one small cave for a given path"?

Dold text

Max 1 small cave Àr det. Det blir tydligare om man kollar pÄ vilka vÀgar som Àr med i deras exempel-resultat, respektive vilka som skiner med sin frÄnvaro.

"start,A,end" Àr giltig (ingen liten besöks 2 gÄnger).

"start,A,c,A,c,A,b,A,end" Àr ocksÄ giltig ("c" Àr den lilla som besöks 2 gÄnger).

"start,A,c,A,c,A,b,A,b,end" Àr inte giltig (bÄde "c" och "b" besöks 2 gÄnger).

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

Dag: 9
SprÄk: Javascript

const getLowPoints = (map) => { const lowPoints = []; for (let i = 0; i < map.length; i++) for (let j = 0; j < map[0].length; j++) { const current = map[i][j]; const up = i > 0 ? map[i-1][j] : null; const down = i < map.length-1 ? map[i+1][j] : null; const left = j > 0 ? map[i][j-1] : null; const right = j < map[i].length-1 ? map[i][j+1] : null; if (isLowPoint(current, up, down, left, right)) { lowPoints.push({i,j}); }; } return lowPoints; } const replaceNines = (map) => { for (let i = 0; i < map.length; i++) for (let j = 0; j < map[0].length; j++) if (map[i][j] === '9') map[i][j] = -1; } const fillBasin = (i, j, map) => { if (map[i][j] === -1) return 0; map[i][j] = -1; let size = 1 if (i - 1 >= 0) size += fillBasin(i - 1, j, map); if (i + 1 < map.length) size += fillBasin(i + 1, j, map); if (j - 1 >= 0) size += fillBasin(i, j - 1, map); if (j + 1 < map[0].length) size += fillBasin(i, j + 1, map); return size; } export const solutionB = () => { let map = data(input); const lowPoints = getLowPoints(map); replaceNines(map); const basins = []; lowPoints.forEach((x) => { const basin = fillBasin(x.i, x.j, map); basins.push(basin); }) basins.sort((a, b) => b - a); console.log(basins[0] * basins[1] * basins[2]); }

Dold text

Ligger efter en del, prioriterar annat den hÀr mÄnaden men samtidigt sÄ Àr det ju kul att koda Àven efter arbetsdagen
Tycker jag börjar fÄ till, Ätminstone i mitt tycke, skapligt lÀttöverskÄdliga lösningar.
Resten av Äret arbetar jag i huvudsak inte med algoritmer och det Àr vÀl just det som lockar

PermalÀnk
Hedersmedlem ★
●

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

Det var inte lika svÄrt som jag fruktade, men nog tog det en stund. Rekursion Àr inte min starka sida, förvirrar mig sjÀlv alltid med alla stack frames.

LÄngsammaste lösningen hittills, överlÀgset (exkl brute force för dag 8 dÄ, som jag skrev om till <10 ms), runt 315 ms.

Edit: Efter att ha kollat era lösningar insĂ„g jag att jag sparade alla möjliga paths trots att de aldrig anvĂ€ndes. Ändrade till att rĂ€kna antalet istĂ€llet och fick iaf ner det till runt 265 ms istĂ€llet.

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: 12
SprÄk: Rust

use std::collections::{HashMap, HashSet}; fn main() { let input = std::fs::read_to_string("input.txt").unwrap(); let data: Vec<_> = input.lines().filter_map(|s| s.split_once('-')).collect(); let mut map: HashMap<_, HashSet<_>> = HashMap::new(); for (begin, end) in data { map.entry(begin).or_default().insert(end); map.entry(end).or_default().insert(begin); } println!("Part 1: {}", paths(&map, HashSet::new(), "start", false)); // 3230 println!("Part 2: {}", paths(&map, HashSet::new(), "start", true)); // 83475 } fn paths<'a>( data: &HashMap<&str, HashSet<&'a str>>, mut visited: HashSet<&'a str>, id: &'a str, mut twice: bool, ) -> u32 { if id == "end" { return 1; } if is_small(id) { if visited.contains(id) { if twice && id != "start" { twice = false; } else { return 0; } } else { visited.insert(id); } } match data.get(id) { Some(ids) => ids .iter() .fold(0, |acc, v| acc + paths(data, visited.clone(), v, twice)), _ => 0, } } pub fn is_small(s: &str) -> bool { s.chars().all(char::is_lowercase) }

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

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

Skam den som ger sig.
6.2 ms, till skillnad frÄn originalet med brute force (inlÀgg hÀr) som tog 5810 ms. Inte sÄ lÄngt ifrÄn 1000 ggr snabbare.

Hm, typescript kanske inte Àr vÀrdens snabbaste dÄ. Min brute-force i C tar 12ms. Det pÄ en R9-3900X@3.8HGz.
SÄ tycker det Àr tillrÀckligt snabbt för stunden... fÄ se om jag gör nÄn optimering senare.

PermalÀnk
Hedersmedlem ★
●
Skrivet av SAFA:

Hm, typescript kanske inte Àr vÀrdens snabbaste dÄ. Min brute-force i C tar 12ms. Det pÄ en R9-3900X@3.8HGz.
SÄ tycker det Àr tillrÀckligt snabbt för stunden... fÄ se om jag gör nÄn optimering senare.

Har du lagt ut koden nÄgonstans?
LÄter sanslöst snabbt om du kör samma kod som mig (skapa alla permutationer av abcdefg, "översÀtt" alla segment med alla permutationer och testa om de Àr giltiga). C Àr ju snabbare Àn TypeScript förstÄs, men det borde inte vara sÄn skillnad.

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: 12
SprÄk: C++

Blev en ganska stökig rekursiv lösning...

struct cave { bool big; int n_visits = 0; list<string> nb; }; typedef map<string,cave> cave_map; void add_cave(string cave_1, string cave_2, cave_map &caves) { if (caves.count(cave_1) == 0) { cave new_cave; new_cave.big = any_of(cave_1.begin(), cave_1.end(), [](char c) { return isupper(c); }); new_cave.nb.push_back(cave_2); caves.insert(make_pair(cave_1, new_cave)); } else { caves.at(cave_1).nb.push_back(cave_2); } } cave_map parse(vector<string> str_data) { cave_map caves; string regex_str = "^(\\w+)-(\\w+)$"; regex regex_obj(regex_str); smatch matches; int n_rows = str_data.size(); for (int i = 0; i < n_rows; i++) { regex_search(str_data[i], matches, regex_obj); string cave_1 = matches.str(1); string cave_2 = matches.str(2); add_cave(cave_1, cave_2, caves); add_cave(cave_2, cave_1, caves); } return caves; } int recursive_dfs(string start, cave_map &caves, bool allow_twice) { int n_paths = 0; int n_caves = caves.size(); list<string>::iterator list_it; cave_map::iterator cave_it; cave &ccave = caves.at(start); if (!ccave.big) ccave.n_visits++; if (ccave.n_visits==2) allow_twice = false; for (list_it = ccave.nb.begin(); list_it!= ccave.nb.end(); ++list_it) { if ((*list_it) == "start") ; //do nothing else if ((*list_it) == "end") { n_paths++; continue; } else if (allow_twice || caves.at(*list_it).n_visits <= 0) { n_paths += recursive_dfs(*list_it, caves, allow_twice); } } ccave.n_visits--; if (ccave.n_visits == 1) allow_twice = true; return n_paths; } int solve(cave_map caves, bool part_2) { //using DFS int n_paths = recursive_dfs("start", caves, part_2); return n_paths; }

Dold text
la till dag och sprÄk
PermalÀnk
Medlem
●

Dag: 12
SprÄk: Scala

val input = Using.resource(Source.fromFile("12.txt"))(_.getLines().toSet) val caves = input.flatMap { case s"$u-$v" => Set(u -> v, v -> u) }.groupMap(_(0))(_(1)) def dfs(caves: Map[String, Set[String]], visitTwice: Boolean): Int = def recur(u: String, visited: Set[String], visitTwice: Boolean): Int = caves(u).foldLeft(0) { (count, v) => if v == "end" then count + 1 else if visited.contains(v) then if visitTwice && v.head.isLower && v != "start" then count + recur(v, visited, false) else count else count + recur(v, if v.head.isUpper then visited else visited + v, visitTwice) } recur("start", Set("start"), visitTwice) dfs(caves, false) // part1 dfs(caves, true) // part2

Dold text
PermalÀnk
Medlem ★
●

Dag: 12
SprÄk: F#

type Cave = Map<string, List<string>> let parse = let parseLine (cave:Cave) (x:string) = let words = x.Split("-") let start, node = (words |> Seq.item 0, words |> Seq.item 1) let existingNode = Map.tryFind start cave let newCave = match existingNode with | None -> cave.Add(start, [node]) | Some connections -> cave.Add(start, node::connections) if start="start" || node="end" then // Don't add a reverse node for these, as we are not allowed to go back newCave else let revNode = Map.tryFind node newCave match revNode with | None -> newCave.Add(node, [start]) | Some connections -> newCave.Add(node, start::connections) System.IO.File.ReadAllLines >> Seq.fold parseLine Map.empty let isSmallCave = Seq.forall (System.Char.IsLower) let solver filter (map: Cave) = let rec solver' visitedNodes = let currentCave = visitedNodes |> List.head let exits = map.[currentCave] |> List.filter (filter visitedNodes) [ for exit in exits do if exit = "end" then yield ("end"::visitedNodes) else yield! solver' (exit::visitedNodes) ] solver' ["start"] |> Seq.length let task1 = let filter visitedNodes x = (not (isSmallCave x)) || not (visitedNodes |> List.contains x) parse >> solver filter let task2 = let filter visitedNodes cave = cave <> "start" && (not (isSmallCave cave) || not (List.contains cave visitedNodes) || visitedNodes |> Seq.countBy id |> Seq.exists (fun (cave, count) -> (isSmallCave cave) && count = 2) |> not) parse >> solver filter printfn "%A" (task1 "input.txt") printfn "%A" (task2 "input.txt")

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 12
SprÄk: Javascript

import * as fs from 'fs' const readCaveSystem = () => { const nodes = { } fs .readFileSync('./src/day12/input.txt', 'utf-8') .split('\n') .filter(l => l) .map(l => l.split('-')) .forEach(edge => { const node1 = edge[0] const node2 = edge[1] nodes[node1] = nodes[node1] ? [node2, ...nodes[node1]] : [node2] nodes[node2] = nodes[node2] ? [node1, ...nodes[node2]] : [node1] }) return nodes } const calcPaths = (nodes, calcSubPaths) => { const paths = [] nodes.start.forEach(node => { const path = ['start', node] paths.push(...calcSubPaths(nodes, path)) }) return paths } const calcSubPathsVisitingSmallOnce = (nodes, path) => { const current = path[path.length - 1] return isNodeEnd(current) ? [path] : nodes[current] .flatMap(next => isNodeLarge(next) || !isNodeInPath(path, next) ? calcSubPathsVisitingSmallOnce(nodes, [...path, next]) : [null] ) .filter(p => p !== null) } const calcSubPathsVisitingSmallTwiceOnce = (nodes, path) => { const current = path[path.length - 1] return isNodeEnd(current) ? [path] : nodes[current] .flatMap(next => isNodeLarge(next) || !isNodeInPath(path, next) || (!isNodeStart(next) && !hasSmallTwice(path)) ? calcSubPathsVisitingSmallTwiceOnce(nodes, [...path, next]) : [null] ) .filter(p => p !== null) } const hasSmallTwice = (path) => path.some((n1, i1) => !isNodeLarge(n1) && path.some((n2, i2) => n1 === n2 && i1 !== i2 ) ) const isNodeStart = (node) => node === 'start' const isNodeEnd = (node) => node === 'end' const isNodeLarge = (node) => { const allCaps = /^[A-Z]*$/ return node.match(allCaps) !== null } const isNodeInPath = (path, node) => path.includes(node) export const solvePart1 = () => { const nodes = readCaveSystem() const paths = calcPaths(nodes, calcSubPathsVisitingSmallOnce) return paths.length } export const solvePart2 = () => { const nodes = readCaveSystem() const paths = calcPaths(nodes, calcSubPathsVisitingSmallTwiceOnce) return paths.length }

Dold text
Visa signatur

An expert is one who knows more and more about less and less until he knows everything about nothing.

PermalÀnk
Medlem ★
●

Dag:12
SprÄk: Go

type node struct { small bool name string edges []string visitedTimes int } type Graph map[string]*node func main() { fileName := "input.txt" input, err := helpers.ReadLines(fileName) if err != nil { panic(err) } start := time.Now() graph := initGraph(input) result1, result2 := graph.findPaths() duration := time.Since(start) fmt.Println(result1, result2) fmt.Println(duration) } func initGraph(input []string) (graph Graph) { graph = make(Graph) for _, line := range input { vertices := strings.Split(line, "-") v, w := vertices[0], vertices[1] graph.createNode(v, w) graph.createNode(w, v) } return } func (graph *Graph) createNode(v, w string) { if n, ok := (*graph)[v]; ok { n.edges = append(n.edges, w) } else { var n node n.edges = make([]string, 0) n.edges = append(n.edges, w) n.name = v n.small = IsLowerCase(v) (*graph)[v] = &n } } func (graph Graph) findPaths() (int, int) { root := graph["start"] count1 := dfs(graph, root, false) count2 := dfs(graph, root, true) return count1, count2 } func dfs(graph Graph, node *node, allowDoubleVisit bool) (count int) { if node.name == "end" { return count + 1 } if node.small { node.visitedTimes++ if node.visitedTimes == 2 { allowDoubleVisit = false } } for _, v := range node.edges { neighbour := graph[v] if ((neighbour.visitedTimes == 0 || !neighbour.small) || allowDoubleVisit) && v != "start" { neighbour := graph[v] count += dfs(graph, neighbour, allowDoubleVisit) } } node.visitedTimes-- return count } func IsLowerCase(s string) bool { for _, r := range s { if !unicode.IsLower(r) && unicode.IsLetter(r) { return false } } return true }

Dold text
PermalÀnk
Medlem
●

Dag: 12
SprÄk: C#

LÄngsammaste lösningen hittills, men har iaf fÄtt ner sÄ att samtliga dagar löses pÄ ~250 ms sÄ det kÀnns hyfsat ÀndÄ.

internal class Day12 : Puzzle { public override object PartOne() => GetPathCount(new HashSet<Node>(), GetStartNode(), false); public override object PartTwo() => GetPathCount(new HashSet<Node>(), GetStartNode(), true); private static int GetPathCount(HashSet<Node> visitedLimitedNodes, Node node, bool allowVisitOneLimitedNodeTwice) { if (node.IsEnd) return 1; if (allowVisitOneLimitedNodeTwice && node.LimitedVisits && visitedLimitedNodes.Contains(node)) allowVisitOneLimitedNodeTwice = false; if (node.LimitedVisits) visitedLimitedNodes = new HashSet<Node>(visitedLimitedNodes, visitedLimitedNodes.Comparer) { node }; return node.ConnectedNodes .Where(x => !x.IsStart && (!x.LimitedVisits || allowVisitOneLimitedNodeTwice || !visitedLimitedNodes.Contains(x))) .Sum(x => GetPathCount(visitedLimitedNodes, x, allowVisitOneLimitedNodeTwice)); } private Node GetStartNode() { var paths = Utilities.GetInput(GetType()) .Split(Environment.NewLine) .Select(x => x.Split("-").ToArray()) .Select(x => (Start: x[0], Destination: x[1])); var nodesDict = new Dictionary<string, Node>(); foreach (var (start, destination) in paths) { nodesDict.TryAdd(start, new Node(start)); nodesDict.TryAdd(destination, new Node(destination)); var (startNode, destinationNode) = (nodesDict[start], nodesDict[destination]); startNode.ConnectedNodes.Add(destinationNode); destinationNode.ConnectedNodes.Add(startNode); } return nodesDict["start"]; } private class Node { public readonly bool IsStart; public readonly bool IsEnd; public readonly bool LimitedVisits; public Node(string name) { ConnectedNodes = new List<Node>(); IsStart = name == "start"; IsEnd = name == "end"; LimitedVisits = name == name.ToLower(); } public IList<Node> ConnectedNodes { get; } } }

Dold text
PermalÀnk
●

Dag: 13
SprÄk: Scala

object Day13 { val data = readLines("13/data.txt") val parts = data.splitBetween((_, s) => s.isEmpty) val dots = parts.head.map { case s"${int(x)},${int(y)}" => (x, y) } .toSet val folds = parts.last def flip(v: Int, axis: Int) = if(v > axis) axis * 2 - v else v def fold(dots: Set[(Int, Int)], instruction: String) = instruction match { case s"fold along x=${int(col)}" => dots.map { case (x, y) => (flip(x, col), y) } case s"fold along y=${int(row)}" => dots.map { case (x, y) => (x, flip(y, row)) } } def main(args: Array[String]): Unit = { // part 1 println(fold(dots, folds.head).size) // part 2 var tDots = dots folds.foreach { instruction => tDots = fold(tDots, instruction) } val maxX = tDots.map(_._1).max val maxY = tDots.map(_._2).max for(y <- 0 to maxY) { val chars = Array.fill[Char](maxX + 1)(' ') tDots.filter(_._2 == y).map(_._1).foreach(x => chars(x) = '#') println(new String(chars)) } } }

Dold text
PermalÀnk
Medlem ★
●

Dag: 13
SprÄk: Python

import numpy as np import re coords0, folds0 = open("input13").read().split("\n\n") coords = [[int(i) for i in s.split(",")] for s in coords0.split("\n")] folds = re.findall("([xy])=(\d+)", folds0) mx, my = map(np.array, zip(*coords)) dims = (next(int(value) * 2 + 1 for axis, value in folds if axis == 'x'), next(int(value) * 2 + 1 for axis, value in folds if axis == 'y')) a = np.full(dims, False) a[(mx, my)] = True def x(a, z): return a[:z,:] | np.flip(a, axis = 0)[:z,:] def y(a, z): return a[:,:z] | np.flip(a, axis = 1)[:,:z] for f, v in folds: a = eval(f)(a, int(v)) for line in a.T: print("".join([" *"[int(i)] for i in line]))

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

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

Jag har svÄrt för det hÀr med rekursion. Jag ser ju direkt att en uppgift som denna lÀmpar sig vÀldigt vÀl för en rekursiv DFS, men trots det sitter jag lÀÀÀÀnge och försöker göra en iterativ variant. Tillslut fick jag ge upp och ge mig ut pÄ rekursionsjakt pÄ Internet. Aja. TillrÀckligt mÄnga sÄdana hÀr uppgifter sÄ kanske jag ger med mig och lÀr mig gilla rekursion.

Dold text

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
Skrivet av Ingetledigtnamn:

Dag: 13
SprÄk: Python

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
Visa signatur

:(){ :|:& };:

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

PermalÀnk
Medlem
●

Dag: 13
SprÄk: C#

internal class Puzzle13 : Puzzle<int, string> { public record Instruction(int FoldAt, bool FoldUp); protected override void Solve(string[] lines) { var coords = lines .TakeWhile(x => !string.IsNullOrWhiteSpace(x)) .Select(x => x.Split(',').Select(int.Parse).ToArray()) .Select(c => (x: c[0], y: c[1])) .ToList(); var grid = new bool[coords.Max(x => x.x) + 1, coords.Max(y => y.y) + 1]; foreach (var (x, y) in coords) { grid[x, y] = true; } var instructions = lines[(coords.Count + 1)..] .Select(x => new Instruction(int.Parse(x[(x.IndexOf("=") + 1)..]), x.Contains('y'))) .ToList(); var newGrid = Fold(grid, instructions[0]); One = Grid.Iterate(newGrid).Count(x => newGrid[x.x, x.y]); var finalGrid = instructions.Aggregate(grid, (a, b) => Fold(a, b)); var sb = new StringBuilder(Environment.NewLine); for (var y = 0; y < finalGrid.GetLength(1); y++) { for (var x = 0; x < finalGrid.GetLength(0); x++) { sb.Append(finalGrid[x, y] ? '#' : '.'); } sb.AppendLine(); } Two = sb.ToString(); } private static bool[,] Fold(bool[,] grid, Instruction foldInstruction) { bool[,] newGrid; if (foldInstruction.FoldUp) { newGrid = new bool[grid.GetLength(0), grid.GetLength(1) / 2]; foreach (var (x,y) in Grid.Iterate(grid).Where(c => grid[c.x, c.y])) { newGrid[x, y < foldInstruction.FoldAt ? y : (2 * foldInstruction.FoldAt - y)] = true; } } else { newGrid = new bool[grid.GetLength(0) / 2, grid.GetLength(1)]; foreach (var (x, y) in Grid.Iterate(grid).Where(c => grid[c.x, c.y])) { newGrid[x < foldInstruction.FoldAt ? x : (2 * foldInstruction.FoldAt - x), y] = true; } } return newGrid; } }

Dold text
PermalÀnk
Hedersmedlem ★
●

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

2.8 ms att lösa, 4.8 ms inkl console.log-raderna.

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: C++

Ganska lÀtt (jÀmfört med tidigare dagar) men roligt.

struct manual { set<pair<int,int>> dots; vector<pair<bool,int>> folds; pair<int,int> grid_size; bool folded = false; }; manual parse(vector<string> str_data) { manual data; int n_rows = str_data.size(); string regex_str = "^([0-9]+),([0-9]+)$"; regex regex_obj(regex_str); smatch matches; int row = 0; while (!str_data[row].empty()) { regex_search(str_data[row], matches, regex_obj); data.dots.insert(make_pair(stoi(matches.str(1)),stoi(matches.str(2)))); row++; } regex_obj.assign("(\\w)=([0-9]+)$"); bool fold_x; int fold_nr = 0; while (row < n_rows) { if (str_data[row].empty()) { row++; continue; } regex_search(str_data[row], matches, regex_obj); fold_x = (matches.str(1)=="x")? 1:0; data.folds.push_back(make_pair(fold_x,stoi(matches.str(2)))); row++; } return data; } void draw(manual f_manual) { set<pair<int,int>>::iterator it; vector<vector<char>> frame(f_manual.grid_size.second, vector<char>(f_manual.grid_size.first,'.')); for (it = f_manual.dots.begin(); it != f_manual.dots.end(); ++it) { frame[(*it).second][(*it).first] = '#'; } for (int i = 0; i < f_manual.grid_size.second; i++) { for (int j = 0; j < f_manual.grid_size.first; j++) { cout << frame[i][j]; } cout << endl; } cout << endl; } int solve(manual &man, bool part2 = false) { set<pair<int,int>> new_dots;; set<pair<int,int>>::iterator dot_it; int x, y, fold_val, n_dots; int n_folds = man.folds.size(); for (int i = 0; i < n_folds; i++) { man.folded = true; fold_val = man.folds[i].second; new_dots.clear(); for (dot_it = man.dots.begin(); dot_it != man.dots.end(); ++dot_it) { x = get<0>(*dot_it); y = get<1>(*dot_it); switch (man.folds[i].first) { case true: x = (x > fold_val)? 2*fold_val-x : x; man.grid_size.first = fold_val; break; case false: y = (y > fold_val)? 2*fold_val-y : y; man.grid_size.second = fold_val; break; } new_dots.insert(make_pair(x,y)); } man.dots = new_dots; if (!part2) return new_dots.size(); } draw(man); return 0; }

Dold text
PermalÀnk
Medlem ★
●

PÄ dag 13 del 2, Àr det tÀnkte att man ska rita ut bokstÀverna? Jag försökte det men det ser inte ut som bokstÀver direkt

###..#....###...##....##..##..#....#.. #..#.#....#..#.#..#....#.#..#.#....#.. #..#.#....###..#.......#.#....#....#.. ###..#....#..#.#.......#.#.##.#....#.. #.#..#....#..#.#..#.#..#.#..#.#....#..

PermalÀnk
Hedersmedlem ★
●

@Gorgonzola Àr du sÀker pÄ att all kod stÀmmer? Mina ser mer ut som bokstÀver. (Lösningen beror ju pÄ varje anvÀndares data, sÄ vi lÀr inte ha samma bokstÀver i svaret.)
Ser dels ut som att du saknar den sista raden.

Day 13 Part 2: #### ### # ## ### # # # ### # # # # # # # # # # # # # ### # # # # # # # # # # # # ### # # ## ### # # # ### # # # # # # # # # # # # #### # #### ### # # ## #### # #

Valde att ha mellanslag istÀllet för punkter dÄ det blev lÀttare att lÀsa sÄ.

Dold text
Visa signatur

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

PermalÀnk
Medlem ★
●
Skrivet av Gorgonzola:

PÄ dag 13 del 2, Àr det tÀnkte att man ska rita ut bokstÀverna? Jag försökte det men det ser inte ut som bokstÀver direkt

###..#....###...##....##..##..#....#.. #..#.#....#..#.#..#....#.#..#.#....#.. #..#.#....###..#.......#.#....#....#.. ###..#....#..#.#.......#.#.##.#....#.. #.#..#....#..#.#..#.#..#.#..#.#....#..

Ja - du ska skriva ut outputen och sen tolka vilka bokstÀver som visas. Jag tror du har gjort nÄgot galet i din kod, för jag kan inte lÀsa 8 bokstÀver

Tips

Din output Àr 5 tecken hög. Jag tror den ska vara 6 tecken hög för alla input.

Dold text
Visa signatur

:(){ :|:& };:

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

PermalÀnk
Medlem ★
●

sprÄk: 13
dag: c#

Kod:

var dots = new HashSet<(int, int)>(); int pt1 = 0; bool pt1get = true; using (var sr = new StreamReader("input.txt")) { // add dots to grid while (!sr.EndOfStream) { var line = sr.ReadLine()!; // fold instructions begin after an empty line if (string.IsNullOrWhiteSpace(line)) break; var split = line.Split(",").Select(int.Parse); dots.Add((split.First(), split.Last())); } // fold while (!sr.EndOfStream) { var line = sr.ReadLine()!; var instruction = line.Substring(line.IndexOf('=') - 1).Split('='); switch (instruction.First()) { case "x": dots = fold_x(int.Parse(instruction.Last())); break; case "y": dots = fold_y(int.Parse(instruction.Last())); break; default: break; } if (pt1get) { pt1 = dots.Count; pt1get = false; } } HashSet<(int, int)> fold_x(int value) { Console.WriteLine("Folding on x at " + value); HashSet<(int, int)> fold = new HashSet<(int, int)>(); foreach (var dot in dots) { if (dot.Item1 > value) fold.Add((Math.Abs(dot.Item1 - (2 * value) ), dot.Item2)); else fold.Add(dot); } return fold; } HashSet<(int, int)> fold_y(int value) { HashSet<(int, int)> fold = new HashSet<(int, int)>(); foreach (var dot in dots) { if (dot.Item2 > value) fold.Add((dot.Item1, Math.Abs(dot.Item2 - (2 * value) ))); else fold.Add(dot); } return fold; } } Console.WriteLine("Part 1 " + pt1); Console.WriteLine("Part 2 :"); visualise_grid(dots); void visualise_grid(HashSet<(int, int)> grid) { Console.WriteLine(); for (int y = 0; y < grid.Select(a => a.Item2).Max() +1 ; y++) { for (int x = 0; x < grid.Select(a => a.Item1).Max() +1; x++) { if (grid.Contains((x, y))) { Console.Write("#"); } else { Console.Write(" "); } } Console.WriteLine(); } }

Dold text

Kommentarer

KÀndes ÀndÄ najs att jag redan skrivit koden för att visualisera rutnÀtet nÀr jag ÀndÄ felsökte dag 1 (fick fel svar hela tiden, hade missat att jag ju la till en egen punkt för att testa och sen glömt ta bort den). Utöver det var det vÀl mest att komma pÄ att köra absolutvÀrdet pÄ (x_eller_y - 2 * vikvÀrdet), men det gav sig ju ÀndÄ hyfsat fort nÀr jag ritat och tÀnkt lite.

Sedan var jag vÀl i och för sig tvungen att rÀtta en off-by-one i utskriften för del 2, sÄ det blev lite enklare att tolka bokstÀverna, men men.

Edit: Och som vanligt ska man försöka lÀsa instruktionerna ocksÄ, jag försökte ge svaret med helt fÀrdigvikt tills jag sÄg att det bara var en vikning som skulle göras för del 1...

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

Har du lagt ut koden nÄgonstans?
LÄter sanslöst snabbt om du kör samma kod som mig (skapa alla permutationer av abcdefg, "översÀtt" alla segment med alla permutationer och testa om de Àr giltiga). C Àr ju snabbare Àn TypeScript förstÄs, men det borde inte vara sÄn skillnad.

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Ä.

#include <stdio.h> #include <unistd.h> #include <string.h> /* read input from stdin */ int charmap[11]; char inputline[14][100]; static int m[7]; static short transmap[5042][7]; int mapseg(char *buf) { int i; int map; map = 0; i = 0; while(buf[i] != '\000') { if ((buf[i] < 'a') || (buf[i] > 'g')) { printf("invalid string: %s \n", buf); _exit(-1); } map |= 1 << (buf[i++] - 'a'); } return(map); } void map_setup() { charmap[0] = mapseg("abcefg"); charmap[1] = mapseg("cf"); charmap[2] = mapseg("acdeg"); charmap[3] = mapseg("acdfg"); charmap[4] = mapseg("bcdf"); charmap[5] = mapseg("abdfg"); charmap[6] = mapseg("abdefg"); charmap[7] = mapseg("acf"); charmap[8] = mapseg("abcdefg"); charmap[9] = mapseg("abcdfg"); charmap[10] = -1; } /* return 1 if pattern is a valid 7 seg digit */ int isvalid(char *buf) { int i, digit; digit = mapseg(buf); for (i = 0; i < 10; i++) { if (charmap[i] == digit) return(1); } return(0); } int seg_to_dig(char *buf) { int i, digit; digit = mapseg(buf); for (i = 0; i < 10; i++) { if (charmap[i] == digit) return(i); } return(-1); } int read_ln() { int i, j; char dummy[100]; for (i = 0; i < 10; i++) j = scanf("%s ", inputline[i]); j = scanf("%s ", dummy); for (i = 10; i < 14; i++) j = scanf("%s ", inputline[i]); return(j); } void remap_dig(char *instring, short *transbuf, char *outstring) { int i; i = 0; while(instring[i] != '\000') { if ((instring[i] < 'a') || (instring[i] > 'g')) { printf("remap_dig: invalid string: %s \n", instring); _exit(-1); } outstring[i] = transbuf[instring[i]-'a']+'a'; i++; } outstring[i] = '\000'; } int tmap_inc() { int i; for (i = 6; i >= 0; i--) { if (m[i] < 6) { m[i] += 1; return 0; } else { m[i] = 0; } } return -1; } int tmap_check() { int i, j; for (i = 0; i < 7; i++) { for (j = i+1; j < 7; j++) { if (m[i] == m[j]) return 0; } } return 1; } int tmap_next() { int i; i = 0; while (i == 0) { i = tmap_inc(); if (i < 0) return(-1); i = tmap_check(); if (i) return(1); } return 0; } int tmap_ini() { int i, j; int mapidx; for (i = 0; i < 7; i++) m[i] = 0; mapidx = 0; i = 1; while (i > 0) { i = tmap_next(); if (i > 0) { for (j = 0; j < 7; j++) transmap[mapidx][j] = m[j]; mapidx++; } } for (j = 0; j < 7; j++) transmap[mapidx][j] = -1; return (mapidx); } int main() { int i, j, k; char buffer[32767]; int maxmap, mapno; int number, numbersum; map_setup(); maxmap = tmap_ini(); printf("generated %d segement mappings\n", maxmap); numbersum = 0; i = 1; while (i == 1) { i = read_ln(); if (i == 1) { for (mapno = 0; mapno < maxmap; mapno++) { j = 1; for (k = 0; k < 14; k++) { remap_dig(inputline[k], transmap[mapno], buffer); j &= isvalid(buffer); if (j == 0) break; } if (j == 1) break; } number = 0; for (k = 10; k < 14; k++) { remap_dig(inputline[k], transmap[mapno], buffer); j = seg_to_dig(buffer); number = number * 10 + j; } numbersum += number; } } printf("sum of all numbers: %d \n", numbersum); return 0; }

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

@Gorgonzola Àr du sÀker pÄ att all kod stÀmmer? Mina ser mer ut som bokstÀver. (Lösningen beror ju pÄ varje anvÀndares data, sÄ vi lÀr inte ha samma bokstÀver i svaret.)
Ser dels ut som att du saknar den sista raden.

Day 13 Part 2: #### ### # ## ### # # # ### # # # # # # # # # # # # # ### # # # # # # # # # # # # ### # # ## ### # # # ### # # # # # # # # # # # # #### # #### ### # # ## #### # #

Valde att ha mellanslag istÀllet för punkter dÄ det blev lÀttare att lÀsa sÄ.

Dold text
Skrivet av GLaDER:

Ja - du ska skriva ut outputen och sen tolka vilka bokstÀver som visas. Jag tror du har gjort nÄgot galet i din kod, för jag kan inte lÀsa 8 bokstÀver

Tips

Din output Àr 5 tecken hög. Jag tror den ska vara 6 tecken hög för alla input.

Dold text

Jag hade 0<height och 0<width istÀllet för 0<=height 0<=width nÀr jag printade