🌟 Advent of Code (AoC) 2024 🌟

PermalÀnk
Medlem ★
●
Skrivet av Yoshman:

HÀr Àr ett exempel nÀr körtiden, som jag gissar du mÀtte med "Stopwatch"?, inte alls blir rÀtt. Det Àr betydligt snabbare om man tar bort "warmup". .NET verkar ha lÄngt kortare warmup jÀmfört med typiska JVM:er, redan körningen av part 2 verkar vara "ljummen" dÄ det rimligen borde ta lÀngre tid Àn part 1.

Kör man i en loop fÄr jag ca 90”s i del 1 och ca 310”s i del 2 med din lösning pÄ en M3 och .NET core 8.

I första varvet fÄr man ~5ms och 1ms pÄ samma dator...

Det Àr en 0a som fattas i körning nr 2.. det ska sÄklart stÄ 10ms
Körningarnas tid noteras separat, alltsÄ en uppgift Ät gÄngen (kommenterar ut del 1 och 2 beroende pÄ vilken som körs)

var sw = new Stopwatch(); sw.Start(); var input = System.IO.File.ReadAllText("input.txt"); /*var partOneResult = Solver.Run_PartOne(input); sw.Stop(); Console.WriteLine($"{partOneResult} in {sw.ElapsedMilliseconds} ms");*/ sw.Restart(); var partTwoResult = Solver.Run_PartTwo(input); sw.Stop(); Console.WriteLine($"{partTwoResult} in {sw.ElapsedMilliseconds} ms");

Visa signatur

NZXT H510 Flow MSI B450 Tomahawk MAX
AMD Ryzen 5800X3D RX 7900XTX Kingston Fury 64GB
LG C2 42" 4K@120Hz AOC Q27G2U 1440P@144Hz

PermalÀnk
Medlem ★
●

Dag 7 Del 1 Endast !!! (Del 2 kan dra ... eller jag provar vĂ€l dĂ„ kanske...?đŸ€Ł)
PHP via "Code Runner" Extension i VSCode Terminal

7. php - Dag 7 Del 1 Endast Del !!!

<?php $data = "https://adventofcode.com/2024/day/7/input"; $lines = array_map('rtrim', explode("\n", $data)); foreach ($lines as $key => $line) { $lines[$key] = explode(": ", $line); } $operators = ["+", "*"]; $sumOfValidCalculations = 0; foreach ($lines as $line) { $line[1] = explode(" ", $line[1]); $line[1] = array_map('intval', $line[1]); $intVal = intval($line[0]); $line[0] = array_map('intval', str_split($line[0])); $testGeneratedCombinations = generateCombinations($operators, count($line[1]) - 1, true); foreach ($testGeneratedCombinations as $testGeneratedCombination) { $testString = insertValuesBetweenOtherValues($testGeneratedCombination, $line[1]); echo "Testing string: " . $testString . "\n"; $result = calcFromLeftToRightPerOperatorInString($testString); if ($result === $intVal) { echo "Result: " . $result . " = " . $intVal . " | Adding to sum!\n"; $sumOfValidCalculations += $result; break; } } } echo "Part 1: " . $sumOfValidCalculations; ?>

_helpers.php - relevanta för just Dag 7 Del 1 Endast !!!

