this post was submitted on 05 Dec 2024
26 points (100.0% liked)

Advent Of Code

1035 readers
1 users here now

An unofficial home for the advent of code community on programming.dev!

Advent of Code is an annual Advent calendar of small programming puzzles for a variety of skill sets and skill levels that can be solved in any programming language you like.

AoC 2024

Solution Threads

M T W T F S S
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25

Rules/Guidelines

Relevant Communities

Relevant Links

Credits

Icon base by Lorc under CC BY 3.0 with modifications to add a gradient

console.log('Hello World')

founded 2 years ago
MODERATORS
 

Day 5: Print Queue

Megathread guidelines

  • Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
  • You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL

FAQ

(page 2) 7 comments
sorted by: hot top controversial new old
[โ€“] JRaccoon@discuss.tchncs.de 1 points 4 months ago (2 children)

Java

Part 2 was an interesting one and my solution kinda feels like cheating. What I did I only changed the validation method from part 1 to return the indexes of incorrectly placed pages and then randomly swapped those around in a loop until the validation passed. I was expecting this to not work at all or take forever to run but surprisingly it only takes three to five seconds to complete.

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;

public class Day05 {
    private static final Random random = new Random();

    public static void main(final String[] args) throws IOException {
        final String input = Files.readString(Path.of("2024\\05\\input.txt"), StandardCharsets.UTF_8);
        final String[] inputSplit = input.split("[\r\n]{4,}");

        final List<PageOrderingRule> rules = Arrays.stream(inputSplit[0].split("[\r\n]+"))
            .map(row -> row.split("\\|"))
            .map(row -> new PageOrderingRule(Integer.parseInt(row[0]), Integer.parseInt(row[1])))
            .toList();

        final List<ArrayList<Integer>> updates = Arrays.stream(inputSplit[1].split("[\r\n]+"))
            .map(row -> row.split(","))
            .map(row -> Arrays.stream(row).map(Integer::parseInt).collect(Collectors.toCollection(ArrayList::new)))
            .toList();

        System.out.println("Part 1: " + updates.stream()
            .filter(update -> validate(update, rules).isEmpty())
            .mapToInt(update -> update.get(update.size() / 2))
            .sum()
        );

        System.out.println("Part 2: " + updates.stream()
            .filter(update -> !validate(update, rules).isEmpty())
            .map(update -> fixOrder(update, rules))
            .mapToInt(update -> update.get(update.size() / 2))
            .sum()
        );
    }

    private static Set<Integer> validate(final List<Integer> update, final List<PageOrderingRule> rules) {
        final Set<Integer> invalidIndexes = new HashSet<>();

        for (int i = 0; i < update.size(); i++) {
            final Integer integer = update.get(i);
            for (final PageOrderingRule rule : rules) {
                if (rule.x == integer && update.contains(rule.y) && i > update.indexOf(rule.y)) {
                    invalidIndexes.add(i);
                }
                else if (rule.y == integer && update.contains(rule.x) && i < update.indexOf(rule.x)) {
                    invalidIndexes.add(i);
                }
            }
        }

        return invalidIndexes;
    }

    private static List<Integer> fixOrder(final List<Integer> update, final List<PageOrderingRule> rules) {
        List<Integer> invalidIndexesList = new ArrayList<>(validate(update, rules));

        // Swap randomly until the validation passes
        while (!invalidIndexesList.isEmpty()) {
            Collections.swap(update, random.nextInt(invalidIndexesList.size()), random.nextInt(invalidIndexesList.size()));
            invalidIndexesList = new ArrayList<>(validate(update, rules));
        }

        return update;
    }

    private static record PageOrderingRule(int x, int y) {}
}
load more comments (2 replies)
[โ€“] aurele@sh.itjust.works 1 points 4 months ago

Elixir

defmodule AdventOfCode.Solution.Year2024.Day05 do
  use AdventOfCode.Solution.SharedParse

  @impl true
  def parse(input) do
    [rules, pages_list] =
      String.split(input, "\n\n", limit: 2) |> Enum.map(&String.split(&1, "\n", trim: true))

    {for(rule <- rules, do: String.split(rule, "|") |> Enum.map(&String.to_integer/1))
     |> MapSet.new(),
     for(pages <- pages_list, do: String.split(pages, ",") |> Enum.map(&String.to_integer/1))}
  end

  def part1({rules, pages_list}), do: solve(rules, pages_list, false)

  def part2({rules, pages_list}), do: solve(rules, pages_list, true)

  def solve(rules, pages_list, negate) do
    for pages <- pages_list, reduce: 0 do
      total ->
        ordered = Enum.sort(pages, &([&1, &2] in rules))

        if negate != (ordered == pages),
          do: total + Enum.at(ordered, div(length(ordered), 2)),
          else: total
    end
  end
