[Advent Of Code 2022] Day 04: Camp Cleanup [SPOILERS]

Management wasn’t paying much attention when they handed out the assignments!

Thankfully we only need to solve pairs of elves and not detect all overlaps!

Summary
``````part1 = sum(
True
for a1, a2, b1, b2 in parsed_input
if (a1 >= b1 and a2 <= b2) or (b1 >= a1 and b2 <= a2)
)

part2 = sum(
True
for a1, a2, b1, b2 in parsed_input
if b1 <= a1 <= b2 or a1 <= b1 <= a2
)
``````

Reviewing my Pangram exercise notes this morning for Day 03 helped out a lot.

Julia Solution
``````module day04
function part01()
count = 0
start1, stop1, start2, stop2 = parse.(Int, split(l, r"[,-]"))
pair1 = range(start1, stop1)
pair2 = range(start2, stop2)
if (pair1 ⊆ pair2) || (pair2 ⊆ pair1)
count += 1
end
end
count
end

function part02()
count = 0
start1, stop1, start2, stop2 = parse.(Int, split(l, r"[,-]"))
pair1 = range(start1, stop1)
pair2 = range(start2, stop2)
if (!isempty(pair1 ∩ pair2))
count += 1
end
end
count
end
end
println("P01: \$(day04.part01())")
println("P02: \$(day04.part02())")
``````

I have a feeling this was the easiest day yet this year. It was good to have a more relaxed day. Calm before the storm

Typescript solution
``````interface Range {
min: number;
max: number;
}

interface RangePair {
first: Range;
second: Range;
}

interface State {
rangePairs: RangePair[];
}

export function parse(input: string): State {
return {
rangePairs: nonEmptyLines(input).map((l) => {
const [r1, r2] = l.split(",");
const [min1, max1] = r1.split("-").map((x) => parseInt(x, 10));
const [min2, max2] = r2.split("-").map((x) => parseInt(x, 10));
return {
first: { min: min1, max: max1 },
second: { min: min2, max: max2 },
};
}),
};
}

function isContainedBy(r1: Range, r2: Range): boolean {
return r1.min >= r2.min && r1.max <= r2.max;
}

function doesOverlap(r1: Range, r2: Range): boolean {
return r1.min <= r2.max && r1.max >= r2.min;
}

export function part1(parsed: State): string {
const containedRanges = parsed.rangePairs.filter((rangePair) => {
const { first, second } = rangePair;
return isContainedBy(first, second) || isContainedBy(second, first);
});

return containedRanges.length.toString();
}

export function part2(parsed: State): string {
const overlappedRanges = parsed.rangePairs.filter((rangePair) => {
const { first, second } = rangePair;
return doesOverlap(first, second) || doesOverlap(second, first);
});

return overlappedRanges.length.toString();
}
``````

I was also surprised that this was so smooth. I didn’t even leave the console to solve that one. So part 1 is a one-liner, as I forgot to make it as “pretty” as part 2.

``````defmodule AdventOfCode.Day04 do
def part1(args) do
args|> String.split() |> Enum.map(&String.split(&1, ~r{[\-\,]})) |> Enum.map(&Enum.map(&1, fn x -> String.to_integer(x) end)) |> Enum.map(fn [a,b,c,d] -> (a >= c and b <= d) or (c >= a and d <= b)  end) |> Enum.count(fn x -> x end)
end

def part2(args) do
args
|> String.split()
|> Enum.map(&String.split(&1, ~r{[\-\,]}))
|> Enum.map(&Enum.map(&1, fn x -> String.to_integer(x) end))
|> Enum.map(fn [a,b,c,d] -> (a >= c and a <= d) or (b >= c and b <= d) or (c >= a and c <= b) or (d >= a and d <= b)
end)
|> Enum.count(fn x -> x end)

end
end
``````
Ruby Solution
``````def contains(fst, snd) = fst[0] >= snd[0] && fst[1] <= snd[1]
def overlaps(fst, snd) = fst[0] >= snd[0] && fst[0] <= snd[1] || fst[1] >= snd[0] && fst[1] <= snd[1]

pairs = File.readlines('inputs/04.txt', chomp: true).map { |line| line.split(',').map { |assignment| assignment.split('-').map(&:to_i) } }
a = pairs.count { |fst, snd| contains(fst, snd) || contains(snd, fst) }
b = pairs.count { |fst, snd| overlaps(fst, snd) || overlaps(snd, fst) }
``````