function calcFromLeftToRightPerOperatorInString($stringToCalc) { if (!preg_match('/^[\d\+\-\*\/]+$/', $stringToCalc)) { return "calcFromLeftToRightPerOperatorInString(): Valid Math String is: \d+ and/or +, -, *, /"; } $numbers = preg_split('/[\+\-\*\/]/', $stringToCalc); $operators = preg_split('/[\d]+/', $stringToCalc, -1, PREG_SPLIT_NO_EMPTY); $result = $numbers[0]; for ($i = 0; $i < count($numbers) - 1; $i++) { switch ($operators[$i]) { case "+": $result += $numbers[$i + 1]; break; case "-": $result -= $numbers[$i + 1]; break; case "*": $result *= $numbers[$i + 1]; break; case "/": $result /= $numbers[$i + 1]; break; default: return "calcFromLeftToRightPerOperatorInString(): Invalid operator found."; } } echo "Result for testing $stringToCalc: $result\n"; return $result; } function generateCombinations($arrayValues, $numberOfPlaces, $returnAsArray = false) { if (!is_array($arrayValues)) { throw new Exception("(generateCombinations): First parameter must be an array."); } if (!is_int($numberOfPlaces)) { throw new Exception("(generateCombinations): Second parameter must be an integer."); } $totalCombinations = pow(count($arrayValues), $numberOfPlaces); for ($i = 0; $i < $totalCombinations; $i++) { $combination = ""; for ($j = 0; $j < $numberOfPlaces; $j++) { // We add the index of the arrayValues which is the floor of // the current index divided by the count of the arrayValues // which is then modulo the count of the arrayValues. This works // because the index will always be a multiple of the count of the // arrayValues, and then we just divide by the count of the arrayValues // to get the correct index of the arrayValues. // SÄKERT chatGPT, SÄKERT... $combination .= $arrayValues[floor($i / pow(count($arrayValues), $j)) % count($arrayValues)]; } if ($returnAsArray) { yield str_split($combination); } else { yield $combination; } } } function insertValuesBetweenOtherValues($arrayReplaceValues, $arrayOtherValues) { if (!is_array($arrayReplaceValues) || !is_array($arrayOtherValues)) { throw new Exception("(insertValuesBetweenOtherValues) :Both parameters must be arrays."); } if (count($arrayReplaceValues) >= count($arrayOtherValues)) { throw new Exception("(insertValuesBetweenOtherValues) :First array must have one element fewer than the second array."); } $result = ""; for ($i = 0; $i < count($arrayOtherValues); $i++) { $result .= $arrayOtherValues[$i]; if ($i < count($arrayReplaceValues)) { $result .= $arrayReplaceValues[$i]; } } return $result; }

Dold text

Det sĂ€ger jag dĂ„ bara: chatGPT4o gratis Ă€r riktigt ja... En hel del smĂ„fel hĂ€r och var (ibland pga. avsaknaden av uppenbara saker). Men jovars, visst ska "A.I." ersĂ€tta oss alla snart.😂

Dock har jag ingen aning alls över varför just detta gör att kombinationsfunktionen fungerar som den ska:

// Jag ser att den inuti index för $arrayValues nyttjar floor() och vill dela nÄgot index med // upphöjningen av antalet av $arrayvalues och sedan modulus av antalet $arrayValues. // HÀr Àr det nÄgot matematiskt som jag inte riktigt förstÄr mig pÄ. Men funkar gör det! $combination .= $arrayValues[floor($i / pow(count($arrayValues), $j)) % count($arrayValues)]; // Ok, vad jag ser Àr att kombinationsantalet Àr exponentprodukten // som den vill dela och jÀmna ut utifrÄn. NÄgot Ät det hÄllet, mÄ tro?

Dold text

För övrigt Àr jag riktigt nöjd över min allra första generator skriven i PHP:

Dold text

Mvh,
WKF.

Visa signatur

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

PermalÀnk
Medlem ★
●

Dag 7 Del 2 Endast !!!đŸ€ŻđŸ€ŻđŸ€Ż
PHP via "Code Runner" Extension i VSCode Terminal

Det som tog lĂ€ngst tid var att köra det i VSCode Terminalen vilket verkar ha att göra med concatenation som nĂ„gon nĂ€mnde?đŸ€”

7.php + _helpers.php men endast Dag 7 Del 2-lösningen
och den nya varianten av funktionen i _helpers.php:

<?php // // Part 2: First prepare values with fresh values $data = "https://adventofcode.com/2024/day/7/input"; $lines2 = array_map('rtrim', explode("\n", $data)); foreach ($lines2 as $key => $line2) { $lines2[$key] = explode(": ", $line2); } $operators = ["+", "*", "|"]; $sumOfValidCalculations = 0; foreach ($lines2 as $line2) { // Split and convert to an array of integers $line2[1] = explode(" ", $line2[1]); $line2[1] = array_map('intval', $line2[1]); $intVal = intval($line2[0]); $line2[0] = array_map('intval', str_split($line2[0])); $testGeneratedCombinations = generateCombinations($operators, count($line2[1]) - 1, true); foreach ($testGeneratedCombinations as $testGeneratedCombination) { $testString = insertValuesBetweenOtherValues($testGeneratedCombination, $line2[1]); $result = calcFromLeftToRightPerOperatorInString($testString); if ($result === $intVal) { $sumOfValidCalculations += $result; echo "Result: " . $result . " = " . $intVal . " | Adding to sum! | Sum so far: $sumOfValidCalculations \n"; break; } else { echo "Result: " . $result . " != " . $intVal . " | Skipping! | Sum so far: $sumOfValidCalculations \n"; } } } echo "Part 2: " . $sumOfValidCalculations; // From: _helpers.php function calcFromLeftToRightPerOperatorInString($stringToCalc) { if (!preg_match('/^[\d\+\-\*\/\|]+$/', $stringToCalc)) { return "calcFromLeftToRightPerOperatorInString(): Valid Math String is: \d+ and/or +, -, *, /, or |"; } $numbers = preg_split('/[\+\-\*\/\|]/', $stringToCalc); $operators = preg_split('/[\d]+/', $stringToCalc, -1, PREG_SPLIT_NO_EMPTY); $result = $numbers[0]; for ($i = 0; $i < count($numbers) - 1; $i++) { switch ($operators[$i]) { case "+": $result = intval($result); $result += $numbers[$i + 1]; break; case "-": $result = intval($result); $result -= $numbers[$i + 1]; break; case "*": $result = intval($result); $result *= $numbers[$i + 1]; break; case "/": $result = intval($result); $result /= $numbers[$i + 1]; break; case "|": $result = (string)$result . (string)$numbers[$i + 1]; $result = intval($result); break; default: return "calcFromLeftToRightPerOperatorInString(): Invalid operator found."; } } echo "Calculated from Left->Right: $stringToCalc = $result\n"; return $result; }

Dold text

Lösningen var lustigt nog inte sÄ komplicerad trots allt förutom att jag först gjorde pÄ ett sÀtt som gjorde att allt allt klassades rÀtt vilket inte var sÄ rÀtt trots allt!

I princip sju kodradsförĂ€ndringar (fyra tillagda). Ju fler `echo` jag hade, desto lĂ€ngre tid tog det att ens se om jag hade gjort rĂ€tt eller fel i slutĂ€ndan!đŸ„Č

(Jag testkörde ocksÄ bara Del 1 igen för att se sÄ att kodradsÀndringarna fortfarande fungerade för del 1 med - det gjorde dem! )

Mvh,
WKF.

Visa signatur

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

PermalÀnk
Medlem ★
●

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

package main

import (
"fmt"
"log"
"math"
"os"
"strconv"
"strings"
)

type Equation struct {
Result int
Numbers []int
}

// Determine the math operator by the result. Examples:
//
// 190: 10 19 # 10 * 19
// 3267: 81 40 27 # 81 + 40 * 27
// 161011: 16 10 13 # Invalid
//
// Operators are read left to right, not according to predecence rules
// Not all equations are possible.
// Print the total calibration amount, which is the sum of the test values
// produced by valid equations
func main() {

input, err := os.ReadFile("input")
if err != nil {
log.Fatal(err)
}
equations := getEquations(string(input))

var total int
for _, e := range equations {
operatorCombinations := generateOperatorCombinations(e.Numbers)
for _, operator := range operatorCombinations {
if validEquationOperator(e.Numbers, e.Result, operator) {
total += e.Result
break
}
}
}
fmt.Println(total)
}

// A three-number equation require two operators. In that case, we have a total of
// nine possible operator combinations: ++, +*, +|, *+, **, *|, ||, |+, |*.
// We use ternary (base 3) to generate all operator combinations,
// We replace 0 with +, 1 with * and 2 with |.
func generateOperatorCombinations(numbers []int) []string {

totalOperators := len(numbers) - 1
possibleCombinations := int(math.Pow(3, float64(totalOperators)))
operatorCombinations := make([]string, 0, possibleCombinations)

for c := 0; c < possibleCombinations; c++ {

cToTernaryAsString := string(strconv.FormatInt(int64(c), 3))
// Pad string to make it into a "binary" format
for len(cToTernaryAsString) < totalOperators {
cToTernaryAsString = "0" + cToTernaryAsString
}
var operators string
operators = strings.ReplaceAll(cToTernaryAsString, "1", "*")
operators = strings.ReplaceAll(operators, "0", "+")
operators = strings.ReplaceAll(operators, "2", "|")
operatorCombinations = append(operatorCombinations, operators)
}
return operatorCombinations
}

func validEquationOperator(numbers []int, expectedResult int, operators string) bool {

total := numbers[0]
for i := 0; i < len(numbers)-1; i++ {

operator := string(operators[i])
if operator == "+" {
// fmt.Printf("%d + %d", total, numbers[i+1])
total += numbers[i+1]
} else if operator == "*" {
// fmt.Printf("%d x %d", total, numbers[i+1])
total *= numbers[i+1]
} else if operator == "|" {
// fmt.Printf("%d | %d", total, numbers[i+1])
concatenation := strconv.Itoa(total) + strconv.Itoa(numbers[i+1])
concatAsInt, err := strconv.Atoi(concatenation)
if err != nil {
log.Fatal(err)
}
total = concatAsInt
}
// fmt.Printf(" = %d\n", total)
}
return total == expectedResult
}

func getEquations(input string) []Equation {

inputLines := strings.Split(string(input), "\r\n")
equations := make([]Equation, 0, len(inputLines))

for _, line := range inputLines {
lineSplitByColon := strings.Split(line, ": ")
result, err := strconv.Atoi(lineSplitByColon[0])
if err != nil {
log.Fatal(err)
}
numbers := lineSplitByColon[1]

equation := Equation{Result: result, Numbers: make([]int, 0, len(numbers))}
for _, number := range strings.Split(numbers, " ") {
numberAsInt, err := strconv.Atoi(number)
if err != nil {
log.Fatal(err)
}
equation.Numbers = append(equation.Numbers, numberAsInt)
}
equations = append(equations, equation)
}
return equations

}

Dold text
Visa signatur

CCNP
FCSS

PermalÀnk
Medlem ★
●
Skrivet av jclr:

Jag förstÄr fortfarande inte hur man skulle kunna göra del tvÄ om man inte har en rapport som man sprider ut alla kombinationer av över ett register?

Dold text

Det tog lite tid. Livet kom i vÀgen.

Uppgiften Àr inte ideal för SIMD. Det blir lite för mÄnga specialfall som mÄste hanteras; olika lÀngder pÄ rapporterna och att antalet rapporter inte stÀmmer med vektorlÀngden. Men hÀr fÄr du i alla fall ett hemskt exempel hur man kan sprida ut rapporterna i flera olika register och operera pÄ 64 olika samtidigt.

Dold text
PermalÀnk
Medlem
●

Dag: 8
SprÄk: C#

Lite trött pÄ söndagskvÀllen sÄ postar ostÀdad kod för lösningen av del2.
OvÀntat liten input idag. Undrar hur lÄng tid det tagit med penna och papper? 50 us utan I/O, 350 us med.

public static int BenchPart2() { StreamReader reader = new StreamReader(_dataLocation); string[] lines = File.ReadAllLines(_dataLocation); Dictionary<char, HashSet<(int, int)>> antennaDictionary = new Dictionary<char, HashSet<(int, int)>>(); char[,] array = new char[lines.Length, lines[0].Length]; HashSet<(int, int)> hits = new HashSet<(int, int)>(); for (int i = 0; i < array.GetLength(0); i++) { for (int j = 0; j < array.GetLength(1); j++) { char c = lines[i][j]; array[i, j] = c; if(c == '.') continue; if (antennaDictionary.TryGetValue(c, out var chars)) { chars.Add((i, j)); } else { antennaDictionary.Add(c, [(i, j)]); } } } foreach (var c in antennaDictionary.Keys) { var antennas = antennaDictionary[c].ToList(); for (int i = 0; i < antennas.Count-1; i++) { var first = antennas[i]; for (int j = i + 1; j < antennas.Count; j++) { var second = antennas[j]; var diff = ((first.Item1 - second.Item1), ((first.Item2 - second.Item2))); var val1 = second; var val2 = first; while (true) { val1 = (val1.Item1 + diff.Item1, val1.Item2 + diff.Item2); if ((val1.Item1 < 0 || val1.Item2 < 0 || val1.Item1 >= array.GetLength(0) || val1.Item2 >= array.GetLength(1))) break; hits.Add(val1); } while (true) { val2 = (val2.Item1 - diff.Item1, val2.Item2 - diff.Item2); if ((val2.Item1 < 0 || val2.Item2 < 0 || val2.Item1 >= array.GetLength(0) || val2.Item2 >= array.GetLength(1))) break; hits.Add(val2); } } } } return hits.Count; }

Dold text
PermalÀnk
Medlem ★
●

Dag: 9
SprÄk: C#
Dag 9

Del 1: ~2.6ms
Del 2: ~260ms
(MÀtt med loop enligt det förslag @Yoshman gav tidigare för att inte mÀta warmup-tiden )

Kan tillÀgga att det Àven Àr bra om man kör i Release och inte Debug vid mÀtning av tid..

public class Solver { private struct File(int id, int index, bool isEmpty) { public int Id { get; set; } = id; public int Index { get; set; } = index; public bool IsEmpty { get; set; } = isEmpty; public long Checksum => Id * Index; } public static long Run_PartOne(string input) { // Parse string var numbers = input.Select(c => int.Parse(c.ToString())).ToList(); // Generate filestructure List<File> files = new List<File>(); for (int i = 0; i < numbers.Count; i++) { var count = numbers[i]; for (int j = 0; j < count; j++) { files.Add(new File(i / 2, i, i % 2 != 0)); } } // Rearrange files bool isDone = false; int startIndex = 0; for (int i = files.Count - 1; i > 0 && !isDone; i--) { var fileA = files[i]; if (fileA.IsEmpty) continue; for (int j = startIndex; j < files.Count; j++) { var fileB = files[j]; if (!fileB.IsEmpty) continue; if (j > i) { isDone = true; break; } files[i] = new File(fileB.Id, i, fileB.IsEmpty); files[j] = new File(fileA.Id, j, fileA.IsEmpty); startIndex = j + 1; break; } if (isDone) break; } // Re-index files for (int i = 0; i < files.Count; i++) { files[i] = new File(files[i].Id, i, files[i].IsEmpty); } // Validate checksum return files.Sum(file => file.IsEmpty ? 0L : file.Checksum); } public static long Run_PartTwo(string input) { // Parse string var numbers = input.Select(c => int.Parse(c.ToString())).ToList(); // Generate filestructure List<File> files = new List<File>(); for (int i = 0; i < numbers.Count; i++) { var count = numbers[i]; for (int j = 0; j < count; j++) { files.Add(new File(i / 2, i, i % 2 != 0)); } } // Rearrange files for (int i = files.Count - 1; i > 0; i--) { var fileA = files[i]; if (fileA.IsEmpty) { continue; } // Get size for files var numberOfFiles = 0; for (int j = i; j > 0; j--) { if (files[j].Id != fileA.Id) { break; } numberOfFiles++; } // Make sure files fit bool fileFits = false; int fitIndex = 0; for (int j = 0; j < files.Count && j < i; j++) { if (!files[j].IsEmpty) continue; int emptyFileCount = 1; for (var k = j + 1; k < numberOfFiles + j && k < files.Count; k++) { if (!files[k].IsEmpty) { break; } emptyFileCount++; if (emptyFileCount == numberOfFiles) break; } if (emptyFileCount != numberOfFiles) { j += emptyFileCount - 1; continue; } fileFits = true; fitIndex = j; break; } if (!fileFits) { i -= numberOfFiles - 1; continue; } // Move files int rightIndex = i; for (int j = fitIndex; j < fitIndex + numberOfFiles; j++) { var fileB = files[j]; files[rightIndex] = new File(fileB.Id, rightIndex, fileB.IsEmpty); files[j] = new File(fileA.Id, j, fileA.IsEmpty); rightIndex--; } i -= numberOfFiles - 1; } // Re-index files long sum = 0L; for (int i = 0; i < files.Count; i++) { files[i] = new File(files[i].Id, i, files[i].IsEmpty); if(files[i].IsEmpty) continue; sum += files[i].Checksum; } // Validate checksum return sum; } }

Dold text
Visa signatur

NZXT H510 Flow MSI B450 Tomahawk MAX
AMD Ryzen 5800X3D RX 7900XTX Kingston Fury 64GB
LG C2 42" 4K@120Hz AOC Q27G2U 1440P@144Hz

PermalÀnk
Medlem ★
●

Dag: 9
SprÄk: Python

place_file1 och 2 Àr ganska lika sÄ det kÀnns som att det skulle gÄ att bryta ut lite gemensam funktionalitet men det Àr smÄ skillnader pÄ i stort sett varje rad.

l= [int(digit) for digit in open("input09.txt", "r").read().strip()] def split_input(l): files, gaps = [], [] pos = 0 for i, digit in enumerate(l): if i % 2 == 0: files.append([pos, digit, i // 2]) else: if digit: gaps.append([pos, digit]) pos += digit return files, gaps, [] def place_file1(pos, size, id): while size and gaps and gaps[0][0] < pos: pos2, size2 = gaps.pop(0) msize = min(size, size2) compacted.append([pos2, msize, id]) size -= msize if size: files.append((pos, size, id)) pos2 += msize size2 -= msize if size2 > 0: gaps.insert(0, [pos2, size2]) return if size: compacted.append([pos, size, id]) def place_file2(pos, size, id): for i in range(len(gaps)): if gaps[i][0] < pos and gaps[i][1] >= size: pos2, size2 = gaps.pop(i) compacted.append([pos2, size, id]) pos2 += size size2 -= size if size2 > 0: gaps.insert(i, [pos2, size2]) return compacted.append([pos, size, id]) for f in [place_file1, place_file2]: files, gaps, compacted = split_input(l) while files: pos, size, id = files.pop() f(pos, size, id) print(sum([sum([x for x in range(pos, pos + n)]) * id for pos, n, id in compacted]))

Dold text
PermalÀnk
Medlem
●

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

...long.. not int :'|

PermalÀnk
Medlem ★
●

Dag 9, C#

Lösning: Inte sÄ snygg, men den fungerar - och det Àr ju minst lika viktigt.

var line = File.ReadAllText("input.txt"); (long sumpart1, long sumpart2) = (0, 0); bool file = true; int filecounter = 0; List<(int value, bool empty)> disklist = []; List<(int value, bool empty, int length)> disklist2 = []; for (int i = 0; i < line.Length; i++) { int sectorlength = line[i] & 15; if (file) { disklist2.Add((filecounter, false, sectorlength)); for (int x = 0; x < sectorlength; x++) { disklist.Add((filecounter, false)); } filecounter++; file = false; } else { disklist2.Add((0, true, sectorlength)); for (int x = 0; x < sectorlength; x++) { disklist.Add((0, true)); } file = true; } } var disk1 = disklist.ToArray(); int backwards = disk1.Length - 1; // part 1 for (int i = 0; i < disk1.Length; i++) { if (!disk1[i].empty) continue; while (backwards > i) if (disk1[backwards].empty) backwards--; else break; (disk1[i], disk1[backwards]) = (disk1[backwards], disk1[i]); } for (int i = 0; i < disk1.Length; ++i) { sumpart1 += i * disk1[i].value; } // part 2 List<(long value, bool empty, int length)> p2list = []; while (true) { var curr = disklist2.First(); if (!curr.empty) { p2list.Add(curr); disklist2.Remove(curr); } else // curr is empty { int length = curr.length; while (length > 0) { var last_matches = disklist2.Where(x => !x.empty && x.length <= length); if (last_matches.Count() == 0) break; var last_match = last_matches.Last(); length -= last_match.length; p2list.Add(last_match); var last_idx = disklist2.IndexOf(last_match); disklist2[last_idx] = (0, true, last_match.length); disklist2.Remove(last_match); } if (length > 0) { p2list.Add((0, true, length)); } disklist2.Remove(curr); } if (disklist2.Count == 0) break; } List<(long value, bool empty)> disk2 = []; foreach (var sektor in p2list) { for (int i = 0; i < sektor.length; i++) { disk2.Add((sektor.value, sektor.empty)); } } for (int i = 0; i < disk2.Count; ++i) { sumpart2 += i * disk2[i].value; } Console.WriteLine("Part 1: " + sumpart1); Console.WriteLine("Part 2: " + sumpart2);

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

Dag: 9
SprÄk: Rust

Del 1: 100”s (M3), 340”s (Orange Pi 5)
Del 2: 320”s (M3), 1,4ms (Orange Pi 5)

use std::array::from_fn; use std::cmp::Ordering; use std::collections::BinaryHeap; use std::fs; use std::iter::repeat; pub const INPUT_FILE: &str = "input.txt"; pub const FREE_BLOCK: Block = u16::MAX; pub type Block = u16; #[derive(Eq, PartialEq)] struct FreeRange { begin: usize, end: usize, } struct FreeBlocks { sizes: [BinaryHeap<FreeRange>; 10], } impl Ord for FreeRange { fn cmp(&self, other: &Self) -> Ordering { other.begin.cmp(&self.begin) } } impl PartialOrd for FreeRange { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { other.begin.partial_cmp(&self.begin) } } pub fn read_blocks(path: &str) -> Vec<Block> { let content = fs::read_to_string(path).expect("Failed to read file"); let mut blocks = Vec::new(); let mut id: Block = 0; for (offset, length_ch) in content.trim_ascii_end().chars().enumerate() { let length = length_ch.to_digit(10).unwrap() as usize; if offset % 2 == 0 { blocks.extend(repeat(id).take(length)); id += 1; } else { blocks.extend(repeat(FREE_BLOCK).take(length)); } } blocks } pub fn part1(blocks: &[Block]) -> usize { let mut compacted_blocks = blocks.to_vec(); let mut free_offset = 0; let next_free_offset = |offset: usize, bs: &[Block]| { let mut new_offset = offset; while bs[new_offset] != FREE_BLOCK { new_offset += 1; } new_offset }; let mut block_offset = compacted_blocks.len() - 1; let next_block_offset = |offset: usize, bs: &[Block]| { let mut new_offset = offset; while bs[new_offset] == FREE_BLOCK { new_offset -= 1; } new_offset }; loop { free_offset = next_free_offset(free_offset, &compacted_blocks); block_offset = next_block_offset(block_offset, &compacted_blocks); if free_offset > block_offset { break; } compacted_blocks.swap(free_offset, block_offset); } checksum(&compacted_blocks[0..free_offset]) } pub fn part2(blocks: &[Block]) -> usize { let mut compacted_blocks = blocks.to_vec(); let mut free_blocks = find_free_blocks(&compacted_blocks); let mut offset = compacted_blocks.len() - 1; let mut id = Block::MAX; loop { while compacted_blocks[offset] >= id { offset -= 1; } let last = offset; id = compacted_blocks[offset]; if id == 0 { break; } while compacted_blocks[offset] == id { offset -= 1; } let size = last - offset; if let Some(best_sz) = get_best_free_range_size(&free_blocks, offset, size) { let mut free_range = free_blocks.sizes[best_sz].pop().unwrap(); for i in 0..size { compacted_blocks.swap(free_range.begin + i, offset + 1 + i); } free_range.begin += size; if free_range.begin < free_range.end && free_range.begin < offset { free_blocks.sizes[free_range.end - free_range.begin].push(free_range); } } } checksum(&compacted_blocks) } fn get_best_free_range_size( free_blocks: &FreeBlocks, max_offset: usize, size: usize, ) -> Option<usize> { let mut best_sz = None; let mut best_offset = 0; for sz in size..free_blocks.sizes.len() { if !free_blocks.sizes[sz].is_empty() { let offset = free_blocks.sizes[sz].peek().unwrap().begin; if offset <= max_offset && (best_sz.is_none() || best_offset > offset) { best_sz = Some(sz); best_offset = offset; } } } best_sz } fn find_free_blocks(blocks: &[Block]) -> FreeBlocks { let mut sizes = from_fn(|_| BinaryHeap::new()); let mut offset = 0; while offset < blocks.len() { if blocks[offset] != FREE_BLOCK { offset += 1; continue; } let free_block_start = offset; loop { offset += 1; if blocks[offset] != FREE_BLOCK { break; } } let free_range = FreeRange { begin: free_block_start, end: offset, }; sizes[offset - free_block_start].push(free_range); } FreeBlocks { sizes } } fn checksum(blocks: &[Block]) -> usize { blocks .iter() .enumerate() .filter_map(|(offset, &id)| { if id == FREE_BLOCK { None } else { Some(offset * id as usize) } }) .sum() } fn main() { let blocks = read_blocks(&INPUT_FILE); println!("part 1: {}", part1(&blocks)); println!("part 2: {}", part2(&blocks)); }

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: 9
SprÄk: C#

Del 2, ca 35 ms. Gjorde Del 1 imorse och det blev indexering frÄn helvetet, sÄ den postar jag inte. Orkade inte heller fippla med det nu ikvÀll sÄ styrde upp det en aning i alla fall.

public static long Question2() { long sum = 0; string[] lines = File.ReadAllLines(_dataLocation); string line = lines[0]; List<Block> files = new List<Block>(); List<Block> emptySpace = new List<Block>(); int currentNumber = 0; for (int i = 0; i < line.Length; i++) { if (i % 2 == 0) { files.Add(new Block((int)line[i] - 48, currentNumber)); currentNumber++; } else { emptySpace.Add(new Block((int)line[i] - 48)); } } for (int i = files.Count - 1; i >= 0; i--) { var file = files[i]; for(int j = 0; j < i; j++) { var space = emptySpace[j]; if (space.FreeSpace < file.Size) continue; //add data and break loop space.Append(file.Data); file.Clear(); break; } } int position = 0; for (int i = 0; i < line.Length; i++) { int[] data; if (i % 2 == 0) { int index = i / 2; data = files[index].Data; } else { int index = (i / 2); data = emptySpace[index].Data; } for (int j = 0; j < data.Length; j++) { sum += position++ * data[j]; } } return sum; } private class Block { private int size = 0; public Block(int size, int number = -1) { this.size = size; Data = new int[size]; if (number >= 0) { FreeSpace = 0; for (int i = 0; i < size;i++) { Data[i] = number; } } else { FreeSpace = size; } } public int Size => Data.Length; public int[] Data { get; } public int FreeSpace { get; private set; } public override string ToString() { var sb = new StringBuilder(); for (int i = 0; i < size; i++) { var s = Data[i].ToString(); sb.Append(s); } sb.Append(" , fSpace = "); sb.Append(FreeSpace); return sb.ToString(); } public void Append(int[] fileData) { if (fileData.Length > FreeSpace) throw new AccessViolationException(); FreeSpace -= fileData.Length; int fileDataIndex = 0; for (int i = 0; i < Data.Length; i++) { if (Data[i] != 0) continue; Data[i] = fileData[fileDataIndex++]; if (fileDataIndex >= fileData.Length) return; } } public void Clear() { for (int i = 0; i < Data.Length; i++) { Data[i] = 0; } FreeSpace = size; } }

Dold text
PermalÀnk
Medlem ★
●

Dag: 10
SprÄk: Python

SÄg en presentation pÄ jobbet i gÄr om GitHub Copilot och de visade hur man kunde köra stegvis förfining för att till slut nÄ det mÄlet. TÀnkte jag skulle pröva, köra en @WebbkodsFrilansaren. Resultatet har lite annan stil Àn hur mina lösningar brukar se ut

Jag Àr ganska imponerad. PÄ det stora hela gick det bra. Det blev inte helt rÀtt nÀr jag bad om att filtrera redan besökta platser, sÄ det krÀvdes lite handpÄlÀggning innan vi fick rÀtt svar. Uppenbarligen var jag inte tillrÀckligt precis i mina önskemÄl för vi löste av misstag del 2 före del 1

import numpy as np filename = "input10.txt" # Read the file and create a 2D numpy array a = np.array([[int(c) for c in line.strip()] for line in open(filename, "r").readlines()]) print(a) # Pad the array with -1 all around padded_a = np.pad(a, pad_width=1, mode='constant', constant_values=-1) print(padded_a) # Define the find_path function (updated implementation) def find_path(position, peaks): x, y = position current_value = padded_a[x, y] next_value = current_value + 1 print(f"Finding path from position: {position}, current value: {current_value}") # If the current value is 9, return 1 if current_value == 9: peaks.add(position) return 1 # Mark the current position as visited # Check surrounding elements and sum the results of recursive calls total_paths = 0 for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]: new_x, new_y = x + dx, y + dy new_position = (new_x, new_y) if padded_a[new_x, new_y] == next_value: total_paths += find_path(new_position, peaks) return total_paths # Find the positions of all zeros in the array zero_positions = np.argwhere(padded_a == 0) # Iterate over the positions and call find_path with each position s1 = 0 s2 = 0 for pos in zero_positions: peaks = set() s2 += find_path(tuple(pos), peaks) s1 += len(peaks) print(f"Total paths: {s, s2}")

Dold text
Stavfel
PermalÀnk
Medlem ★
●

Alla jag diskuterat dagens problem med har löst del 2 innan del 1...
Och jag visste att folk gjorde det innan jag ens tittade pÄ det sjÀlv, och ÀndÄ gjorde jag det jag med. Men det innebar ju Ä andra sidan att det gick vÀldigt fort att gÄ frÄn en stjÀrna till tvÄ.

Dag 10, C#

using System.Diagnostics; using Position = (int x, int y); Stopwatch sw = Stopwatch.StartNew(); var lines = File.ReadAllLines("input.txt"); (int sumpart1, int sumpart2, int max) = (0, 0, lines.Length); Dictionary<Position, int> grid = []; List<Position> heads = []; for (int x = 0; x < max; x++) for (int y = 0; y < max; y++) { var val = lines[x][y] & 15; grid[(x, y)] = val; if (val == 0) heads.Add((x, y)); } foreach (var head in heads) { HashSet<Position> found = []; sumpart2 += ascend(grid, head, 0, max, found); sumpart1 += found.Count; } Console.WriteLine("Part 1: " + sumpart1); Console.WriteLine("Part 2: " + sumpart2); Console.WriteLine("Time: " + sw.Elapsed); IEnumerable<(int x, int y)> neighbours(Position pos, int max) { Position[] rel_pos = [(0, 1), (1, 0), (0, -1), (-1, 0)]; foreach (var rel in rel_pos) { var new_pos = (pos.x + rel.x, pos.y + rel.y); if (inRange(new_pos, max)) yield return new_pos; } yield break; } bool inRange(Position pos, int max) => (pos.x < max && pos.x >= 0 && pos.y < max && pos.y >= 0); int ascend(Dictionary<Position, int> grid, Position pos, int sought, int max, HashSet<Position> found) { var curr = grid[pos]; if (curr == sought) { if (sought == 9) { found.Add(pos); return 1; } int retval = 0; foreach (var neighbour in neighbours(pos, max)) retval += ascend(grid, neighbour, sought + 1, max, found); return retval; } else return 0; }

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

Dag: 10
SprÄk: Python

SÄg en presentation pÄ jobbet i gÄr om GitHub Copilot och de visade hur man kunde köra stegvis förfining för att till slut nÄ det mÄlet. TÀnkte jag skulle pröva, köra en @WebbkodsFrilansaren. Resultatet har lite annat stil Àn hur mina lösningar brukar se ut

Jag Àr ganska imponerad. PÄ det stora hela gick det bra. Det blev inte helt rÀtt nÀr jag bad om att filtrera redan besökta platser, sÄ det krÀvdes lite handpÄlÀggning innan vi fick rÀtt svar. Uppenbarligen var jag inte tillrÀckligt precis i mina önskemÄl för vi löste av misstag del 2 före del 1

import numpy as np filename = "input10.txt" # Read the file and create a 2D numpy array a = np.array([[int(c) for c in line.strip()] for line in open(filename, "r").readlines()]) print(a) # Pad the array with -1 all around padded_a = np.pad(a, pad_width=1, mode='constant', constant_values=-1) print(padded_a) # Define the find_path function (updated implementation) def find_path(position, peaks): x, y = position current_value = padded_a[x, y] next_value = current_value + 1 print(f"Finding path from position: {position}, current value: {current_value}") # If the current value is 9, return 1 if current_value == 9: peaks.add(position) return 1 # Mark the current position as visited # Check surrounding elements and sum the results of recursive calls total_paths = 0 for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]: new_x, new_y = x + dx, y + dy new_position = (new_x, new_y) if padded_a[new_x, new_y] == next_value: total_paths += find_path(new_position, peaks) return total_paths # Find the positions of all zeros in the array zero_positions = np.argwhere(padded_a == 0) # Iterate over the positions and call find_path with each position s1 = 0 s2 = 0 for pos in zero_positions: peaks = set() s2 += find_path(tuple(pos), peaks) s1 += len(peaks) print(f"Total paths: {s, s2}")

Dold text

Jag brukar inte heller fÄ 100 % rÀtt och det Àr ju dÀr det fina med att faktiskt kunna lÀsa kod kommer in sÄ att man kan se det och korrigera i efterhand. Ibland brukar jag fÄ kodförslag som jag tycker inte alls Àr rÀtt vÀg att gÄ. SÄ dÄ brukar jag skriva nÄgot i stil med "// Now, what we're going to do instead is X Y Z".

Mvh,
WKF.

Visa signatur

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

PermalÀnk
Medlem
●

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

Del 2 var löst innan del 1 för mig ocksÄ

PermalÀnk
Medlem
●

Dag: 10
SprÄj: Java
Lösning: GitHub

NÀstan sÄ man tror han blandade ihop delarna idag. Kommenterade bort en rad frÄn del 1 för att fÄ rÀtt pÄ tvÄan.

Visa signatur

Starka Äsikter om onödiga saker.

PermalÀnk
Datavetare ★
●

Dag: 10
SprÄk: Rust

Del 1: 19”s (M3), 81”s (Orange Pi 5)
Del 2: 22”s (M3), 95”s (Orange Pi 5)

use std::fs::read_to_string; pub const INPUT_FILE: &str = "input.txt"; pub fn read_map(path: &str) -> (Vec<Vec<u8>>, Vec<(i8, i8)>) { let content = read_to_string(path).expect("Failed to read file"); let mut map = Vec::new(); let mut start_positions = Vec::new(); for (y, line) in content.lines().enumerate() { let row: Vec<u8> = line .chars() .enumerate() .map(|(x, c)| { let digit = c.to_digit(10).expect("Not a digit") as u8; if digit == 0 { start_positions.push((x as i8, y as i8)) } digit }) .collect(); map.push(row); } (map, start_positions) } pub fn part1(map: &[Vec<u8>], start_positions: &[(i8, i8)]) -> u32 { count_trails(map, start_positions, true) } pub fn part2(map: &[Vec<u8>], start_positions: &[(i8, i8)]) -> u32 { count_trails(map, start_positions, false) } fn count_trails(map: &[Vec<u8>], start_positions: &[(i8, i8)], count_trailheads: bool) -> u32 { let height = map.len() as i8; let width = map[0].len() as i8; let get_adjacent_positions = |x: i8, y: i8| { [ if x > 0 { Some((x - 1, y)) } else { None }, if x < width - 1 { Some((x + 1, y)) } else { None }, if y > 0 { Some((x, y - 1)) } else { None }, if y < height - 1 { Some((x, y + 1)) } else { None }, ] }; let mut visited = vec![0u64; map.len()]; let mut trails = Vec::new(); let mut num_trails = 0; for start_position in start_positions { if count_trailheads { for visited_row in &mut visited { *visited_row = 0; } } trails.push((*start_position, 0)); while !trails.is_empty() { let ((x, y), height) = trails.pop().unwrap(); if height == 9 { num_trails += 1; } else { let next_height = height + 1; for adj_pos in get_adjacent_positions(x, y) { if let Some((adj_x, adj_y)) = adj_pos { if map[adj_y as usize][adj_x as usize] == next_height && (!count_trailheads || visited[adj_y as usize] & (1 << adj_x) == 0) { visited[adj_y as usize] |= 1 << adj_x; trails.push(((adj_x, adj_y), next_height)); } } } } } } num_trails } fn main() { let (map, start_positions) = read_map(&INPUT_FILE); println!("part 1: {}", part1(&map, &start_positions)); println!("part 2: {}", part2(&map, &start_positions)); }

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: 10
SprÄk: Python
Programmerare: ChatGPT 4o

Det Àr rÀtt imponerande och rÀtt uppenbart att leaderboards i AoC numera lÀr vara lite "iffy" dÄ de mÀter tid till ett korrekt svar. ChatGPT nailade detta pÄ första försöket med en, av mig filtrerad beskrivning av problemet.

def read_map(file_path): with open(file_path, 'r') as f: return [[int(c) for c in line.strip()] for line in f] def analyze_paths(grid): rows, cols = len(grid), len(grid[0]) directions = [(-1, 0), (1, 0), (0, -1), (0, 1)] unique_paths_count = 0 unique_reachable = set() def dfs(r, c, start, path_seen): nonlocal unique_paths_count if grid[r][c] == 9: unique_paths_count += 1 # Count all paths to '9' # Count unique '0' -> '9' pairs unique_reachable.add((start, (r, c))) return for dr, dc in directions: nr, nc = r + dr, c + dc if 0 <= nr < rows and 0 <= nc < cols and (nr, nc) not in path_seen and grid[nr][nc] == grid[r][c] + 1: dfs(nr, nc, start, path_seen | {(nr, nc)}) for r in range(rows): for c in range(cols): if grid[r][c] == 0: dfs(r, c, (r, c), {(r, c)}) return unique_paths_count, len(unique_reachable) if __name__ == "__main__": file_path = "input.txt" grid = read_map(file_path) total_paths, unique_pairs = analyze_paths(grid) print(f"Total unique paths: {unique_pairs}") print(f"Total paths: {total_paths}")

Dold text

Och detta Àr om man helt sonika ger den hela webbsidan och sÀger

"Can you solve this in Python?"

Enda Àndringen gjord Àr att sÀtta namnet pÄ filen till "input.txt".

from collections import deque def parse_map(input_map): return [list(map(int, line.strip())) for line in input_map.splitlines()] def find_trailheads(map_data): trailheads = [] for i, row in enumerate(map_data): for j, height in enumerate(row): if height == 0: trailheads.append((i, j)) return trailheads def find_hiking_trails(map_data, start): rows, cols = len(map_data), len(map_data[0]) queue = deque([(start, [start])]) trails = set() while queue: (x, y), path = queue.popleft() current_height = map_data[x][y] for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]: nx, ny = x + dx, y + dy if 0 <= nx < rows and 0 <= ny < cols: next_height = map_data[nx][ny] if next_height == current_height + 1 and (nx, ny) not in path: new_path = path + [(nx, ny)] queue.append(((nx, ny), new_path)) if next_height == 9: trails.add(tuple(new_path)) return trails def calculate_trailhead_scores(map_data): trailheads = find_trailheads(map_data) total_score = 0 for trailhead in trailheads: trails = find_hiking_trails(map_data, trailhead) total_score += len(set(trail[-1] for trail in trails)) return total_score def calculate_trailhead_ratings(map_data): trailheads = find_trailheads(map_data) total_rating = 0 for trailhead in trailheads: trails = find_hiking_trails(map_data, trailhead) total_rating += len(trails) return total_rating if __name__ == "__main__": with open('input.txt', 'r') as file: file_content = file.read() map_data = parse_map(file_content) # Part 1 trailhead_score = calculate_trailhead_scores(map_data) print(f"Sum of trailhead scores (Part 1): {trailhead_score}") # Part 2 trailhead_rating = calculate_trailhead_ratings(map_data) print(f"Sum of trailhead ratings (Part 2): {trailhead_rating}")

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:

Dag: 10
SprÄk: Python
Programmerare: ChatGPT 4o

Det Àr rÀtt imponerande och rÀtt uppenbart att leaderboards i AoC numera lÀr vara lite "iffy" dÄ de mÀter tid till ett korrekt svar. ChatGPT nailade detta pÄ första försöket med en, av mig filtrerad beskrivning av problemet.

Bad du om att fÄ slippa meningslösa kommentarer? Min lösning var strösslad med # nu gör vi det nÀr det var helt uppenbart att nÀsta kodrad gjorde just det. De kanske kom för att illustrera vilken del av koden som kom frÄn de olika stegen i min steg-för-steg-lösning.

Presentationen jag sÄg gjordes av en tjej frÄn GitHub och de borde veta vad som funkar bÀttre och sÀmre. En sak som brukade vara bra att att ge exempel, bÄde om man ville ha koden enligt en kodstandard och exempel pÄ vad som var det korrekta beteendet. AoC-uppgifterna brukar ha ganska utförliga exempel.

PermalÀnk
Datavetare ★
●
Skrivet av Ingetledigtnamn:

Bad du om att fÄ slippa meningslösa kommentarer? Min lösning var strösslad med # nu gör vi det nÀr det var helt uppenbart att nÀsta kodrad gjorde just det. De kanske kom för att illustrera vilken del av koden som kom frÄn de olika stegen i min steg-för-steg-lösning.

Presentationen jag sÄg gjordes av en tjej frÄn GitHub och de borde veta vad som funkar bÀttre och sÀmre. En sak som brukade vara bra att att ge exempel, bÄde om man ville ha koden enligt en kodstandard och exempel pÄ vad som var det korrekta beteendet. AoC-uppgifterna brukar ha ganska utförliga exempel.

Normalt fĂ„r man massor med kommentarer, men lade till ”make it compact”

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: 10
SprÄk: C#
Dag 10

Det Àr mer eller mindre exakt samma lösning för del 1 som tvÄ. Det som skiljer dem i min lösning Àr helt enkelt en int som rÀknas upp, eller ett HashSet som utökas.. samma kod utöver det. Optimalt? Antagligen inte, men det fungerar

Del 1: ~2ms
Del 2: ~2ms (samma lösning som del 1)

public class Solver { private enum Direction { Up, Down, Left, Right } private static (int x, int y) GetCoordAtDirection(int xPos, int yPos, Direction dir) { return dir switch { Direction.Up => (xPos, yPos - 1), Direction.Down => (xPos, yPos + 1), Direction.Left => (xPos - 1, yPos), Direction.Right => (xPos + 1, yPos), _ => throw new ArgumentOutOfRangeException(nameof(dir), dir, null) }; } private static bool IsDirValid(int xPos, int yPos, Direction dir, int width, int height) { return dir switch { Direction.Up => yPos - 1 >= 0, Direction.Down => yPos + 1 < height, Direction.Left => xPos - 1 >= 0, Direction.Right => xPos + 1 < width, _ => false }; } private static List<(int x, int y)> GetAvailableNodes(int[,] grid, int x, int y) { var nextAvailablePositions = new List<(int x, int y)>(); foreach (var dir in Enum.GetValues<Direction>()) { if (!IsDirValid(x, y, dir, grid.GetLength(1), grid.GetLength(0))) continue; var coord = GetCoordAtDirection(x, y, dir); if (grid[coord.y, coord.x] == (grid[y, x] + 1)) { nextAvailablePositions.Add((coord.x, coord.y)); } } return nextAvailablePositions; } private static (int uniqueEnds, int numberOfPaths) GetNumberOfPaths(int[,] grid, int x, int y) { HashSet<(int x, int y)> visited = []; int numPaths = 0; var nextAvailablePositions = GetAvailableNodes(grid, x, y); TraverseGrid(nextAvailablePositions); return (visited.Count, numPaths); void TraverseGrid(List<(int x, int y)> nodesToCheck) { foreach (var node in nodesToCheck) { if (grid[node.y, node.x] == 9) { numPaths++; visited.Add((node.x, node.y)); } else { var newNodes = GetAvailableNodes(grid, node.x, node.y); TraverseGrid(newNodes); } } } } private static (int, int) ParseGrid(int[,] grid) { var unique = 0; var num = 0; for (var y = 0; y < grid.GetLength(0); y++) { for (var x = 0; x < grid.GetLength(1); x++) { if (grid[y, x] != 0) continue; var res = GetNumberOfPaths(grid, x, y); unique += res.uniqueEnds; num += res.numberOfPaths; } } return (unique, num); } private static int[,] GetGrid(string input) { var lines = input.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries); var height = lines.Length; var width = lines[0].Length; var grid = new int[width, height]; for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { grid[y, x] = int.Parse(lines[y][x].ToString()); } } return grid; } public static int Run_PartOne(string input) { // Parse string var grid = GetGrid(input); var sum = ParseGrid(grid).Item1; return sum; } public static int Run_PartTwo(string input) { var grid = GetGrid(input); var sum = ParseGrid(grid).Item2; return sum; } }

Dold text
Visa signatur

NZXT H510 Flow MSI B450 Tomahawk MAX
AMD Ryzen 5800X3D RX 7900XTX Kingston Fury 64GB
LG C2 42" 4K@120Hz AOC Q27G2U 1440P@144Hz

PermalÀnk
Medlem ★
●
Skrivet av Yoshman:

Dag: 10
SprÄk: Python
Programmerare: ChatGPT 4o

Det Àr rÀtt imponerande och rÀtt uppenbart att leaderboards i AoC numera lÀr vara lite "iffy" dÄ de mÀter tid till ett korrekt svar. ChatGPT nailade detta pÄ första försöket med en, av mig filtrerad beskrivning av problemet.

def read_map(file_path): with open(file_path, 'r') as f: return [[int(c) for c in line.strip()] for line in f] def analyze_paths(grid): rows, cols = len(grid), len(grid[0]) directions = [(-1, 0), (1, 0), (0, -1), (0, 1)] unique_paths_count = 0 unique_reachable = set() def dfs(r, c, start, path_seen): nonlocal unique_paths_count if grid[r][c] == 9: unique_paths_count += 1 # Count all paths to '9' # Count unique '0' -> '9' pairs unique_reachable.add((start, (r, c))) return for dr, dc in directions: nr, nc = r + dr, c + dc if 0 <= nr < rows and 0 <= nc < cols and (nr, nc) not in path_seen and grid[nr][nc] == grid[r][c] + 1: dfs(nr, nc, start, path_seen | {(nr, nc)}) for r in range(rows): for c in range(cols): if grid[r][c] == 0: dfs(r, c, (r, c), {(r, c)}) return unique_paths_count, len(unique_reachable) if __name__ == "__main__": file_path = "input.txt" grid = read_map(file_path) total_paths, unique_pairs = analyze_paths(grid) print(f"Total unique paths: {unique_pairs}") print(f"Total paths: {total_paths}")

Dold text

NÀstan lÀskigt hur lik den genererade koden Àr min egenskrivna kod. Speciellt "analyze_path"-funktionen, som nÀstan Àr en kopia

Uppenbart att LLM Àr oerhört effektivt för dessa uppgifter. TyvÀrr (eller det kanske Àr bra? ) Àr det vÀl inte riktigt lika detaljerade förklaringar i "verkligheten".

Dold text
Visa signatur

NZXT H510 Flow MSI B450 Tomahawk MAX
AMD Ryzen 5800X3D RX 7900XTX Kingston Fury 64GB
LG C2 42" 4K@120Hz AOC Q27G2U 1440P@144Hz

PermalÀnk
Medlem ★
●

Dag: 11
SprÄk: Python

from collections import Counter def handle_stone(stone, times, output): s = str(stone) if stone == 0: output[stone + 1] += times elif (l := len(s)) % 2 == 0: output[int(s[0:l//2])] += times output[int(s[l//2:])] += times else: output[stone * 2024] += times def blink(input): output = Counter() for stone, times in input.items(): handle_stone(stone, times, output) return output for part in [25, 75]: c = Counter(int(i) for i in open("input11.txt", "r").read().split()) for i in range(part): c = blink(c) print(sum(c.values()))

Dold text
PermalÀnk
Medlem
●

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

PermalÀnk
Medlem ★
●
Skrivet av Ingetledigtnamn:

Dag: 11
SprÄk: Python

from collections import Counter def handle_stone(stone, times, output): s = str(stone) if stone == 0: output[stone + 1] += times elif (l := len(s)) % 2 == 0: output[int(s[0:l//2])] += times output[int(s[l//2:])] += times else: output[stone * 2024] += times def blink(input): output = Counter() for stone, times in input.items(): handle_stone(stone, times, output) return output for part in [25, 75]: c = Counter(int(i) for i in open("input11.txt", "r").read().split()) for i in range(part): c = blink(c) print(sum(c.values()))

Dold text

KĂ€ckt!

Jag körde en pÄ defaultdict(int) för att uppnÄ samma sak.

Dold text
Visa signatur

:(){ :|:& };:

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

PermalÀnk
Medlem
●

Dag: 11
SprÄk: Scala

val stones = Using.resource(Source.fromFile("11.txt"))(_.mkString.trim.split(' ').groupMapReduce(_.toLong)(_ => 1L)(_ + _)) def blink(stones: Map[Long, Long]) = def transform(stone: Long) = stone match case 0 => Vector(1L) case x => val digits = Math.log10(x.toDouble).toInt + 1 if digits % 2 == 0 then val mult = Math.pow(10, digits / 2).toLong Vector(x / mult, x % mult) else Vector(x * 2024) stones.toVector .flatMap((stone, count) => transform(stone).map(_ -> count)) .groupMapReduce(_._1)(_._2)(_ + _) val simulate = LazyList.iterate(stones)(blink) simulate(25).values.sum simulate(75).values.sum

Dold text
PermalÀnk
Medlem
●

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

Satt fast en stund men efter att sparat alla utrÀknade vÀrden i en hashmap gick det ganska snabbt klar pÄ under 100 ms.

Dold text

Är nyfiken pĂ„ hur GPT och Copilot hanterar problem som krĂ€ver en del optimering.
GPT löste Python kod efter tvÄ prompts.

Visa signatur

Starka Äsikter om onödiga saker.

PermalÀnk
Medlem
●
Skrivet av Ingetledigtnamn:

Det tog lite tid. Livet kom i vÀgen.

Uppgiften Àr inte ideal för SIMD. Det blir lite för mÄnga specialfall som mÄste hanteras; olika lÀngder pÄ rapporterna och att antalet rapporter inte stÀmmer med vektorlÀngden. Men hÀr fÄr du i alla fall ett hemskt exempel hur man kan sprida ut rapporterna i flera olika register och operera pÄ 64 olika samtidigt.

Dold text

Samma hÀr.

Snyggt! Jag skulle inte kalla det ett hemskt exempel. DÀremot har du en bugg pÄ rad 86, testar samma kombination tvÄ gÄnger. Jag upptÀckte ganska snabbt att det inte var nÄgra problem att skriva din variant nÀr jag testade att skriva ner den i kod istÀllet för att bara försöka koda i huvudet. Jag tror att jag hade hÀngt upp mig lite för mycket pÄ att jag ville göra en simd version av parsningen ocksÄ. Konstigt nog sÄg jag inte nÄn direkt skillnad i java trots att det Àr uppenbart att din version borde vara snabbare Àn min. Lösningen blev att skriva om min version till c++ istÀllet för att kunna jÀmföra bÀttre. (bara programmerat c++ ett par dagar förra pÄsken vilket Àr förklaringen till att koden ser ut som den gör). Tydligare skillnad i c++ dÀr din version ser ut att vara nÀstan 50% snabbare.

Men... jag passade Àven pÄ att skriva om parsningen till simd för att visa det jag Àr ute efter. Parsar tvÄ rapporter Ät gÄngen. Egentligen kan man skippa nÄgra steg om man mmap:ar filen istÀllet (vilket jag inte orkade ta reda pÄ hur man gör i c++) och flyttar in part2 koden direkt i parsningen. expandedNums innehÄller tvÄ rapporter: check pÄ första, flytta ner andra med en valignq och check pÄ den.

Den hÀr versionen av dag2 del2 kör parsning + berÀkning pÄ drygt 7ms för 1 miljon rapporter (x1000 input). 125+ miljoner rapporter * 8 per sekund Àr vÀl hyffsat snabbt iaf sÄ jag tycker nog att det Àr ett problem som lÀmpar sig bra för simd.

Dold text
PermalÀnk
Medlem ★
●

Dag 11, C#

Kul att lanternfishes Àr tillbaks igen...

using System.Diagnostics; Stopwatch sw = Stopwatch.StartNew(); var line = File.ReadAllText("input.txt").Split(' '); Dictionary<string, long> dict = []; foreach (var item in line) dict[item] = 1; dict = blink_times(dict, 25); Console.WriteLine("Part 1: " + dict.Sum(x => x.Value)); Console.WriteLine(sw.Elapsed); dict = blink_times(dict, 50); Console.WriteLine("Part 2: " + dict.Sum(x => x.Value)); Console.WriteLine(sw.Elapsed); static Dictionary<string, long> blink(Dictionary<string, long> dict) { Dictionary<string, long> ret = []; foreach (var item in dict) { if (item.Key == "0") { add(ret, "1", item.Value); } else if (item.Key.Length % 2 == 0) { add(ret, long.Parse(item.Key[(item.Key.Length / 2)..]).ToString(), item.Value); add(ret, long.Parse(item.Key[..(item.Key.Length / 2)]).ToString(), item.Value); } else { add(ret, (long.Parse(item.Key) * 2024).ToString(), item.Value); } } return ret; static void add(Dictionary<string, long> d, string k, long v) { if (d.TryGetValue(k, out long value)) d[k] = value + v; else d[k] = v; } } static Dictionary<string, long> blink_times(Dictionary<string, long> dict, int times) { for (int i = 0; i < times; i++) { var output = blink(dict); dict = output; } return dict; }

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