# Day 4: Camp Cleanup

Please post your solutions in your own top-level comment. Here's a template you can copy-paste into your comment to format it nicely, with the code collapsed by default inside an expandable section with syntax highlighting (you can replace `python` with any of the "short names" listed in this page of supported languages):

``````<details>
<summary>Part 1</summary>

```python
```

</details>
``````

1. tjf
My Python solutions. Just like yesterday, sets are perfect here. Part 1 #!/usr/bin/env pypy3 import sys def main(): pairs = ([set(range(a, b + 1)) for a, b in c] for c in (([*map(int,...

My Python solutions. Just like yesterday, sets are perfect here.

Part 1
``````#!/usr/bin/env pypy3

import sys

def main():
pairs = ([set(range(a, b + 1)) for a, b in c] for c in
(([*map(int, d.split('-'))] for d in line.strip().split(','))
for line in sys.stdin))
overlaps = (a.issubset(b) or b.issubset(a) for a, b in pairs)
print(sum(overlaps))

if __name__ == '__main__':
main()
``````
Part 2
``````#!/usr/bin/env pypy3

import sys

def main():
pairs = ([set(range(a, b + 1)) for a, b in c] for c in
(([*map(int, d.split('-'))] for d in line.strip().split(','))
for line in sys.stdin))
overlaps = (a & b != set() for a, b in pairs)
print(sum(overlaps))

if __name__ == '__main__':
main()
``````
2. akk
(edited )
Pretty similar to yesterday if you ask me. Still love Swift! Part 1 and 2 import Foundation var totalFullSubRanges: Int = 0 var totalAnySubRanges: Int = 0 while let line = readLine() { let...

Pretty similar to yesterday if you ask me. Still love Swift!

Part 1 and 2
``````import Foundation

var totalFullSubRanges: Int = 0
var totalAnySubRanges: Int = 0

while let line = readLine() {
let sectionRanges = line.components(separatedBy: ",").map { \$0.components(separatedBy: "-").map { Int(\$0) ?? -1 } }
let rangeOne = Set(Array(sectionRanges[0][0]...sectionRanges[0][1]))
let rangeTwo = Set(Array(sectionRanges[1][0]...sectionRanges[1][1]))
if rangeOne.isSubset(of: rangeTwo) || rangeTwo.isSubset(of: rangeOne) {
totalFullSubRanges += 1
}

if !rangeOne.intersection(rangeTwo).isEmpty {
totalAnySubRanges += 1
}
}

print(totalFullSubRanges)
print(totalAnySubRanges)
``````
3. [4]
primordial-soup
advent of code is the only time that i write dynamically typed code these days. and lo and behold! 2/3rds of the time i took for part 1 was spent because i forgot to convert strings to ints and...

advent of code is the only time that i write dynamically typed code these days. and lo and behold! 2/3rds of the time i took for part 1 was spent because i forgot to convert strings to ints and didn't realize what was going wrong :')

Part 1, in Python-ish
``````(ls
> fe(X.split(",") | fe(X.split("-") | fe(int) | tuple)
| permutations | fe(as_args(λ a, b: a[0] <= b[0] <= b[1] <= a[1])) | any)
| sum
)
``````
Python code generated from the above
``````from itertools import permutations
from pipetools import X
from pipetools import as_args
from pipetools import foreach
import sys
from pyp import pypprint
fe = foreach
lines = [x.rstrip('\n') for x in sys.stdin]
ls = lines
output = ls > fe(X.split(',') | fe(X.split('-') | fe(int) | tuple) | permutations | fe(as_args(lambda a, b: a[0] <= b[0] <= b[1] <= a[1])) | any) | sum
if output is not None:
pypprint(output)
``````
Part 2, in Python-ish
``````(ls
> fe(X.split(",") | fe(X.split("-") | fe(int) | tuple)
| permutations | fe(as_args(λ a, b: a[0] <= b[0] <= a[1])) | any)
| sum
)
``````
Python code generated from the above
``````from itertools import permutations
from pipetools import X
from pipetools import as_args
from pipetools import foreach
import sys
from pyp import pypprint
fe = foreach
lines = [x.rstrip('\n') for x in sys.stdin]
ls = lines
output = ls > fe(X.split(',') | fe(X.split('-') | fe(int) | tuple) | permutations | fe(as_args(lambda a, b: a[0] <= b[0] <= a[1])) | any) | sum
if output is not None:
pypprint(output)
``````
1. [2]
bhrgunatha
Python-ish looks interesting. I could only find a github compiler to generate C++ from a python subset. Is it a pre-processor, interpreter, compiler? Something else?

Python-ish looks interesting. I could only find a github compiler to generate C++ from a python subset.

