đą Main: R9 9900X3D | Strix B850-I | 64GB | RX9070 | Samsung C49RG9
đ” unRaid: Ryzen5 2700X | B450M DS3H | 32GB
đ Tfn: Google Pixel 7 Lime Green
-:| @ eller citera för svar |:-
Dag: 3
SprÄk: PowerShell
$content = Get-Content day3.txt
### Part 1
$readableData = [regex]::Matches($content, 'mul\(\d{1,3},\d{1,3}\)')
$mulInstructions = 0
$correctedMulInstructions = 0
$readableData | ForEach-Object{
$item = ($PSItem.Value).Replace( 'mul(','' ).Replace(')','').Split(',')
$mulInstructions = $mulInstructions + ([int]$item[0] * [int]$item[1])
}
Write-Host "Part 1: $mulInstructions"
### Part 2
$extractedDataToCalculate = $allData = @()
$allData += [regex]::Matches($content, "don't()|do()" )
$allData += $readableData
$allData = $allData | Sort-Object Index
$doCalculations = $true
$allData | ForEach-Object{
switch($PSItem.Value){
"do" { $doCalculations = $true }
"don't" { $doCalculations = $false }
}
if( $doCalculations -eq $true -and $PSItem.Value -like 'mul*' ){
$extractedDataToCalculate += $PSItem
}
}
$extractedDataToCalculate | ForEach-Object{
$item = ($PSItem.Value).Replace( 'mul(','' ).Replace(')','').Split(',')
$correctedMulInstructions = $correctedMulInstructions + ([int]$item[0] * [int]$item[1])
}
Write-Host "Part 2: $correctedMulInstructions"
Kan klart optimera koden i efterhand nu nÀr jag fÄtt rÀtt pÄ logiken men jag orkar inte
đą Main: R9 9900X3D | Strix B850-I | 64GB | RX9070 | Samsung C49RG9
đ” unRaid: Ryzen5 2700X | B450M DS3H | 32GB
đ Tfn: Google Pixel 7 Lime Green
-:| @ eller citera för svar |:-
Dag: 3
SprÄk: F#
Som flera andra, reguljÀra uttryck var Àven central i min lösning.
open System.Text.RegularExpressions
let input = System.IO.File.ReadAllText "./input.txt"
let parse pattern input =
Regex.Matches(input, pattern) |>
Seq.fold (fun (acc, enabled) cur ->
match cur.Value with
| "do()" -> (acc, true)
| "don't()" -> (acc, false)
| _ when enabled -> let x = int cur.Groups.[1].Value
let y = int cur.Groups.[2].Value
((acc+x*y), enabled)
| _ -> (acc, enabled)
) (0, true) |> fst
let part1 = parse @"mul\((\d+),(\d+)\)"
let part2 = parse @"mul\((\d+),(\d+)\)|do\(\)|don't\(\)"
printfn $"Part 1: %i{part1 input}"
printfn $"Part 2: %i{part2 input}"
Jag Àr en optimist; det Àr aldrig sÄ dÄligt sÄ att det inte kan bli sÀmre.
Blev inspirerad av det funktionella sÄ gjorde om min till den stilen i c#
Dag 3:
public partial class Puzzle_2024_3 : Puzzle
{
public override object PartOne(string data)
{
return MulRegex()
.Matches(data)
.Select(m => m.Value[4..^1]
.Split(',')
.Select(int.Parse)
.Aggregate((x, y) => x * y))
.Sum();
}
public override object PartTwo(string data)
{
return DoMulRegex()
.Matches(data)
.Aggregate<Match, (bool enabled, int acc)>((true, 0), (current, match) => match.Value switch
{
"do()" => (true, current.acc),
"don't()" => (false, current.acc),
_ => (current.enabled,
current.enabled
? current.acc += match.Value[4..^1].Split(',').Select(int.Parse).Aggregate((x, y) => x * y)
: current.acc)
}).acc;
}
[GeneratedRegex(@mul\(\d+,\d+\), RegexOptions.Compiled)]
private static partial Regex MulRegex();
[GeneratedRegex(@(do\(\))|(don't\(\))|(mul\(\d+,\d+\)), RegexOptions.Compiled)]
private static partial Regex DoMulRegex();
}
Dag: 3
SprÄk: C#
KÀnner mig ganska bekvÀm med Regex, Àven om jag aldrig fÄr nÄgon anvÀndning av det pÄ jobbet. Passade pÄ att testa .NETs RegexGenerator.
'
namespace AdventOfCode2024.code
{
public static partial class RegexCommands
{
private const string ScanCommandsPattern = @mul\((\d+),(\d+)\)|(do\(\))|(don't\(\));
[GeneratedRegex(ScanCommandsPattern)]
private static partial Regex scanForCommands();
public static MatchCollection ScanForCommands(string input) => scanForCommands().Matches(input);
}
internal static class December3
{
private static readonly string _dataLocation = @data\input3dec.txt;
public static int QuestionOne() => processData(useMultiplicationFlag: false);
public static int QuestionTwo() => processData(useMultiplicationFlag: true);
private static int processData(bool useMultiplicationFlag)
{
int sum = 0;
using var reader = new StreamReader(_dataLocation);
while (reader.ReadLine() is string line)
{
bool isMultiplicationActive = true;
var matches = RegexCommands.ScanForCommands(line);
if (matches.Count== 0) continue;
foreach(Match match in matches)
{
if (match.Groups[3].Success && useMultiplicationFlag) {isMultiplicationActive = true; continue;}
if (match.Groups[4].Success && useMultiplicationFlag) {isMultiplicationActive = false; continue;}
if ((isMultiplicationActive) &&
(match.Groups[1].Success && match.Groups[2].Success))
{
sum += int.Parse(match.Groups[1].Value) * int.Parse(match.Groups[2].Value);
}
}
}
return sum;
}
}
}
Dag: 3
SprÄk: Python (one-liner)
I denna variant görs input-strÀngen om till ett uttryck som sedan evalueras. Man öppnar med en vÀnsterparentes och gör om alla "mul(X,Y)" -> "+X*Y", "do()" -> ")+(" och "don't()" -> ")+(" eller ")+0*(" beroende pÄ om alla produkter skall vara med eller bara efter "do()". Till slut skall det pÄ en högerparentes för att stÀnga uttrycket.
print([eval("("+"".join([re.sub(r"mul\((\d{1,3}),(\d{1,3})\)", r"+\1*\2", i)
.replace("do()", ")+(")
.replace("don't()", p)
for line in [re.findall(r"mul\(\d{1,3},\d{1,3}\)|do\(\)|don't\(\)", l)
for l in open("input03.txt", "r").readlines()]
for i in line]) + ")")
for p in [")+(", ")+0*("]])
Dag: 3
SprÄk: Dyalog APL
Mer regex Àn apl...
dââââNGET'3.txt'1
mâ'mul(\(\d{1,3}),(\d{1,3}\))'
+/Ă/âââmâS'\1 \2'âąd
+/Ă/âââ'don''t\(\)(.*?)(do\(\)|$)'mâS '' '\1 \2'âąd
Dag: 3
SprÄk: Python - Fluffig kod utan one-liners
import re
def day(data: list, debug=True):
if debug:
print(f' Mul reports \n{data}')
# Use debug to switch between the two example data items provided for part 1 and part 2
data_1 = [data[0]]
data_2 = [data[1]]
else:
data_1 = data_2 = data
print(' --------- Part 1 ---------')
re_mul = re.compile(r'mul\(\d+,\d+\)')
re_digits = re.compile(r'\d+')
mul_added = 0
for line in data_1:
# Find correct mul statements
matches = re_mul.findall(line)
for match in matches:
# Find numbers to multiply
a, b = re_digits.findall(match)
if debug:
print(f' {match}, {a}, {b}')
mul_added += int(a) * int(b)
print(' --------- Part 2 ---------')
mul_added_2 = 0
# Start with match enabled
match_enabled = True
for line in data_2:
# Use regular expression groups to find all relevant combinations in correct order and iterate over them
for match in re.finditer(r"(don\'t\(\))|(do\(\))|(mul\(\d+,\d+\))", line):
# Assign matches depending on order defined in the regular expression
dont, do, mul = match.groups()
if debug:
print(f'\tDo: {do} - Dont: {dont} - mul: {mul}')
if do:
if debug:
print('\t -Match enabled')
match_enabled = True
elif dont:
if debug:
print('\t -Match disabled')
match_enabled = False
else:
if match_enabled:
a, b = re_digits.findall(mul)
mul_added_2 += int(a) * int(b)
if debug:
print(f'\tAdd mul: {mul}, {a}, {b}, New mul: {mul_added_2}')
else:
if debug:
print("\tSkipping mul as disabled")
print(f' Answer part 1: {mul_added}, part 2: {mul_added_2}')
return mul_added, mul_added_2
C2D E6300 @ 3.2HGz 1.2V | Thermalright 120 Extr. | Gainward 8800 GT Golden Sample |Samsung 2x500Gb | Corsair VX 550V | Antec P182 [img]http://valid.x86-secret.com/cache/banner/421648.png[/img]
Dag: 3
SprÄk: C#
using System.Text.RegularExpressions;
const string corruptedInput = @"xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))";
var instructions = Regex.Matches(corruptedInput, @"mul\(\d{1,3},\d{1,3}\)");
var products = instructions.Select(instruction =>
{
var factors = Regex.Matches(instruction.Value,@"\d{1,3}");
var multiplier = int.Parse(factors.First().Value);
var multiplicand = int.Parse(factors.Last().Value);
return multiplier * multiplicand;
});
Console.WriteLine(products.Sum());
Dag: 3
SprÄk: C++
#include <iostream>
#include <fstream>
struct StateMachine {
enum State { RESET, M, MU, MUL, D, DO, DON, DON2 /* = DON' */, DONT,
NUM1, NUM2, // reading first and second number to multiply
DO_END, DONT_END, // states expecting a closing parenthesis
} state;
int num1, num2, sum1, sum2;
bool enabled;
StateMachine()
: state(RESET), num1(0), num2(0), sum1(0), sum2(0), enabled(true)
{}
void reset() { state = RESET; num1 = 0; num2 = 0; }
void read(char c)
{
if (state == RESET && c == 'm') state = M;
else if (state == RESET && c == 'd') state = D;
else if (state == D && c == 'o') state = DO;
else if (state == DO && c == 'n') state = DON;
else if (state == DO && c == '(') state = DO_END;
else if (state == DON && c == '\'') state = DON2;
else if (state == DON2 && c == 't') state = DONT;
else if (state == DONT && c == '(') state = DONT_END;
else if (state == M && c == 'u') state = MU;
else if (state == MU && c == 'l') state = MUL;
else if (state == MUL && c == '(') state = NUM1;
else if (state == NUM1 && c == ',') state = NUM2;
else if (state == NUM1 && c>='0' && c<='9') num1 = 10*num1 + c - '0';
else if (state == NUM2 && c>='0' && c<='9') num2 = 10*num2 + c - '0';
else if (state == DO_END && c == ')') { enabled=true; reset(); }
else if (state == DONT_END && c == ')') { enabled=false; reset(); }
else if (state == NUM2 && c == ')')
{
sum1 += num1*num2;
sum2 += enabled ? num1*num2 : 0;
reset();
}
else if (state != RESET)
{
reset();
read(c);
}
}
};
int main(int argc, char* argv[])
{
std::ifstream f(argv[1]);
StateMachine m{};
while(!f.eof())
m.read(f.get());
std::cout << "Part 1: " << m.sum1 << "\nPart 2: " << m.sum2 << '\n';
return 0;
}
Som vanligt sÄ kommer jag ihÄg att AoC Àr en grej nÀr trÄden dyker upp hÀr!
FÄr se om jag Àr med i Är, det Àr inte sÀkert. IsÄfall mÄste jag snabbt bestÀmma vilket sprÄk det blir.
2023 körde jag Python (för att det Àr bekvÀmt), 2021 TypeScript (för att lÀra mig). 2022 uteblev pga flytt.
Skulle vilja lÀra mig Powershell lite bÀttre, men jag tror inte jag Àr sÄ sjÀlvplÄgande att jag kör AoC i det.
Jag brukar orka med mellan 2 och 10 st AoC med PowerShell. Om du vill kan du kolla pÄ mina lösningar hÀr och fÄ hjÀlp eller frÄga om det Àr nÄgot. Jag Àr dock inte supersnabb pÄ att svara
đą Main: R9 9900X3D | Strix B850-I | 64GB | RX9070 | Samsung C49RG9
đ” unRaid: Ryzen5 2700X | B450M DS3H | 32GB
đ Tfn: Google Pixel 7 Lime Green
-:| @ eller citera för svar |:-
Kör som med serier; VÀntar ett par dagar sÄ det finns flera avsnitt att plöja igenom. Ett avsnitt om dagen rÀcker liksom inte
Dag: 1
SprÄk: C#
Dag 1
public class Solver
{
public static int Run_PartOne(List<string> input)
{
var leftNumbers = new List<int>();
var rightNumbers = new List<int>();
foreach (var line in input)
{
var numbers = line.Split(" ");
var left = int.Parse(numbers[0]);
var right = int.Parse(numbers[1]);
leftNumbers.Add(left);
rightNumbers.Add(right);
}
leftNumbers = leftNumbers.OrderBy(x => x).ToList();
rightNumbers = rightNumbers.OrderBy(x => x).ToList();
var totalDistance = 0;
for (int i = 0; i < input.Count; i++)
{
var left = leftNumbers[i];
var right = rightNumbers[i];
var distance = Math.Abs(left - right);
totalDistance += distance;
}
return totalDistance;
}
public static int Run_PartTwo(List<string> input)
{
var leftNumbers = new List<int>();
var rightNumbers = new List<int>();
foreach (var line in input)
{
var numbers = line.Split(" ");
var left = int.Parse(numbers[0]);
var right = int.Parse(numbers[1]);
leftNumbers.Add(left);
rightNumbers.Add(right);
}
var totalSimilarityScore = 0;
for (int i = 0; i < leftNumbers.Count; i++)
{
var left = leftNumbers[i];
var leftInRightCount = rightNumbers.Count(n => n == left);
var similarityScore = left * leftInRightCount;
totalSimilarityScore += similarityScore;
}
return totalSimilarityScore;
}
}
Dag: 2
SprÄk: C#
Dag 2
HÀr skulle man alltsÄ validera raden för att sedan, om det inte validerade, försöka igen fast genom att hoppa över ett index tills det eventuellt validerade.
Det Àr ju lÀttare att hoppa över frÄn första början istÀllet dÄ resultatet blir detsamma - fast mindre rörig kod
public class Solver
{
private static bool AllNumbersAreAscOrDesc(List<int> numbers)
{
return numbers.SequenceEqual(numbers.Order()) || numbers.SequenceEqual(numbers.OrderDescending());
}
private static bool CheckAllAdjacentNumberDistances(List<int> numbers, int minDistance, int maxDistance)
{
bool isValid = true;
for (int i = 0; i < numbers.Count - 1; i++)
{
var distance = Math.Abs(numbers[i] - numbers[i + 1]);
if (distance < minDistance || distance > maxDistance)
{
isValid = false;
break;
}
}
return isValid;
}
private static bool ValidateNumbers(List<int> numbers)
{
return AllNumbersAreAscOrDesc(numbers) && CheckAllAdjacentNumberDistances(numbers, 1, 3);
}
public static int Run_PartOne(List<string> input)
{
// Example line: "7 6 4 2 1"
// Each line must validate against the following rules:
// 1. All increasing or all decreasing
// 2. Any two adjacent numbers differs by at least one and at most three
int safeLines = 0;
foreach (var line in input)
{
var numbers = line.Split(" ").Select(x => int.Parse(x)).ToList();
if(ValidateNumbers(numbers))
safeLines++;
}
return safeLines;
}
public static int Run_PartTwo(List<string> input)
{
// Example line: "7 6 4 2 1"
// Each line must validate against the following rules:
// 1. All increasing or all decreasing
// 2. Any two adjacent numbers differs by at least one and at most three
// If the line does not validate, try ignoring one number at a time, until every number has been ignored once.
// If the line validates while ignoring a number, count it as valid.
int safeLines = 0;
foreach (var line in input)
{
var numbers = line.Split(" ").Select(x => int.Parse(x)).ToList();
var isValid = numbers
.Index()
.Any(item => ValidateNumbers(numbers.Index().Where(t => t.Index != item.Index).Select(t => t.Item).ToList()));
if(isValid)
safeLines++;
}
return safeLines;
}
}
Dag: 3
SprÄk: C#
Dag 3
Regex Àr djÀvulens pÄfund alltsÄ. Försökte vara "smart" men fick svÀlja stoltheten och helt enkelt gÄ pÄ vanlig string-manipulering istÀllet. Inte den snyggaste lösningen (eller effektivaste?) men den fungerar
public class Solver
{
public static int Run_PartOne(string input)
{
// Run the multiplications (mul(X,Y)) from the input
// Only run the instructions defined as; mul(number,number) and ignore anything that does not match this pattern
// Sum the results from each instruction
var result = 0;
var matches = Regex.Matches(input, @mul\((\d+)\,(\d+)\));
foreach (Match match in matches)
{
var first = int.Parse(match.Groups[1].Value);
var second = int.Parse(match.Groups[2].Value);
result += first * second;
}
return result;
}
public static int Run_PartTwo(string input)
{
// Run the multiplications (mul(X,Y)) from the input
// Only run the instructions defined as; mul(number,number) and ignore anything that does not match this pattern
// instructions following a "don't()" is ignored until a "do()" is reached - where it is enabled again.
// Sum the results from each instruction
do
{
var startIndex = input.IndexOf("don't()");
var endIndex = input.Substring(startIndex).IndexOf("do()");
if (endIndex == -1)
{
input = input.Substring(0, startIndex);
}
else
{
endIndex += "do()".Length + startIndex;
input = input.Replace(input.Substring(startIndex, endIndex - startIndex), "");
}
} while (input.Contains("don't()"));
var result = 0;
var matches = Regex.Matches(input, @mul\((\d+)\,(\d+)\));
foreach (Match match in matches)
{
var first = int.Parse(match.Groups[1].Value);
var second = int.Parse(match.Groups[2].Value);
result += first * second;
}
return result;
}
}
NZXT H510 Flow MSI B450 Tomahawk MAX
AMD Ryzen 5800X3D RX 7900XTX Kingston Fury 64GB
LG C2 42" 4K@120Hz AOC Q27G2U 1440P@144Hz
Dag: 3
SprÄk: Rust
use regex::{Captures, Regex};
use std::fs;
pub const INPUT_FILE: &str = "input.txt";
pub enum Instruction {
Mul(i32, i32),
Commit(bool),
}
pub fn read_memory(path: &str) -> String {
fs::read_to_string(path).expect(&format!("File {} should be present", path))
}
fn decode_instruction(caps: Captures) -> Instruction {
if caps.name("mul").is_some() {
let a = caps["a"].parse().unwrap();
let b = caps["b"].parse().unwrap();
Instruction::Mul(a, b)
} else if caps.name("do").is_some() {
Instruction::Commit(true)
} else {
Instruction::Commit(false)
}
}
pub fn decode_instructions(memory: &str) -> Vec<Instruction> {
let pattern = r"(?P<mul>mul\((?P<a>\d+),(?P<b>\d+)\))|(?P<do>do\(\))|(?P<not>don't\(\))";
let re = Regex::new(pattern).unwrap();
re.captures_iter(memory).map(decode_instruction).collect()
}
pub fn execute(instructions: &[Instruction], always_commit: bool) -> i32 {
let mut result = 0;
let mut commit = true;
for instruction in instructions {
match instruction {
Instruction::Mul(a, b) if commit || always_commit => result += a * b,
Instruction::Commit(new_commit) => commit = *new_commit,
_ => {}
}
}
result
}
fn main() {
let memory = read_memory(&INPUT_FILE);
let instructions = decode_instructions(&memory);
println!("part 1: {}", execute(&instructions, true));
println!("part 2: {}", execute(&instructions, false));
}
Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer
Dag: 3
SprÄk: Go
Lösning:
package main
import (
"fmt"
"io"
"log"
"os"
"regexp"
"strconv"
)
func readValuesFromFile(filename string) (string, error) {
file, err := os.Open(filename)
if err != nil {
return "", fmt.Errorf("failed to open file: %w", err)
}
defer file.Close()
data, err := io.ReadAll(file)
if err != nil {
return "", fmt.Errorf("failed to reading file: %w", err)
}
return string(data), nil
}
type Mul struct {
Val1 int
Val2 int
}
func getGroupNameMap(names []string) map[string]int {
nameMap := map[string]int{}
for i, v := range names {
if v != "" {
nameMap[v] = i
}
}
return nameMap
}
func parseMultiplications(value string, interpretConditionals bool) ([]Mul, error) {
re := regexp.MustCompile(`(?:(?P<Mul>mul)\((?P<MulVal1>\d+),(?P<MulVal2>\d+)\))|(?:(?P<Do>do)\(\))|(?:(?P<Dont>don't)\(\))`)
groupNames := getGroupNameMap(re.SubexpNames())
matches := re.FindAllStringSubmatch(value, -1)
muls := []Mul{}
mulsEnabled := true
for _, match := range matches {
if match[groupNames["Mul"]] == "mul" {
if mulsEnabled {
val1, err := strconv.Atoi(match[groupNames["MulVal1"]])
if err != nil {
return nil, fmt.Errorf("not an integer: %s", match[groupNames["MulVal1"]])
}
val2, err := strconv.Atoi(match[groupNames["MulVal2"]])
if err != nil {
return nil, fmt.Errorf("not an integer: %s", match[groupNames["MulVal2"]])
}
mul := Mul{Val1: val1, Val2: val2}
muls = append(muls, mul)
}
}
if interpretConditionals {
if match[groupNames["Do"]] == "do" {
mulsEnabled = true
}
if match[groupNames["Dont"]] == "don't" {
mulsEnabled = false
}
}
}
return muls, nil
}
func calculateMultiplications(value string, interpretConditionals bool) (int, error) {
muls, err := parseMultiplications(value, interpretConditionals)
if err != nil {
return 0, fmt.Errorf("failed to parse multiplications: %w", err)
}
total := 0
for _, mul := range muls {
total += mul.Val1 * mul.Val2
}
return total, nil
}
func main() {
value, err := readValuesFromFile("input.txt")
if err != nil {
log.Fatalf("Error reading data: %s", err)
}
total, err := calculateMultiplications(value, false)
if err != nil {
log.Fatalf("Error calculating part 1: %s", err)
}
fmt.Printf("Part 1: %d\n", total)
total2, err := calculateMultiplications(value, true)
if err != nil {
log.Fatalf("Error calculating part 2: %s", err)
}
fmt.Printf("Part 2: %d\n", total2)
}
Desktop spel m.m.: Ryzen 9800X3D || MSI X870 Tomahawk Wifi || MSI Ventus 3x 5080 || Gskill FlareX 6000 64GB || Kingston KC3000 2TB || Samsung 970 EVO Plus 2TB || Samsung 960 Pro 1TB || Fractal Torrent || Asus PG42UQ 4K OLED
Arbetsstation: Ryzen 7945HX || Minisforum BD790i || Asus Proart 4070 Ti Super || Kingston Fury Impact 5600 65 GB || WD SN850 2TB || Samsung 990 Pro 2TB || Fractal Ridge
Proxmox server: Ryzen 5900X || Asrock Rack X570D4I-2T || Kingston 64GB ECC || WD Red SN700 1TB || Blandning av WD Red / Seagate Ironwolf för lagring || Fractal Node 304
NÄgon som hittade nÄgon esoterisk lösning?
Ett sÀtt att programmera en snabbare version av dag 2 ...
... Àr att fortfarande köra bruteforce men anvÀnda simd. Tittar man pÄ indatan sÄ Àr varje report mellan 5 och 8 levels lÄng och vÀrdet för level hÄller sig inom 1-99 alltsÄ fÄr varje report plats i 8 bytes.
AnvÀnder man AVX512 sÄ kan man i del 1 testa 8 reports samtidigt och i del 2 kan man testa alla möjliga subsequences som uppstÄr om man tar bort ett vÀrde samtidigt.
Det borde vara snabbare Àn att försöka göra nÄgot annat smart.
Ett sÀtt att programmera en snabbare version av dag 2 ...
... Àr att fortfarande köra bruteforce men anvÀnda simd. Tittar man pÄ indatan sÄ Àr varje report mellan 5 och 8 levels lÄng och vÀrdet för level hÄller sig inom 1-99 alltsÄ fÄr varje report plats i 8 bytes.
AnvÀnder man AVX512 sÄ kan man i del 1 testa 8 reports samtidigt och i del 2 kan man testa alla möjliga subsequences som uppstÄr om man tar bort ett vÀrde samtidigt.
Det borde vara snabbare Àn att försöka göra nÄgot annat smart.
Nja,
SIMD-instruktionerna Àr bra pÄ att göra samma sak pÄ mÄnga rapporter samtidigt, men du vill inte ha en rapport i samma register. De Àr inte alls bra pÄ att operera pÄ flera element i samma register. Du vill snarare sprida ut dem sÄ att du har första elementen frÄn 64 olika rapporter i vektorregister zmm1 och andra elementet i zmm2, osv. DÄ kan du operera pÄ 64 rapporter parallellt, men det blir lite bökigt eftersom de hade olika lÀngder. Det gÄr, men det blir lite pyssligt.
Dag: 2
SprÄk: C
Lösning:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void new_row_without_idx(const int *in, int *out, int rm_idx)
{
int ofs = 0;
for (int i = 0; i < 7; i++) {
if (rm_idx == i) {
ofs = 1;
}
out[i] = in[i+ofs];
}
}
// returns 0 if safe, -1 when non-safe
int is_row_safe(int *row)
{
int dir = 0;
int j;
for (j = 1; j < 8; j++) {
// start by checking if value is zero, that means we've passed through the row successfully
if (row[j] == 0) {
return 0;
}
if (!dir) {
dir = row[j] - row[j-1];
}
if (dir > 0) {
if (row[j-1] >= row[j]) {
return -1;
}
} else { // dir decreasing
if (row[j-1] <= row[j]) {
return -1;
}
}
// Check safeness - diff 1-3 and same dir
if (abs(row[j-1] - row[j]) > 3) {
return -1; // diff outside of 1-3 range
}
}
return 0;
}
int main(int argc, char *argv[])
{
FILE *fp;
int a[1000][8] = {{0}};
char tmp[100], *r = NULL;
int i = 0, j;
int safecount = 0;
fp = fopen("input.txt", "r");
while ((r = fgets(tmp, sizeof(tmp), fp)) != NULL) {
(void) sscanf(r, "%d %d %d %d %d %d %d %d", &a[i][0], &a[i][1], &a[i][2], &a[i][3], &a[i][4], &a[i][5], &a[i][6], &a[i][7]);
i++;
}
fclose(fp);
// part 1
for (i = 0; i < 1000; i++) {
if (is_row_safe(a[i]) == 0) {
safecount++;
}
}
printf("part1: %d\n", safecount);
// part 2
int tmprow[8] = {0};
safecount = 0;
for (i = 0; i < 1000; i++) {
if (is_row_safe(a[i]) != 0) {
for (j = 0; j < 8; j++) {
memset(tmprow, 0, sizeof(tmprow));
new_row_without_idx(a[i], tmprow, j);
if (is_row_safe(tmprow) == 0) {
safecount++;
break;
}
}
} else {
safecount++;
}
}
printf("part 2: %d\n", safecount);
return 0;
}
Inte bra att redan halkat efter i schemat, men fortsÀtter pÄ temat med C. Se om man hinner Äterkomma och fundera pÄ om man kan hitta nÄgra genvÀgar..
Citera mig för svar.
Arch Linux
Nja,
SIMD-instruktionerna Àr bra pÄ att göra samma sak pÄ mÄnga rapporter samtidigt, men du vill inte ha en rapport i samma register. De Àr inte alls bra pÄ att operera pÄ flera element i samma register. Du vill snarare sprida ut dem sÄ att du har första elementen frÄn 64 olika rapporter i vektorregister zmm1 och andra elementet i zmm2, osv. DÄ kan du operera pÄ 64 rapporter parallellt, men det blir lite bökigt eftersom de hade olika lÀngder. Det gÄr, men det blir lite pyssligt.
Jag kan inte komma pÄ hur man skulle kunna göra det effektivt pÄ det sÀtt du beskriver. Det gÄr inte att göra en gather pÄ 64 bytes alltsÄ mÄste man under parsning arrangera om datan. Hur hÄller du dÄ koll pÄ lÀngden pÄ varje report? Och hur skulle del 2 fungera?
Det enda man ska göra som har med tvÄ element i samma vektor Àr en subtraktion av nÀrliggande element. Det Àr en 3 latency vpermb för att skifta vektorn ett steg.
HÀr kommer ett lite mer detaljerat exempel hur man skulle kunna göra (skippar optimerad parsning):
AnvÀnder de tvÄ första exemplen frÄn uppgiften
LÀs in textfilen till en 1000 x 8 byte array sÄ att man fÄr 0 padding pÄ slutet.
[7 6 4 2 1 0 0 0 1 2 7 8 9 0 0 0 ...]
Flytta 64 bytes till ett vektor register
<7 6 4 2 1 0 0 0 1 2 7 8 9 0 0 0 ...>
LÀngden - 1 för varje enskilt report behövs senare och den fÄr man genom att anvÀnda vektor registret som ett 8 x 64 bitars och ta 7 - (lzcnt( 64 bitar ) >> 3). (leading zero count)
<4 4 ...>
Skifta en kopia av registret ett steg och subtrahera. (? Àr skrÀp frÄn nÀsta report som kommer maskas bort senare)
r1 = <7 6 4 2 1 0 0 0 1 2 7 8 9 0 0 0 ...>
r2 = <6 4 2 1 0 0 0 1 2 7 8 9 0 0 0 ? ...>
r1 - r2 = <1 2 2 1 1 0 0 -1 -1 -5 -1 -1 9 0 0 ? ...>
Skapa en mask som maskar bort allt utom de bitar man Àr intresserat av t.ex. genom att kombinera element i r2 som inte Àr 0 med en 7f7f... mask som maskar bort högsta byten i varje report.
<1 2 2 1 1 0 0 -1 -1 -5 -1 -1 9 0 0 ? ...>
<T TÂ TÂ T _ _ _ _ T T T T _ _ _ _ ...>
Nu kan man göra tvÄ maskade compares som kollar om elementen Àr mellan 1 och 3 eller mellan -1 och -3.
<1 2 2 1 1 0 0 -1 -1 -5 -1 -1 9 0 0 ? ...>
cmp1 = <T T T T _ _ _ _ _ _ _ _ _ _ _ _ ...>
cmp2 = <_ _ _ _ _ _ _ _ TÂ Â _ T T _ _ _ _ ...>
Sen flyttar man tillbaka maskerna till tvÄ vektor register. Det sÀtter alla bitar till 1 om masken Àr T. AlltsÄ fÄr man vÀrdet -1 pÄ bytes som var sanna och 0 pÄ de andra
<-1 -1 -1 -1 0 0 0 0 0 0 0 0 0 0 0 0 ...>
< 0 0 0 0 0 0 0 0 -1 0 -1 -1 0 0 0 0 ...>
Genom att tolka registret som ett 8 x 64 bit igen kan man ta en popcount för rÀkna antalet satta bitar per report.
cnt1 = <32 0 ...>
cnt2 = <0 24 ...>
Om man nu gör en compare mellan antalet satta bitar i bÄda registren och lÀngden man sparade tidigare gÄnger 8 sÄ fÄr man fram en mask som visar vilka reports som Àr safe.
len = < 4 4 ...>
x 8 = <32 32 ...>
cnt1 = <32 0 ...>
cnt2 = <0 24 ...>
m1 = <TÂ _ ...>
m2 = <_ _ ...>
Genom att göra en popcount pÄ m1 och m2 sÄ fÄr man antalet Safe reports.
Del tvÄ Àr i princip samma sak fast istÀllet för att lÀsa in 8 reports sÄ tar man en Ät gÄngen. Antingen genom en maskad load eller genom en inre loop som skiftar ner registret 8 bytes Ät gÄngen.
<1 3 2 4 5 0 0 0 0 ...>
Sen gör man en permute som sprider ut elementen i alla möjliga kombinationer av 7 element.
<3 2 4 5 0 0 0 0 1 2 4 5 0 0 0 0 1 3 4 5 0 0 0 0...>
Skillnaden frÄn del 1 Àr att man sen kollar om man fÄr minst en trÀff i antingen m1 eller m2 istÀllet för att rÀkna ihop alla trÀffar.
Det gÄr sÀkert att göra nÄgot smartare men att lösa problemet utan simd tar < 100us sÄ knappast vÀrt att lÀgga ner tid pÄ den hÀr typen av lösning.
HÀr Àr lite groovy för den som Àr intresserad.
def "2024-04 in Groovy as a Spock test case"() { given: def text = this.getClass().getResource( '/y2024/data03.txt' ).readLines().join() def ops = text.findAll(/mul\((\d+),(\d+)\)/) def res = ops.sum { def parts = it[4..-2].split(",").collect { it.toLong() } parts[0] * parts[1] } expect: res == 187825547 }
Dag: 4
Sprak: Golang
Inte vackert.
package main
import (
"bufio"
"fmt"
"os"
)
type Position struct {
y int
x int
}
func isOutOfBounds(rows []string, pos Position) bool {
if pos.y < 0 || pos.y >= len(rows) {
return true
} else if pos.x < 0 || pos.x >= len(rows[pos.y]) {
return true
}
return false
}
func checkDirection(rows []string, pos, dir Position) bool {
target := "XMAS"
for i := 1; i < len(target); i++ {
pos.y += dir.y
pos.x += dir.x
if isOutOfBounds(rows, pos) {
return false
} else if rows[pos.y][pos.x] != target[i] {
return false
}
}
return true
}
func getPossibleDirection(rows []string, pos Position, diagonalOnly bool) (directions []Position) {
for y := -1; y < 2; y++ {
for x := -1; x < 2; x++ {
if x == 0 && y == 0 {
continue
}
if diagonalOnly && (abs(y)+abs(x)) != 2 {
continue
}
if isOutOfBounds(rows, Position{pos.y + y, pos.x + x}) {
continue
}
directions = append(directions, Position{y: y, x: x})
}
}
return directions
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}
func getPartOne(rows []string) int {
count := 0
for y, row := range rows {
for x, char := range row {
if string(char) != "X" {
continue
}
directions := getPossibleDirection(rows, Position{y, x}, false)
for _, direction := range directions {
if checkDirection(rows, Position{y, x}, direction) {
count++
}
}
}
}
return count
}
func getPartTwo(rows []string) int {
count := 0
validCombinations := map[string]struct{}{
"MMSS": {},
"SMMS": {},
"SSMM": {},
"MSSM": {},
}
for y, row := range rows {
for x, char := range row {
if string(char) != "A" {
continue
}
directions := getPossibleDirection(rows, Position{y, x}, true)
if len(directions) != 4 {
continue
}
northWest := string(rows[y-1][x-1])
northEast := string(rows[y-1][x+1])
southEast := string(rows[y+1][x+1])
southWest := string(rows[y+1][x-1])
if _, exist := validCombinations[fmt.Sprintf("%s%s%s%s",
northWest, northEast, southEast, southWest)]; exist {
count++
}
}
}
return count
}
func getRows(filename string) []string {
file, err := os.Open(filename)
if err != nil {
panic(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
var rows []string
for scanner.Scan() {
rows = append(rows, scanner.Text())
}
return rows
}
func main() {
fmt.Println("Part one:", getPartOne(getRows("../input.txt")))
fmt.Println("Part two:", getPartTwo(getRows("../input.txt")))
}
(Jag sa ju att krav pÄ tvÄdimensionella arrayer skulle sÀnka mig! )
Dag 4 Del 1 - FrÄga i SPOILER dÄ jag har fastnat (fÄr för lÄgt svar i Dag 4 Del 1):
Jag fĂ„r för lĂ„gt och jag saknar den spatiala tankeförmĂ„gan Ă€n sĂ„ lĂ€nge att visualisera den diagonala navigeringen nĂ€r den ska tugga igenom. Och vad exakt Ă€r exempel pĂ„ "overlapping" i detta fall? Ăr det t.ex. SAMXMAS och XMASAMX?
Jag anvÀnder funktionen substr_count() i PHP: https://www.php.net/manual/en/function.substr-count.php DÀr stÄr det att den ej klarar av "overlapping". Om sluttecknet pÄ en matchning ocksÄ Àr början pÄ nÀsta matchning sÄ Àr det "overlapping"?
Ăn sĂ„ lĂ€nge har jag:
// 4.php | PHP
$cleanLines = array_map('rtrim', explode("\n", $data));
$grid = array_map('str_split', $cleanLines);
$LINELENGTH = strlen($cleanLines[0]);
$MAXINDEX = $LINELENGTH - 1;
$NUMBEROFLINES = count($cleanLines);
$numberOfFoundXMAS = 0;
echo "Line Length: $LINELENGTH\n";
echo "Max Index: $MAXINDEX\n";
echo "Number of Lines: $NUMBEROFLINES\n";
function checkRowStraightAndReverse($stringRow, &$numberOfFoundXMAS)
{
$numberOfFoundXMAS += substr_count($stringRow, "XMAS");
$numberOfFoundXMAS += substr_count($stringRow, "SAMX");
}
for ($i = 0; $i < $NUMBEROFLINES; $i++) {
checkRowStraightAndReverse($cleanLines[$i], $numberOfFoundXMAS);
}
echo "Found Horizontally Total: $numberOfFoundXMAS\n";
for ($i = 0; $i < $LINELENGTH; $i++) {
$stringColumn = "";
for ($j = 0; $j < $NUMBEROFLINES; $j++) {
$stringColumn .= $grid[$j][$i];
}
checkRowStraightAndReverse($stringColumn, $numberOfFoundXMAS);
}
echo "Found Horizontally+Vertically: $numberOfFoundXMAS\n";
for ($i = 0; $i < $NUMBEROFLINES; $i++) {
$stringDiagonal = "";
for ($j = 0; $j < $NUMBEROFLINES - $i; $j++) {
$stringDiagonal .= $grid[$j][$j + $i];
}
checkRowStraightAndReverse($stringDiagonal, $numberOfFoundXMAS);
}
for ($i = 0; $i < $NUMBEROFLINES; $i++) {
$stringDiagonal = "";
for ($j = 0; $j < $NUMBEROFLINES - $i; $j++) {
$stringDiagonal .= $grid[$j][$NUMBEROFLINES - $j - $i - 1];
}
checkRowStraightAndReverse($stringDiagonal, $numberOfFoundXMAS);
}
echo "Found Horizontally+Vertically+Diagonally: $numberOfFoundXMAS\n";
Mvh,
WKF.
(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming
Dag 4, C#
Struntar i att posta kod idag, men i korthet slÀnger jag in alla chars i input i ett dictionary med dess position som nyckel till att börja med. DÄ kan jag köra TryGetValue istÀllet för att behöva tÀnka pÄ edge cases, och det sparar pÄ min psykiska hÀlsa.
För del 1 kollar jag alla riktningar efter MAS för varje X, för del 2 kollar jag om \ resp / har M och S eller S och M
The power of GNU compiles you!
"Often statistics are used as a drunken man uses lampposts -- for support rather than illumination."
Dag: 4
SprÄk: C#
Dag 4
Idag var det roligare. Att ha jobbat med voxels i spelutveckling underlÀttade rejÀlt dÄ det i princip Àr samma tankesÀtt för första uppgiften.
Andra uppgiften fick bli mer "hÄrdkodat" och helt enkelt kolla sÄ varje hörn matchar mot M eller S bÄde för nordvÀst, nordöst, sydvÀst och sydöst frÄn varje bokstav A.
MÄnga rader som antagligen kan kortas ner rejÀlt. Men gillar lÀsbarhet över "coolt"
public class Solver
{
private enum Direction { Up, Down, Left, Right, UpRight, UpLeft, DownRight, DownLeft }
private static string GetStringForDir(List<string> input, int xPos, int yPos, Direction dir)
{
int x2 = xPos, x3 = xPos, x4 = xPos;
int y2 = yPos, y3 = yPos, y4 = yPos;
switch (dir)
{
case Direction.Up:
y2 = yPos - 1;
y3 = yPos - 2;
y4 = yPos - 3;
break;
case Direction.Down:
y2 = yPos + 1;
y3 = yPos + 2;
y4 = yPos + 3;
break;
case Direction.Left:
x2 = xPos - 1;
x3 = xPos - 2;
x4 = xPos - 3;
break;
case Direction.Right:
x2 = xPos + 1;
x3 = xPos + 2;
x4 = xPos + 3;
break;
case Direction.UpLeft:
y2 = yPos - 1;
y3 = yPos - 2;
y4 = yPos - 3;
x2 = xPos - 1;
x3 = xPos - 2;
x4 = xPos - 3;
break;
case Direction.UpRight:
y2 = yPos - 1;
y3 = yPos - 2;
y4 = yPos - 3;
x2 = xPos + 1;
x3 = xPos + 2;
x4 = xPos + 3;
break;
case Direction.DownLeft:
y2 = yPos + 1;
y3 = yPos + 2;
y4 = yPos + 3;
x2 = xPos - 1;
x3 = xPos - 2;
x4 = xPos - 3;
break;
case Direction.DownRight:
y2 = yPos + 1;
y3 = yPos + 2;
y4 = yPos + 3;
x2 = xPos + 1;
x3 = xPos + 2;
x4 = xPos + 3;
break;
}
return $"{input[yPos][xPos]}{input[y2][x2]}{input[y3][x3]}{input[y4][x4]}";
}
private static bool IsDirValid(List<string> characters, int xPos, int yPos, Direction dir, int maxLength)
{
switch (dir)
{
case Direction.Up:
return yPos - maxLength >= 0;
case Direction.Down:
return yPos < characters.Count - maxLength;
case Direction.Left:
return xPos - maxLength >= 0;
case Direction.Right:
return xPos < characters[yPos].Length - maxLength;
case Direction.UpLeft:
return xPos - maxLength >= 0 && yPos - maxLength >= 0;
case Direction.UpRight:
return xPos < characters[yPos].Length - maxLength && yPos - maxLength >= 0;
case Direction.DownLeft:
return xPos - maxLength >= 0 && yPos < characters.Count - maxLength;
case Direction.DownRight:
return xPos < characters[yPos].Length - maxLength && yPos < characters.Count - maxLength;
default:
return false;
}
}
public static int Run_PartOne(List<string> input)
{
var matchedString = "XMAS";
int matchedCount = 0;
for (int y = 0; y < input.Count; y++)
{
for (int x = 0; x < input[y].Length; x++)
{
var character = input[y][x].ToString();
if (character == "X")
{
foreach (var dir in new List<Direction>(){ Direction.Up, Direction.Down, Direction.Left, Direction.Right, Direction.UpRight, Direction.UpLeft, Direction.DownRight, Direction.DownLeft })
{
if (IsDirValid(input, x, y, dir, matchedString.Length - 1))
{
var res = GetStringForDir(input, x, y, dir);
if (res == matchedString) matchedCount++;
}
}
}
}
}
return matchedCount;
}
public static int Run_PartTwo(List<string> input)
{
int matchedCount = 0;
for (int y = 0; y < input.Count; y++)
{
for (int x = 0; x < input[y].Length; x++)
{
var character = input[y][x].ToString();
if (character == "A")
{
var topLeftX = x - 1;
var topLeftY = y - 1;
var topRightX = x + 1;
var topRightY = y - 1;
var bottomLeftX = x - 1;
var bottomLeftY = y + 1;
var bottomRightX = x + 1;
var bottomRightY = y + 1;
if (IsDirValid(input, x, y, Direction.UpLeft, 1) && IsDirValid(input, x, y, Direction.UpRight, 1)
&& IsDirValid(input, x, y, Direction.DownLeft, 1) && IsDirValid(input, x, y, Direction.DownRight, 1))
{
if(((input[topLeftY][topLeftX] == 'M' && input[bottomRightY][bottomRightX] == 'S') || (input[topLeftY][topLeftX] == 'S' && input[bottomRightY][bottomRightX] == 'M')) &&
((input[topRightY][topRightX] == 'M' && input[bottomLeftY][bottomLeftX] == 'S') || (input[topRightY][topRightX] == 'S' && input[bottomLeftY][bottomLeftX] == 'M')))
{
matchedCount++;
}
}
}
}
}
return matchedCount;
}
}
NZXT H510 Flow MSI B450 Tomahawk MAX
AMD Ryzen 5800X3D RX 7900XTX Kingston Fury 64GB
LG C2 42" 4K@120Hz AOC Q27G2U 1440P@144Hz
Dag: 4
SprÄk: C#
Kul att jÀmföra lösningar. Gjorde rÀtt likt @Pamudas - i del 2 ledsnade jag pÄ alven och kollar bara om bÄda motstÄende hörn summeras till (int)M + (int)S.
namespace AdventOfCode2024.code
{
static class December4
{
private static readonly string _secretWord = @XMAS;
private static readonly string _dataLocation = @data\input4dec.txt;
public static int Question1()
{
var lines = File.ReadAllLines(_dataLocation);
int res = 0;
for(int i = 0; i < lines.Length; i++)
{
for(int j = 0; j < lines[i].Length; j++)
{
if(lines[i][j] == _secretWord[0])
{
res += searchAllDirections(lines, i, j);
}
}
}
return res;
}
public static int Question2()
{
var lines = File.ReadAllLines(_dataLocation);
int res = 0;
for(int i = 0; i < lines.Length; i++)
{
for(int j = 0; j < lines[i].Length; j++)
{
if(lines[i][j] == 'A')
{
res += searchForMas(lines, i, j);
}
}
}
return res;
}
[Flags]
private enum Direction
{
Left = 1,
Right = 2,
Up = 4,
Down = 8
};
private static int searchAllDirections(string[] lines, int linesIndex, int lineIndex)
{
List<Direction> directions = new List<Direction>()
{
Direction.Left,
Direction.Right,
Direction.Up,
Direction.Down,
Direction.Left | Direction.Up,
Direction.Left | Direction.Down,
Direction.Right | Direction.Up,
Direction.Right | Direction.Down
};
return directions.Count(direction => search(lines, linesIndex, lineIndex, _secretWord, 0, direction));
}
private static bool search(string[] lines, int linesIndex, int lineIndex, string secretWord, int secretWordIndex, Direction direction)
{
while (true)
{
//Modify indices
if (direction.HasFlag(Direction.Left)) lineIndex--;
if (direction.HasFlag(Direction.Right)) lineIndex++;
if (direction.HasFlag(Direction.Up)) linesIndex--;
if (direction.HasFlag(Direction.Down)) linesIndex++;
secretWordIndex++;
//Check that all indices is within bounds
if (linesIndex < 0) return false;
if (linesIndex == lines.Length) return false;
var line = lines[linesIndex];
if (lineIndex < 0) return false;
if (lineIndex == line.Length) return false;
//Check if we matched the whole word
if (secretWordIndex == secretWord.Length - 1) return secretWord[secretWordIndex] == line[lineIndex];
if (line[lineIndex] == secretWord[secretWordIndex]) continue;
return false;
}
}
private static int searchForMas(string[] lines, int linesIndex, int lineIndex)
{
//Check that all indices is within bounds
if (linesIndex - 1 < 0) return 0;
if (linesIndex + 1 >= lines.Length) return 0;
if (lineIndex - 1 < 0) return 0;
if (lineIndex + 1 >= lines.Length) return 0;
bool res1 = (lines[linesIndex - 1][lineIndex - 1] + lines[linesIndex + 1][lineIndex + 1]) == 'M' + 'S';
bool res2 = (lines[linesIndex - 1][lineIndex + 1] + lines[linesIndex + 1][lineIndex - 1]) == 'M' + 'S';
return res1 && res2 ? 1 : 0;
}
}
}
@Pamudas Jag vill tacka för din indirekta hjÀlp!
Dag 4 Del 1 Endast !!!
PHP - Körs via "Code Runner" i VSCode Terminal
4.php - FĂ„ kommentarer (pinsamt illa att diagonalfunktionen ej lyckades nyttjas korrekt)
<?php
$data = "https://adventofcode.com/2024/day/4/input";
// Prepare ["X,Y"] coordinate using PHP associative keys!
$cleanLines = array_map('rtrim', explode("\n", $data));
$coordinateSystem = [];
foreach ($cleanLines as $y => $row) {
for ($x = 0; $x < strlen($row); $x++) {
$coord = ($x + 1) . "," . ($y + 1);
$coordinateSystem[$coord] = $row[$x];
}
}
$numberOfFoundXMAS = 0;
function getCharAt($coordinate, $coordinateSystem)
{
return isset($coordinateSystem[$coordinate]) ? $coordinateSystem[$coordinate] : "?";
}
function checkForMASAllDirections($coordinate, $coordinateSystem, &$numberOfFoundXMAS)
{
// The starting X,Y coordinates
[$startX, $startY] = array_map('intval', explode(",", $coordinate));
// Check all to the Left meaning, we add getCharAt X-1, X-2, and X-3 and see if that spells "MAS"
if (
getCharAt(($startX - 1) . "," . $startY, $coordinateSystem) === "M" &&
getCharAt(($startX - 2) . "," . $startY, $coordinateSystem) === "A" &&
getCharAt(($startX - 3) . "," . $startY, $coordinateSystem) === "S"
) {
$numberOfFoundXMAS += 1;
}
// Check all to the Right meaning, we add getCharAt X+1, X+2, and X+3 and see if that spells "MAS"
if (
getCharAt(($startX + 1) . "," . $startY, $coordinateSystem) === "M" &&
getCharAt(($startX + 2) . "," . $startY, $coordinateSystem) === "A" &&
getCharAt(($startX + 3) . "," . $startY, $coordinateSystem) === "S"
) {
$numberOfFoundXMAS += 1;
}
// Check all to the Up meaning, we add getCharAt X,Y-1, X,Y-2, and X,Y-3 and see if that spells "MAS"
if (
getCharAt($startX . "," . ($startY - 1), $coordinateSystem) === "M" &&
getCharAt($startX . "," . ($startY - 2), $coordinateSystem) === "A" &&
getCharAt($startX . "," . ($startY - 3), $coordinateSystem) === "S"
) {
$numberOfFoundXMAS += 1;
}
// Check all to the Down meaning, we add getCharAt X,Y+1, X,Y+2, and X,Y+3 and see if that spells "MAS"
if (
getCharAt($startX . "," . ($startY + 1), $coordinateSystem) === "M" &&
getCharAt($startX . "," . ($startY + 2), $coordinateSystem) === "A" &&
getCharAt($startX . "," . ($startY + 3), $coordinateSystem) === "S"
) {
$numberOfFoundXMAS += 1;
}
// Check all to the Top Left meaning, we add getCharAt X-1,Y-1, X-2,Y-2, and X-3,Y-3 and see if that spells "MAS"
if (
getCharAt(($startX - 1) . "," . ($startY - 1), $coordinateSystem) === "M" &&
getCharAt(($startX - 2) . "," . ($startY - 2), $coordinateSystem) === "A" &&
getCharAt(($startX - 3) . "," . ($startY - 3), $coordinateSystem) === "S"
) {
$numberOfFoundXMAS += 1;
}
// Check all to the Top Right meaning, we add getCharAt X+1,Y-1, X+2,Y-2, and X+3,Y-3 and see if that spells "MAS"
if (
getCharAt(($startX + 1) . "," . ($startY - 1), $coordinateSystem) === "M" &&
getCharAt(($startX + 2) . "," . ($startY - 2), $coordinateSystem) === "A" &&
getCharAt(($startX + 3) . "," . ($startY - 3), $coordinateSystem) === "S"
) {
$numberOfFoundXMAS += 1;
}
// Check all to the Bottom Left meaning, we add getCharAt X-1,Y+1, X-2,Y+2, and X-3,Y+3 and see if that spells "MAS"
if (
getCharAt(($startX - 1) . "," . ($startY + 1), $coordinateSystem) === "M" &&
getCharAt(($startX - 2) . "," . ($startY + 2), $coordinateSystem) === "A" &&
getCharAt(($startX - 3) . "," . ($startY + 3), $coordinateSystem) === "S"
) {
$numberOfFoundXMAS += 1;
}
// Check all to the Bottom Right meaning, we add getCharAt X+1,Y+1, X+2,Y+2, and X+3,Y+3 and see if that spells "MAS"
if (
getCharAt(($startX + 1) . "," . ($startY + 1), $coordinateSystem) === "M" &&
getCharAt(($startX + 2) . "," . ($startY + 2), $coordinateSystem) === "A" &&
getCharAt(($startX + 3) . "," . ($startY + 3), $coordinateSystem) === "S"
) {
$numberOfFoundXMAS += 1;
}
}
foreach ($coordinateSystem as $coord => $value) {
if ($value === "X") {
checkForMASAllDirections($coord, $coordinateSystem, $numberOfFoundXMAS);
}
}
echo "Found XMAS/SAMX in Total (Part 1): $numberOfFoundXMAS\n";
Jag kunde "kommentarskoda" fram liknande algoritm som du gjort i Dag 4 Del 1. Jag tror jag misslyckades lÀsa in all data pÄ rÀtt sÀtt för att sedan "rÀkna" fram rÀtt antal. Jag tror min tidigare rad-tolkare faktiskt fungerar rÀtt men fick fel mÀngd data helt enkelt och dÀrmed spottade ut fel antal.
Vad jag Àr nöjd med dock Àr vÀl funktionen som ser till att inte det inte kan krascha vid sÄ kallade bokstavligen talat "edge cases".
Och nu Dag 4 Del 2... đ±đ±đ±
Mvh,
WKF.
(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming
Dag 4 DEL 1 + DEL 2 !!!
PHP - Körs via "Code Runner" i VSCode Terminal
4.php - Dag 4 Del 1 OCH DEL 2 (fÄ kommentarer)
<?php
$data = "https://adventofcode.com/2024/day/4/input";
$cleanLines = array_map('rtrim', explode("\n", $data));
$coordinateSystem = [];
foreach ($cleanLines as $y => $row) {
for ($x = 0; $x < strlen($row); $x++) {
$coord = ($x + 1) . "," . ($y + 1); // Coordinates as "1,1", "2,1", etc.
$coordinateSystem[$coord] = $row[$x];
}
}
function getCharAt($coordinate, $coordinateSystem)
{
return isset($coordinateSystem[$coordinate]) ? $coordinateSystem[$coordinate] : "?";
}
function checkForMASAllDirections($coordinate, $coordinateSystem, &$numberOfFoundXMAS)
{
// The starting X,Y coordinates
[$startX, $startY] = array_map('intval', explode(",", $coordinate));
// Check all to the Left meaning, we add getCharAt X-1, X-2, and X-3 and see if that spells "MAS"
if (
getCharAt(($startX - 1) . "," . $startY, $coordinateSystem) === "M" &&
getCharAt(($startX - 2) . "," . $startY, $coordinateSystem) === "A" &&
getCharAt(($startX - 3) . "," . $startY, $coordinateSystem) === "S"
) {
$numberOfFoundXMAS += 1;
}
// Check all to the Right meaning, we add getCharAt X+1, X+2, and X+3 and see if that spells "MAS"
if (
getCharAt(($startX + 1) . "," . $startY, $coordinateSystem) === "M" &&
getCharAt(($startX + 2) . "," . $startY, $coordinateSystem) === "A" &&
getCharAt(($startX + 3) . "," . $startY, $coordinateSystem) === "S"
) {
$numberOfFoundXMAS += 1;
}
// Check all to the Up meaning, we add getCharAt X,Y-1, X,Y-2, and X,Y-3 and see if that spells "MAS"
if (
getCharAt($startX . "," . ($startY - 1), $coordinateSystem) === "M" &&
getCharAt($startX . "," . ($startY - 2), $coordinateSystem) === "A" &&
getCharAt($startX . "," . ($startY - 3), $coordinateSystem) === "S"
) {
$numberOfFoundXMAS += 1;
}
// Check all to the Down meaning, we add getCharAt X,Y+1, X,Y+2, and X,Y+3 and see if that spells "MAS"
if (
getCharAt($startX . "," . ($startY + 1), $coordinateSystem) === "M" &&
getCharAt($startX . "," . ($startY + 2), $coordinateSystem) === "A" &&
getCharAt($startX . "," . ($startY + 3), $coordinateSystem) === "S"
) {
$numberOfFoundXMAS += 1;
}
// Check all to the Top Left meaning, we add getCharAt X-1,Y-1, X-2,Y-2, and X-3,Y-3 and see if that spells "MAS"
if (
getCharAt(($startX - 1) . "," . ($startY - 1), $coordinateSystem) === "M" &&
getCharAt(($startX - 2) . "," . ($startY - 2), $coordinateSystem) === "A" &&
getCharAt(($startX - 3) . "," . ($startY - 3), $coordinateSystem) === "S"
) {
$numberOfFoundXMAS += 1;
}
// Check all to the Top Right meaning, we add getCharAt X+1,Y-1, X+2,Y-2, and X+3,Y-3 and see if that spells "MAS"
if (
getCharAt(($startX + 1) . "," . ($startY - 1), $coordinateSystem) === "M" &&
getCharAt(($startX + 2) . "," . ($startY - 2), $coordinateSystem) === "A" &&
getCharAt(($startX + 3) . "," . ($startY - 3), $coordinateSystem) === "S"
) {
$numberOfFoundXMAS += 1;
}
// Check all to the Bottom Left meaning, we add getCharAt X-1,Y+1, X-2,Y+2, and X-3,Y+3 and see if that spells "MAS"
if (
getCharAt(($startX - 1) . "," . ($startY + 1), $coordinateSystem) === "M" &&
getCharAt(($startX - 2) . "," . ($startY + 2), $coordinateSystem) === "A" &&
getCharAt(($startX - 3) . "," . ($startY + 3), $coordinateSystem) === "S"
) {
$numberOfFoundXMAS += 1;
}
// Check all to the Bottom Right meaning, we add getCharAt X+1,Y+1, X+2,Y+2, and X+3,Y+3 and see if that spells "MAS"
if (
getCharAt(($startX + 1) . "," . ($startY + 1), $coordinateSystem) === "M" &&
getCharAt(($startX + 2) . "," . ($startY + 2), $coordinateSystem) === "A" &&
getCharAt(($startX + 3) . "," . ($startY + 3), $coordinateSystem) === "S"
) {
$numberOfFoundXMAS += 1;
}
}
function checkForMSTopAndBottomCorners($coordinate, $coordinateSystem, &$numberOfFoundXMAS)
{
// The starting X,Y coordinates
[$startX, $startY] = array_map('intval', explode(",", $coordinate));
// Check if the Top Left and Top Right "M" and "S", and same with the Bottom Left & Right
// OR "S S" on top and "M M" on bottom or "S M" on top and "S M" on bottom
if (
(getCharAt(($startX - 1) . "," . ($startY - 1), $coordinateSystem) === "M" && // Top Left
getCharAt(($startX + 1) . "," . ($startY - 1), $coordinateSystem) === "S" && // Top Right
getCharAt(($startX - 1) . "," . ($startY + 1), $coordinateSystem) === "M" && // Bottom Left
getCharAt(($startX + 1) . "," . ($startY + 1), $coordinateSystem) === "S") // Bottom Right
||
(getCharAt(($startX - 1) . "," . ($startY - 1), $coordinateSystem) === "S" &&
getCharAt(($startX + 1) . "," . ($startY - 1), $coordinateSystem) === "S" &&
getCharAt(($startX - 1) . "," . ($startY + 1), $coordinateSystem) === "M" &&
getCharAt(($startX + 1) . "," . ($startY + 1), $coordinateSystem) === "M")
||
(getCharAt(($startX - 1) . "," . ($startY - 1), $coordinateSystem) === "S" &&
getCharAt(($startX + 1) . "," . ($startY - 1), $coordinateSystem) === "M" &&
getCharAt(($startX - 1) . "," . ($startY + 1), $coordinateSystem) === "S" &&
getCharAt(($startX + 1) . "," . ($startY + 1), $coordinateSystem) === "M")
||
(getCharAt(($startX - 1) . "," . ($startY - 1), $coordinateSystem) === "M" &&
getCharAt(($startX + 1) . "," . ($startY - 1), $coordinateSystem) === "M" &&
getCharAt(($startX - 1) . "," . ($startY + 1), $coordinateSystem) === "S" &&
getCharAt(($startX + 1) . "," . ($startY + 1), $coordinateSystem) === "S")
) {
$numberOfFoundXMAS += 1;
}
}
$numberOfFoundXMAS = 0;
foreach ($coordinateSystem as $coord => $value) {
if ($value === "X") {
checkForMASAllDirections($coord, $coordinateSystem, $numberOfFoundXMAS);
}
}
echo "Found XMAS/SAMX in Total (Part 1): $numberOfFoundXMAS\n";
$numberOfFoundXMAS = 0;
foreach ($coordinateSystem as $coord => $value) {
if ($value === "A") {
checkForMSTopAndBottomCorners($coord, $coordinateSystem, $numberOfFoundXMAS);
}
}
echo "Found XMAS/SAMX in Total (Part 2): $numberOfFoundXMAS\n";
?>
Det var som sjutton! Tack vare en redan mycket vÀlfungerande koordinatfunktion som hanterar specialfall som skivat smör pÄ ishockeyplaner sÄ blev Del 2 mycket enkelt för det var liknande koncept hÀr.
Tur att vad skulle kunna kallas för !n-talet hĂ€r var mycket lĂ„gt annars hade det hĂ„rdkodade blivit mycket mer plĂ„gande!đ
EDIT: Attans, skulle ha postat 13:37. FĂ„r bli "Redigerat: 13:37" istĂ€llet! đ
Mvh,
WKF.
(V)ulnerabilities
(I)n
(B)asically
(E)verything
Programming
Dag: 4
SprÄk: Python (numpy och booliska operationer)
import numpy
Del 2 var vÀldigt mycket mindre kod Àn del 1....
def day(data: list, debug=False):
def get_valid_direction_indices(r, c):
# Compute all possible indices of the letters in XMAS
possible_directions = [r, c] - directions
# Sort out all vectors which are outside the board
boundary_1 = 0 <= possible_directions
x_y_coordinates = numpy.moveaxis(possible_directions, 2, 0)
boundary_2 = numpy.ones_like(x_y_coordinates, dtype=numpy.bool)
boundary_2[0] = x_y_coordinates[0] < cols
boundary_2[1] = x_y_coordinates[1] < rows
boundary_2 = numpy.moveaxis(boundary_2, [0, 1], [2, 0])
# Boolean operation AND
boundaries = boundary_1 & boundary_2
_valid_directions = list()
for direction, boundary in zip(possible_directions, boundaries):
if boundary.all():
# if debug:
# print(f' Valid direction: \n{direction}')
_valid_directions.append(direction)
else:
# if debug:
# print(f' Non valid direction:\n{direction} \n{boundary}')
pass
return _valid_directions
# Get shape of input data
rows = len(data)
cols = len(data[0])
# Create a word cloud
word_cloud = numpy.zeros([rows, cols], dtype=numpy.str_)
# Populate wordcloud
for row_no, row in enumerate(data):
word_cloud[row_no, :] = list(row)
if debug:
print(word_cloud)
print(' --- Part 1')
# Directions
directions = numpy.array([[[0, 0], [-1, 0], [-2, 0], [-3, 0]], # north
[[0, 0], [-1, 1], [-2, 2], [-3, 3]], # north_east
[[0, 0], [0, 1], [0, 2], [0, 3]], # east
[[0, 0], [1, 1], [2, 2], [3, 3]], # south_east
[[0, 0], [1, 0], [2, 0], [3, 0]], # south
[[0, 0], [1, -1], [2, -2], [3, -3]], # south_west
[[0, 0], [0, -1], [0, -2], [0, -3]], # west
[[0, 0], [-1, -1], [-2, -2], [-3, -3]]]) # north_west
xmas_found = 0
# Iterate over all positions
for i in range(0, rows):
for j in range(0, cols):
# Sanity check the first letter to be an X
if word_cloud[i, j] == 'X':
valid_directions = get_valid_direction_indices(i, j)
if debug:
print(f' i, k, valid directions: {i}, {j}, {len(valid_directions)}, {word_cloud[i, j]}')
for valid_direction in valid_directions:
xmass = str()
for x, y in valid_direction:
xmass += (word_cloud[x, y])
# Check if we got XMAS
if xmass == 'XMAS':
xmas_found += 1
print(' --- Part 2')
x_mas_found = 0
# Directions
directions = numpy.array([[[-1, -1], [0, 0], [+1, +1], [+1, -1], [0, 0], [-1, +1]],
[[-1, -1], [0, 0], [+1, +1], [-1, +1], [0, 0], [+1, -1]],
[[+1, +1], [0, 0], [-1, -1], [+1, -1], [0, 0], [-1, +1]],
[[+1, +1], [0, 0], [-1, -1], [-1, +1], [0, 0], [+1, -1]]])
wc = word_cloud
# Iterate over all positions, this time skipp the edges
for i in range(1, rows - 1):
for j in range(1, cols - 1):
# Sanity check the first letter to be an A
if word_cloud[i, j] == 'A':
for d in directions:
# Compute world cloud indices using relative directions
d = d + [i, j]
# Assemble potential x-mas
mas_1 = wc[d[0][0]][d[0][1]] + wc[d[1][0]][d[1][1]] + wc[d[2][0]][d[2][1]]
mas_2 = wc[d[3][0]][d[3][1]] + wc[d[4][0]][d[4][1]] + wc[d[5][0]][d[5][1]]
if mas_1 == mas_2 == "MAS":
x_mas_found += 1
print(f' Part 1 XMAS found: {xmas_found}, Part 2 X-MASS found: {x_mas_found}')
return xmas_found, x_mas_found
C2D E6300 @ 3.2HGz 1.2V | Thermalright 120 Extr. | Gainward 8800 GT Golden Sample |Samsung 2x500Gb | Corsair VX 550V | Antec P182 [img]http://valid.x86-secret.com/cache/banner/421648.png[/img]
Dag: 4
SprÄk: Python (i princip en one-liner)
a = [l.strip() for l in open("input04.txt", "r").readlines()]
print(*[sum(f(x,y)
for x in range(o, len(a) - o)
for y in range(o, len(a[0]) - o)
if a[x][y] == c)
for f, c, o in [(lambda x, y:sum([(0 <= x+3*dx < len(a) and
0 <= y+3*dy < len(a[0]) and
"".join([a[x+i*dx][y+i*dy] for i in range(4)]) == "XMAS")
for dx in range(-1, 2)
for dy in range(-1, 2)]), "X", 0),
(lambda x, y: ("".join([a[x-1][y-1], a[x-1][y+1], a[x+1][y-1], a[x+1][y+1]])
in ["MMSS", "SSMM", "MSMS", "SMSM"]), "A", 1)]])
Spelnyheter frÄn FZ
Copyright © 1999â2025 Geeks AB. Allt innehĂ„ll tillhör Geeks AB.
Citering Àr tillÄten om kÀllan anges.