end
[โ€“] morrowind@lemmy.ml 1 points 3 months ago

Smalltalk

parsing logic is duplicated between the two, and I probably could use part2's logic for part 1, but yeah

part 1

day5p1: in
	| rules pages i j input |

	input := in lines.
	i := input indexOf: ''.
	rules := ((input copyFrom: 1 to: i-1) collect: [:l | (l splitOn: '|') collect: #asInteger]).
	pages := (input copyFrom: i+1 to: input size) collect: [:l | (l splitOn: ',') collect: #asInteger].
	
	^ pages sum: [ :p |
		(rules allSatisfy: [ :rule |
			i := p indexOf: (rule at: 1).
			j := p indexOf: (rule at: 2).
			(i ~= 0 & (j ~= 0)) ifTrue: [ i < j ] ifFalse: [ true ]
		])
			ifTrue: [p at: ((p size / 2) round: 0) ]
			ifFalse: [0].
	]

part 2

day5p2: in
	| rules pages i pnew input |

	input := in lines.
	i := input indexOf: ''.
	rules := ((input copyFrom: 1 to: i-1) collect: [:l | (l splitOn: '|') collect: #asInteger]).
	pages := (input copyFrom: i+1 to: input size) collect: [:l | (l splitOn: ',') collect: #asInteger].
	
	^ pages sum: [ :p |
		pnew := p sorted: [ :x :y | 
			rules anySatisfy: [ :r | (r at: 1) = x and: [ (r at: 2) = y]]
		].
		pnew ~= p
			ifTrue: [ pnew at: ((pnew size / 2) round: 0) ]
			ifFalse: [0].
	]
[โ€“] Leavingoldhabits@lemmy.world 1 points 4 months ago

Still in rust, and still inexperienced.

Forgot to make a separate solve for part two, for part one, imagine this without the make_valid function and some slightly different structure changes around the accumulator in babbage().

Used a hash map to track what should be in order, and a few indexed loops to keep track of where Iโ€™m at and where to look forward.

Day 5

[โ€“] sleeplessone@lemmy.ml 0 points 4 months ago

Rust

Kinda sorta got day 5 done on time.

use std::cmp::Ordering;

use crate::utils::{bytes_to_num, read_lines};

pub fn solution1() {
    let mut lines = read_input();
    let rules = parse_rules(&mut lines);

    let middle_rules_sum = lines
        .filter_map(|line| {
            let line_nums = rule_line_to_list(&line);
            line_nums
                .is_sorted_by(|&a, &b| is_sorted(&rules, (a, b)))
                .then_some(line_nums[line_nums.len() / 2])
        })
        .sum::<usize>();

    println!("Sum of in-order middle rules = {middle_rules_sum}");
}

pub fn solution2() {
    let mut lines = read_input();
    let rules = parse_rules(&mut lines);

    let middle_rules_sum = lines
        .filter_map(|line| {
            let mut line_nums = rule_line_to_list(&line);

            (!line_nums.is_sorted_by(|&a, &b| is_sorted(&rules, (a, b)))).then(|| {
                line_nums.sort_by(|&a, &b| {
                    is_sorted(&rules, (a, b))
                        .then_some(Ordering::Less)
                        .unwrap_or(Ordering::Greater)
                });

                line_nums[line_nums.len() / 2]
            })
        })
        .sum::<usize>();

    println!("Sum of middle rules = {middle_rules_sum}");
}

fn read_input() -> impl Iterator<Item = String> {
    read_lines("src/day5/input.txt")
}

fn parse_rules(lines: &mut impl Iterator<Item = String>) -> Vec<(usize, usize)> {
    lines
        .take_while(|line| !line.is_empty())
        .fold(Vec::new(), |mut rules, line| {
            let (a, b) = line.as_bytes().split_at(2);
            let a = bytes_to_num(a);
            let b = bytes_to_num(&b[1..]);

            rules.push((a, b));

            rules
        })
}

fn rule_line_to_list(line: &str) -> Vec<usize> {
    line.split(',')
        .map(|s| bytes_to_num(s.as_bytes()))
        .collect::<Vec<_>>()
}

fn is_sorted(rules: &[(usize, usize)], tuple: (usize, usize)) -> bool {
    rules.iter().any(|&r| r == tuple)
}

Reusing my bytes_to_num function from day 3 feels nice. Pretty fun challenge.

load more comments
view more: โ€น prev next โ€บ