Is it a pre-processor, interpreter, compiler? Something else?

1. primordial-soup
(edited )
it is a little pre-processor i cobbled together. it has two stages: sed 's/λ/lambda/g'. (in the future i'd like to actually extend the grammar of an existing Python implementation instead of using...

it is a little pre-processor i cobbled together. it has two stages:

1. `sed 's/λ/lambda/g'`. (in the future i'd like to actually extend the grammar of an existing Python implementation instead of using this hack to mimic an extended grammar.)

2. `pyp` with a `pyprc.py` that is (for the most part)

`pyprc.py`
``````import plumbum.cmd as cmd
from plumbum import TF
from functools import *
from itertools import *
from operator import *
from pipetools import *
stdout = sys.stdout
p = pipe
fe = foreach
fe_do = foreach_do
Xp = xpartial
from more_itertools import *
import numpy as np

ls = lines
# string input parsing
n = int(l)
ns = lines > foreach(int) | list
y = float(l)
ys = lines > foreach(float) | list
f = l.split()
fs = lines > foreach(X.split()) | list
``````

much of the cool stuff happening is actually not done by preprocessing—it's `pipetools`'s pure-Python tricks with heavy usage of `(more_)?itertools` on top.

2. ras
Same story here.

Same story here.

1 vote
4. soks_n_sandals
Today was way easier in bash than yesterday. I made a mistake in part 1 (see spoiler) and tried to get too clever in part 2. A simple solution was good enough. Part 1+2 In part 1, I missed the...

Today was way easier in bash than yesterday. I made a mistake in part 1 (see spoiler) and tried to get too clever in part 2. A simple solution was good enough.

Part 1+2 In part 1, I missed the 'continue' command and some overlaps were double counted. Adding it got the right answer.
``````#!/usr/bin/env bash

file=day4.dat
part=2

if [[ \${part} -eq 1 ]]; then
# /////////////////////////////////////////////////////////////////////////////
#part 1 0.55s // 463
sed 's/-/ /g' \$file > \$file.tmp
sum=0
while IFS=, read -r range1 range2 || [[ -n \${range1} ]]; do
ranges=(\$(echo \$range1 \$range2))
if [[ \${ranges[2]} -le \${ranges[0]} && \${ranges[3]} -ge \${ranges[1]} ]]; then
((sum = sum + 1))
continue #mandatory to make sure we don't double count somehow
fi

if [[ \${ranges[0]} -le \${ranges[2]} && \${ranges[1]} -ge \${ranges[3]}  ]]; then
((sum = sum + 1))
continue
fi
done < \$file.tmp

echo Part 1: \$sum
# /////////////////////////////////////////////////////////////////////////////
fi

if [[ \${part} -eq 2 ]]; then
# /////////////////////////////////////////////////////////////////////////////
#part 2  0.54s // 919
sed 's/-/ /g' \$file > \$file.tmp
sum=0
while IFS=, read -r range1 range2 || [[ -n \${range1} ]]; do
ranges=(\$(echo \$range1 \$range2))
if [[ \${ranges[2]} -le \${ranges[0]} && \${ranges[0]} -le \${ranges[3]} ]]; then
# echo overlap
# echo \${ranges[@]}
((sum=sum+1))
continue
fi

if [[ \${ranges[0]} -le \${ranges[2]} && \${ranges[2]} -le \${ranges[1]} ]]; then
# echo overlap
# echo \${ranges[@]}
((sum=sum+1))
continue
fi

done < \$file.tmp

echo Part 2: \$sum
# /////////////////////////////////////////////////////////////////////////////
fi

rm \$file.tmp
``````
5. [4]
bhrgunatha
I'm really annoyed at my performance today, but I'm always too hard on myself. I was delayed about ½ hour and in my haste to grab those sweet, sweet leaderboard points, made so many fundamental...

I'm really annoyed at my performance today, but I'm always too hard on myself.
I was delayed about ½ hour and in my haste to grab those sweet, sweet leaderboard points, made so many fundamental and stupid mistakes I feel ashamed at myself, leading to annoyance, bordering anger. :(

Request: Since I've mistyped it about 100,00 times...

Note mina,minb not min-efla/b etc..
...does anyone have a synonym for efl?
Part 1
``````(define (part-01 input)
(for/sum ([elves (in-list input)]
#:when (contained? (assignments elves)))
1))

(define (assignments elves)
(map string->number (regexp-match* #px"\\d+" elves)))

(define (contained? elves)
(match-define (list mina maxa minb maxb) elves)
(or (and (<= mina minb) (>= maxa maxb))
(and (<= minb mina) (>= maxb maxa))))
``````
Part 2
``````(define (part-02 input)
(for/sum ([elves (in-list input)]
#:when (overlap? (assignments elves)))
1))

(define (overlap? elves)
(match-define (list mina maxa minb maxb) elves)
(or (and (>= maxa minb) (>= maxb mina))
(and (>= maxb mina) (>= maxa minb))))
``````
Speedrun ta;wf Too annoyed, won't fix

Oh well, there's always tomorrow :)

1. [3]
thorondir
This, I feel, went much better than day 03. Part 1 ;; function to make input usable (define (sanitize-input input) (for/list ([l (string-split input "\n")]) (parse-values l))) ;; take the small...

This, I feel, went much better than day 03.

Part 1
``````;; function to make input usable
(define (sanitize-input input)
(for/list ([l (string-split input "\n")])
(parse-values l)))

;; take the small input from the text
(define raw-small-input (file->string "small-input_04"))
(define small-input (sanitize-input raw-small-input))

(define (process-line line)
(define l (first line))
(define r (second line))
(if (or (and (<= (first l) (first r))
(>= (second l) (second r)))
(and (>= (first l) (first r))
(<= (second l) (second r))))
#t
#f))

;; workhorse, part 1
(define (part-1 input)
(for/fold ([acc 0]
#:result acc)
([l input])
(if (process-line l)
acc)))
``````

And I'm quite proud of the overlap function. xD

Part 2
``````(define (overlap? line)
(define l (first line))
(define r (second line))
(if (or (< (second l) (first r))
(> (first l) (second r)))
#f
#t))

;; part 2

(define (part-2 input)
(for/fold ([acc 0]
#:result acc)
([l input])
(if (overlap? l)
acc)))
``````

I know the destructuring in `process-line` and `overlap?` aren't necessary, but it was easier to think about, this way. :D

1. [2]
bhrgunatha
(edited )
You can simplify de-structuring of lists (and structs and others) with match-define (define a (first <alist>)) (define b (second <alist>) (define c (second <alist>) (match-define (list a b c)...

You can simplify de-structuring of lists (and structs and others) with `match-define`

(define a (first <alist>))
(define b (second <alist>)
(define c (second <alist>)

(match-define (list a b c) <alist>)

you can go even further

(match-define (list (list a1 a2) (list a3 a4)) '((1 2) (3 4)))

matching is Racket is very powerful.

One thing I would point out is that in Racket, the only false value is the boolean value `#f`, sometimes written `#false`. Every other value is logically `#t`. So in conditions `null`, `0`, `-1`, `""`, ... even the void value returned by calling e.g. `(vector-set! v 1 7)` is considered logically `#t`.

That means writing `(if <expression> #t #f)` is redundant; it's logically identical to `<expression>`. Whatever is using that (and expecting a `#t` or `#f` value) will respond exactly the same when you just return `<expression>` by itself.

If you want the opposite, `(if <expression> #f #t)`, use `(not <expression>)`.

Of course it's your decision, and it doesn't mean you should never return a bare #t or #f - I'll often do that with a complex `cond` with several cases, but it's never needed with `if`.

1. thorondir

6. [3]
Crestwave
Easier one than yesterday for those of us without sets. Tiny AWK solutions: Part 1 #!/usr/bin/awk -f BEGIN { FS = "[,-]" } { sum += ((\$1 >= \$3 && \$2 <= \$4) || (\$3 >= \$1 && \$4 <= \$2)) } END {...

Easier one than yesterday for those of us without sets. Tiny AWK solutions:

Part 1
``````#!/usr/bin/awk -f
BEGIN { FS = "[,-]" }
{ sum += ((\$1 >= \$3 && \$2 <= \$4) || (\$3 >= \$1 && \$4 <= \$2)) }
END { print(sum) }
``````
Part 2
``````#!/usr/bin/awk -f
BEGIN { FS = "[,-]" }
{ sum += (\$1 <= \$4 && \$3 <= \$2) }
END { print(sum) }
``````
1. [2]
bhrgunatha
feeling incredibly stupid now looking at my test for overlaps... which translated would be ((\$1 <= \$4 && \$3 <= \$2) || (\$3 <= \$2 && \$1 <= \$4))

feeling incredibly stupid now looking at my test for overlaps...

which translated would be
`((\$1 <= \$4 && \$3 <= \$2) || (\$3 <= \$2 && \$1 <= \$4))`

1. Crestwave
Nah I had something even longer at first. I just took the time afterwards to distill it to a simpler form. :P

Nah I had something even longer at first. I just took the time afterwards to distill it to a simpler form. :P

1 vote
7. spit-evil-olive-tips
part 1 import re LINE_RE = re.compile(r'(\d+)-(\d+),(\d+)-(\d+)') with open('04.txt') as input_file: lines = input_file.readlines() count = 0 for line in lines: match = LINE_RE.match(line) start1,...
part 1
``````import re

LINE_RE = re.compile(r'(\d+)-(\d+),(\d+)-(\d+)')

with open('04.txt') as input_file:

count = 0

for line in lines:
match = LINE_RE.match(line)
start1, end1, start2, end2 = [int(group) for group in match.groups()]

# start1    start2 end2    end1
# start2    start1 end1    end2
if (start1 <= start2 and end2 <= end1) or \
(start2 <= start1 and end1 <= end2):
count += 1

print(count)
``````
part 2
``````--- aoc04a.py   2022-12-03 21:21:32.559129397 -0800
+++ aoc04b.py   2022-12-03 21:21:26.839086405 -0800
@@ -11,10 +11,10 @@
match = LINE_RE.match(line)
start1, end1, start2, end2 = [int(group) for group in match.groups()]

-    # start1    start2 end2    end1
-    # start2    start1 end1    end2
-    if (start1 <= start2 and end2 <= end1) or \
-       (start2 <= start1 and end1 <= end2):
+    # start1    start2    end1
+    # start2    start1    end2
+    if (start1 <= start2 <= end1) or \
+       (start2 <= start1 <= end2):
count += 1

print(count)
``````
8. asterisk
(edited )
Python import re def cleanup(full: bool = True) -> int: overlap: int = 0 for line in open("input.txt"): a, b, c, d = map(int, re.findall(r"\d+", line)) first = set(range(a, b + 1)) second =...
Python
``````import re

def cleanup(full: bool = True) -> int:
overlap: int = 0

for line in open("input.txt"):
a, b, c, d = map(int, re.findall(r"\d+", line))
first = set(range(a, b + 1))
second = set(range(c, d + 1))

if first.issubset(second) or second.issubset(first) if full else first.intersection(second):
overlap += 1

return overlap

print(cleanup())  # Part One: 498
print(cleanup(False))  # Part Two: 859
``````
Updated
``````-        if full and (first.issubset(second) or second.issubset(first)) or not full and first.intersection(second):
+        if first.issubset(second) or second.issubset(first) if full else first.intersection(second):
``````
9. jzimbel
Elixir Both parts defmodule AdventOfCode.Solution.Year2022.Day04 do def part1(input) do input |> String.split("\n", trim: true) |> Enum.map(&parse_ints/1) |> Enum.count(&superset_subset?/1) end...

Elixir

Both parts
``````defmodule AdventOfCode.Solution.Year2022.Day04 do
def part1(input) do
input
|> String.split("\n", trim: true)
|> Enum.map(&parse_ints/1)
|> Enum.count(&superset_subset?/1)
end

def part2(input) do
input
|> String.split("\n", trim: true)
|> Enum.map(&parse_ints/1)
|> Enum.count(&overlap?/1)
end

defp parse_ints(line) do
~r/^(\d+)-(\d+),(\d+)-(\d+)\$/
|> Regex.run(line, capture: :all_but_first)
|> Enum.map(&String.to_integer/1)
end

defp superset_subset?([a, b, x, y]) do
(a <= x and b >= y) or (a >= x and b <= y)
end

defp overlap?([a, b, x, y]) do
not Range.disjoint?(a..b, x..y)
end
end
``````
10. Eabryt
Definitely could have done this better if I had some more knowledge, which thanks to other solutions I have now! So hopefully that will help in future days, but for now you're stuck with this...

Definitely could have done this better if I had some more knowledge, which thanks to other solutions I have now! So hopefully that will help in future days, but for now you're stuck with this slightly messy code

Parts 1 & 2
``````def part1(lines):
print(f"Part 1!")
numTimes = 0
for line in lines:
first, second = line.split(',')
firstA = list(range(int(first.split('-')[0]), int(first.split('-')[1])+1))
secondA = list(range(int(second.split('-')[0]), int(second.split('-')[1])+1))
if set(firstA).issubset(set(secondA)) or set(secondA).issubset(set(firstA)):
numTimes += 1
print(f"Result: {numTimes}")

def part2(lines):
print(f"Part 2!")
numTimes = 0
for line in lines:
first, second = line.split(',')
fA = list(range(int(first.split('-')[0]), int(first.split('-')[1])+1))
sA = list(range(int(second.split('-')[0]), int(second.split('-')[1])+1))
if any(i in fA for i in sA):
numTimes += 1
print(f"Result: {numTimes}")

def openFile():

def main():
f = openFile()
part1(f)
part2(f)

if __name__ == '__main__':
main()
``````
11. tomf
(edited )
Google Sheets! EDIT! I am changing my answer. this took me forever -- and it all boiled down to me not converting REGEX outputs to values. Anyway, this is a few characters lighter anyway... Part 1...

EDIT! I am changing my answer.

this took me forever -- and it all boiled down to me not converting REGEX outputs to values. Anyway, this is a few characters lighter anyway...

Part 1
``````=ARRAYFORMULA(
IF(C2=FALSE,"Part 1",
QUERY(
SPLIT(A2:A,"-,"),
"select Count(Col1)
where
Col1 is not null and
(Col1 <= Col3 and Col2 >= Col4) or
(Col3 <= Col1 and Col4 >= Col2)
label Count(Col1) 'Part 1'")))
``````
Part 2
``````=ARRAYFORMULA(
QUERY(
SPLIT(A2:A,"-,"),
"select Count(Col1)
where Col1 is not null and
(Col1 <= Col4 and
Col3 <= Col2)
label Count(Col1) 'Part 2'"))
``````
12. [2]
wycy
Rust Rust use std::env; use std::io::{self, prelude::*, BufReader}; use std::fs::File; use std::ops::RangeInclusive; extern crate regex; use regex::Regex; struct Team { elf1:...

Rust

Rust
``````use std::env;
use std::fs::File;
use std::ops::RangeInclusive;

extern crate regex;
use regex::Regex;

struct Team {
elf1: RangeInclusive<usize>,
elf2: RangeInclusive<usize>,
}
impl Team {
pub fn has_overlaps1(&self) -> bool {
(self.elf1.contains(&self.elf2.start()) && self.elf1.contains(&self.elf2.end())) ||
(self.elf2.contains(&self.elf1.start()) && self.elf2.contains(&self.elf1.end()))
}
pub fn has_overlaps2(&self) -> bool {
self.elf1.contains(&self.elf2.start()) || self.elf1.contains(&self.elf2.end()) ||
self.elf2.contains(&self.elf1.start()) || self.elf2.contains(&self.elf1.end())
}
}
impl From<&String> for Team {
fn from(s: &String) -> Self {
let re = Regex::new(r"(\d+)\-(\d+),(\d+)\-(\d+)").unwrap();
let matches = re.captures(s).unwrap();
Self {
elf1: RangeInclusive::new(matches[1].parse().unwrap(),matches[2].parse().unwrap()),
elf2: RangeInclusive::new(matches[3].parse().unwrap(),matches[4].parse().unwrap()),
}
}
}

fn solve(input: &str) -> io::Result<()> {

// Input
let input: Vec<String> = match reader.lines().collect() {
Err(err) => panic!("Unknown error reading input: {}", err),
Ok(result) => result,
};

// Part 1
let part1 = input
.iter()
.map(Team::from)
.filter(|x| x.has_overlaps1())
.count();
println!("Part 1: {:?}", part1); // 450

// Part 2
let part2 = input
.iter()
.map(Team::from)
.filter(|x| x.has_overlaps2())
.count();
println!("Part 2: {:?}", part2); // 837

Ok(())
}

fn main() {
let args: Vec<String> = env::args().collect();
let filename = &args[1];
solve(&filename).unwrap();
}
``````
1. Toric
I ended up writing my own Range implementation, didnt think to look in std for one.

I ended up writing my own Range implementation, didnt think to look in std for one.

13. [3]
kari
I struggled with trying to convert each elf's assignment to a set. Nim is confusing... Nim (both parts) import std/[sets, sequtils, strutils, sugar] proc assignmentToSet(assignment: string):...

I struggled with trying to convert each elf's assignment to a set. Nim is confusing...

Nim (both parts)
``````import std/[sets, sequtils, strutils, sugar]

proc assignmentToSet(assignment: string): HashSet[int] =
# This is janky as hell... I'm so sorry, nim.
let assignmentSet = collect:
let intEnds = collect:
for a in assignment.split('-'):
parseInt(a)
(intEnds[0]..intEnds[1]).toSeq().toHashSet()
result = assignmentSet[0]

proc day04*() =
var
numProperSubsets = 0
numAnySubsets = 0

for line in lines("inputs/day04.in"):
let pairAssignments = line.split(',')
let assignment1 = assignmentToSet(pairAssignments[0])
let assignment2 = assignmentToSet(pairAssignments[1])

let intersection = assignment1 * assignment2

# Part 1
if intersection == assignment1 or intersection == assignment2:
numProperSubsets += 1

# Part 2
if intersection.len > 0:
numAnySubsets += 1

echo "Part 1: " & \$numProperSubsets
echo "Part 2: " & \$numAnySubsets
``````
1. [2]
petrichor
I didn't really use sets (did <= and if x in a..b instead) but here's a bit of a cleaner procedure: assignmentToSet proc assignmentToSet(assignment: string): HashSet[int] = let intEnds = collect:...

I didn't really use sets (did `<=` and `if x in a..b` instead) but here's a bit of a cleaner procedure:

assignmentToSet
``````proc assignmentToSet(assignment: string): HashSet[int] =
let intEnds = collect:
for a in assignment.split('-'):
parseInt(a)
return collect(for x in intEnds[0] .. intEnds[1]: {x})
``````
14. Toric
Decided to start impl on my custom types. Once again, rusts type system is coming in handy. Driver mod part1; mod part2; mod utilities; fn main() { let _input = include_str!("./input.txt"); let...

Decided to start impl on my custom types. Once again, rusts type system is coming in handy.

Driver
``````mod part1;
mod part2;
mod utilities;

fn main() {
let _input = include_str!("./input.txt");
let _structured_input = utilities::parse(_input);

println!("Part One");
println!("Result: {}", part1::part1(&_structured_input));

println!("Part Two");
println!("Result: {}", part2::part2(&_structured_input));
}
``````
Utils
``````use once_cell::sync::Lazy;
use regex::Regex;
#[derive(Debug, PartialEq, Eq)]
pub struct Range {
start: u16,
end: u16,
}

impl Range {
pub fn new(start: u16, end: u16) -> Self {
Self {
start: start.min(end),
end: end.max(start),
}
}

pub fn calc_size(&self) -> u16 {
self.start.abs_diff(self.end)
}

pub fn any_overlap(&self, other: &Self) -> bool {
self.start <= other.end && self.end >= other.start
}

pub fn calc_overlap(&self, other: &Self) -> Range {
let overlap_start = self.start.min(other.start);
let overlap_end = self.end.max(other.end);
Range::new(overlap_start, overlap_end)
}

pub fn complete_overlap(&self, other: &Self) -> bool {
self.calc_overlap(other) == *self || self.calc_overlap(other) == *other
}

pub fn start(&self) -> u16 {
self.start
}

pub fn end(&self) -> u16 {
self.end
}
}

static PARSE_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(\d+)-(\d+),(\d+)-(\d+)").unwrap());

pub fn parse(input: &str) -> Vec<(Range, Range)> {
input
.lines()
.map(|line| {
let cap = PARSE_REGEX.captures(line).unwrap();
(
Range::new(
cap.get(1).unwrap().as_str().parse().unwrap(),
cap.get(2).unwrap().as_str().parse().unwrap(),
),
Range::new(
cap.get(3).unwrap().as_str().parse().unwrap(),
cap.get(4).unwrap().as_str().parse().unwrap(),
),
)
})
.collect()
}
``````
Part 1
``````use crate::utilities::*;

pub fn part1(input: &[(Range, Range)]) -> usize {
input
.iter()
.filter(|tuple| tuple.0.complete_overlap(&tuple.1))
.count()
}
``````
Part 2
``````use crate::utilities::*;

pub fn part2(input: &[(Range, Range)]) -> usize {
input
.iter()
.filter(|tuple| tuple.0.any_overlap(&tuple.1))
.count()
}
``````
15. Gyrfalcon
When I first read the problem description, I went to sets, just like I did yesterday and like it seems like many people did here. Then, I got worried that this was a trick, and that I was going to...

When I first read the problem description, I went to sets, just like I did yesterday and like it seems like many people did here. Then, I got worried that this was a trick, and that I was going to create some kind of monstrosity with huge sets if I went that path, so I just went with keeping the high and low of each assignment and having to think about the conditionals for overlapping, which tripped me up for a little bit on part 2.

Parts 1 and 2
``````def create_assignments(pair: str) -> Tuple[Tuple[int, int], Tuple[int, int]]:
first, second = pair.split(",")
first_low = int(first.split("-")[0])
first_high = int(first.split("-")[1])
second_low = int(second.split("-")[0])
second_high = int(second.split("-")[1])
return ((first_low, first_high), (second_low, second_high))

def are_completely_overlapping(
assignments: Tuple[Tuple[int, int], Tuple[int, int]]
) -> bool:
return (
assignments[0][0] <= assignments[1][0]
and assignments[0][1] >= assignments[1][1]
) or (
assignments[1][0] <= assignments[0][0]
and assignments[1][1] >= assignments[0][1]
)

def are_overlapping(assignments: Tuple[Tuple[int, int], Tuple[int, int]]) -> bool:
return (
assignments[0][1] >= assignments[1][0]
and assignments[0][0] <= assignments[1][1]
)

def main(filepath: str) -> Tuple[int, int]:
assignments = [create_assignments(pair) for pair in pairs]
return (
sum((are_completely_overlapping(assignment) for assignment in assignments)),
sum((are_overlapping(assignment) for assignment in assignments)),
)
``````
1 vote
16. Crespyl
More sets! I did wonder if maybe there'd be some trick to part 2 that would mean using sets would blow up somehow, but figured that we're still only on day 4. Clojure (both parts) (defn parse-line...

More sets!

I did wonder if maybe there'd be some trick to part 2 that would mean using sets
would blow up somehow, but figured that we're still only on day 4.

Clojure (both parts)
``````(defn parse-line [line]
(let [[[g1-start g1-end] [g2-start g2-end]]
(->> line
(re-matches #"(\d+)-(\d+),(\d+)-(\d+)")
(rest)
(map parse-long)
(partition 2))
group1 (set (range g1-start (inc g1-end)))
group2 (set (range g2-start (inc g2-end)))]
[group1, group2]))

(defn subset-or-superset [set1 set2]
(or (clojure.set/subset? set1 set2)
(clojure.set/subset? set2 set1)))

(defn overlaps? [set1 set2]
(not-empty (clojure.set/intersection set1 set2)))

(defn part-1 [input]
(let [set-pairs (map parse-line input)]
(->> set-pairs
(map #(apply subset-or-superset %))
(filter true?)
(count))))

(defn part-2 [input]
(let [set-pairs (map parse-line input)]
(->> set-pairs
(map #(apply overlaps? %))
(filter #(not (nil? %)))
(count))))
``````
1 vote
17. balooga
Here's my TypeScript solution type InputData = [[number, number], [number, number]][]; function formatInput(input: string): InputData { return input.split('\n').map(e => e.split(',').map(f =>...
Here's my TypeScript solution
``````type InputData = [[number, number], [number, number]][];

function formatInput(input: string): InputData {
return input.split('\n').map(e => e.split(',').map(f => f.split('-').map(g => Number(g)))) as InputData;
}

export function run(input: string): string[] {
const data = formatInput(input);
``````
Part 1
``````  const countFullContainments = (pairs: InputData): number => {
let count = 0;
for (const pair of pairs) {
if (
(pair[0][0] <= pair[1][0] && pair[0][1] >= pair[1][1]) ||
(pair[1][0] <= pair[0][0] && pair[1][1] >= pair[0][1])
) {
count++;
}
}
return count;
};
``````
Part 2

I got lazy here and decided to count the non-overlapping pairs, and subtract that number from the whole. Gets the job done.

``````  const countOverlaps = (pairs: InputData): number => {
let nonOverlapCount = 0;
for (const pair of pairs) {
if (pair[0][1] < pair[1][0] || pair[0][0] > pair[1][1]) {
nonOverlapCount++;
}
}
return pairs.length - nonOverlapCount;
};
``````
``````  return [`\${countFullContainments(data)}`, `\${countOverlaps(data)}`];
}
``````
1 vote
18. ras
JavaScript solution, both parts import { readFileSync } from "fs"; const input = readFileSync("./input.txt", "utf-8").toString(); const groups = input.split("\n"); // Put numbers into an array...
JavaScript solution, both parts
``````import { readFileSync } from "fs";

const groups = input.split("\n");

// Put numbers into an array
const expandNumbers = (start, end) => {
let numbers = [];
for (let index = Number(start); index <= Number(end); index++) {
numbers.push(index);
}
return numbers;
};

// Check if either number contains the other completely
const containsAll = (left, right) => {
return (
left.every((number) => right.includes(number)) ||
right.every((number) => left.includes(number))
);
};

// Check if any of the numbers overlap
const containsSome = (left, right) => {
return (
left.some((number) => right.includes(number)) ||
right.some((number) => left.includes(number))
);
};

let part1 = 0;
let part2 = 0;

groups.forEach((group) => {
const [first, second] = group.split(",");

const [firstStart, firstEnd] = first.split("-");
const [secondStart, secondEnd] = second.split("-");

const firstExpanded = expandNumbers(firstStart, firstEnd);
const secondExpanded = expandNumbers(secondStart, secondEnd);

if (containsAll(firstExpanded, secondExpanded)) part1++;
if (containsSome(firstExpanded, secondExpanded)) part2++;
});

console.log(part1);
console.log(part2);
``````
1 vote
19. MeckiSpaghetti
Ruby require "active_support/all" sum = File .read("input.txt") .split(/-|,|\s/) .map(&:to_i) .each_slice(4) p1 = sum.count{ |a, b, c, d| (a..b).cover?(c..d) || (c..d).cover?(a..b) } p2 =...
Ruby
``````require "active_support/all"

sum = File
.split(/-|,|\s/)
.map(&:to_i)
.each_slice(4)

p1 = sum.count{ |a, b, c, d| (a..b).cover?(c..d) || (c..d).cover?(a..b) }
p2 = sum.count{ |a, b, c, d| (a..b).overlaps?(c..d) }

p p1 # Part 1
p p2 # Part 2
``````
1 vote
20. vord
Did this back-to-back with Day 3, this one was quite a bit easier IMO. Was able to hit part 2 merely adding a second "if". Typescript Solution import * as fs from 'node:fs/promises'; function...

Did this back-to-back with Day 3, this one was quite a bit easier IMO. Was able to hit part 2 merely adding a second "if".

Typescript Solution
``````import * as fs from 'node:fs/promises';

function parseNumbers(input: string): number[][] {
const pair: string[] = input.split(",");

let pair_array: number[][] = [];
for (const elf of pair) {
pair_array.push(elf.split("-").map((item: string) => parseInt(item)));
};

return pair_array;
};

async function main(): Promise<void> {
const assignments: string[] = (await fs.readFile("input/day4", "utf-8")).split("\n");

const pairs: number[][][] = assignments.map(
(pair: string): number[][] => parseNumbers(pair));

let fully_contained: number = 0;
let overlap: number = 0;

for (const pair of pairs) {
const elf_1_start = pair[0][0];
const elf_1_end = pair[0][1];
const elf_2_start = pair[1][0];
const elf_2_end = pair[1][1];

// Part 1
if (   (elf_1_start <= elf_2_start && elf_1_end >= elf_2_end)
|| (elf_2_start <= elf_1_start && elf_2_end >= elf_1_end)) {
fully_contained++;
};

// Part 2
if (   (elf_1_start <= elf_2_start && elf_1_end >= elf_2_start)
|| (elf_2_start <= elf_1_start && elf_2_end >= elf_1_start)) {
overlap++;
};
}

// Output
console.log("Fully Contained Range: ",fully_contained);
console.log("Overlapping Range: ",overlap);
};

main();
``````
1 vote
21. whispersilk
I'm using Rust this year, and trying to keep it std-only throughout the month. Part 1 use std::error::Error; use std::fs::File; use std::io::Read; fn main() -> Result<(), Box<dyn Error>> { let mut...

I'm using Rust this year, and trying to keep it `std`-only throughout the month.

Part 1
``````use std::error::Error;
use std::fs::File;

fn main() -> Result<(), Box<dyn Error>> {
let mut file = File::open("input_4.txt")?;
let mut contents = String::new();
let number_containing = contents.lines().fold(0, |acc, line| {
let mut pieces = line.splitn(2, ',').map(Range::from_str);
let first = pieces.next().unwrap();
let second = pieces.next().unwrap();
if Range::contains(&first, &second) {
acc + 1
} else {
acc
}
});
println!("{number_containing}");
Ok(())
}

struct Range {
start: u32,
end: u32,
}

impl Range {
// Creates a new Range from a string of the form "<start>-<end>"
fn from_str(s: &str) -> Range {
let mut pieces = s.splitn(2, '-');
let start = pieces.next().unwrap().parse::<u32>().unwrap();
let end = pieces.next().unwrap().parse::<u32>().unwrap();
Range {
start,
end
}
}

// Returns true if x contains y or y contains x
fn contains(x: &Range, y: &Range) -> bool {
(x.start <= y.start && x.end >= y.end) || (y.start <= x.start && y.end >= x.end)
}
}
``````
Part 2
``````use std::error::Error;
use std::fs::File;

fn main() -> Result<(), Box<dyn Error>> {
let mut file = File::open("input_4.txt")?;
let mut contents = String::new();
let number_containing = contents.lines().fold(0, |acc, line| {
let mut pieces = line.splitn(2, ',').map(Range::from_str);
let first = pieces.next().unwrap();
let second = pieces.next().unwrap();
if Range::overlaps(&first, &second) {
acc + 1
} else {
acc
}
});
println!("{number_containing}");
Ok(())
}

struct Range {
start: u32,
end: u32,
}

impl Range {
// Creates a new Range from a string of the form "<start>-<end>"
fn from_str(s: &str) -> Range {
let mut pieces = s.splitn(2, '-');
let start = pieces.next().unwrap().parse::<u32>().unwrap();
let end = pieces.next().unwrap().parse::<u32>().unwrap();
Range {
start,
end
}
}

// Returns true if x contains y or y contains x
fn contains(x: &Range, y: &Range) -> bool {
(x.start <= y.start && x.end >= y.end) || (y.start <= x.start && y.end >= x.end)
}

// Returns true if x and y overlap
fn overlaps(x:&Range, y: &Range) -> bool {
(x.start >= y.start && x.end <= y.end)
|| (x.end >= y.start && x.end <= y.end)
|| (y.start >= x.start && y.end <= x.end)
|| (y.end >= x.start && y.end <= x.end)
}
}
``````
1 vote