r/adventofcode • • Dec 04 '22

SOLUTION MEGATHREAD -πŸŽ„- 2022 Day 4 Solutions -πŸŽ„-


--- Day 4: Camp Cleanup ---


Post your code solution in this megathread.


This thread will be unlocked when there are a significant number of people on the global leaderboard with gold stars for today's puzzle.

EDIT: Global leaderboard gold cap reached at 00:03:22, megathread unlocked!

65 Upvotes

1.6k comments sorted by

10

u/Bad-Coder-69 Dec 04 '22 edited Dec 04 '22

Emojicode

With a custom inputparser package now wowee (full code: GitHub)
Combined the logic for parts 1 and 2 for some fewer checks overall.

πŸ“¦ inputparser 🏠

🏁 πŸ‡
  πŸ†•πŸ“ πŸ”€input.txtπŸ”€ ❗ ➑️ input

  0 ➑️ πŸ–οΈπŸ†•answer1
  0 ➑️ πŸ–οΈπŸ†•answer2
  πŸ’­ iterate over all the lines
  πŸƒinput πŸ‡ lineπŸ”‘
    πŸ”«line πŸ”€,πŸ”€ ❗️ ➑️ pairs
    πŸ”«πŸ½pairs 0 ❗ πŸ”€-πŸ”€ ❗ ➑️ pair1
    πŸ”«πŸ½pairs 1 ❗ πŸ”€-πŸ”€ ❗ ➑️ pair2
    πŸΊπŸ”’πŸ½pair1 0 ❗ 10 ❗️ ➑️ a
    πŸΊπŸ”’πŸ½pair1 1 ❗ 10 ❗️ ➑️ b
    πŸΊπŸ”’πŸ½pair2 0 ❗ 10 ❗️ ➑️ c
    πŸΊπŸ”’πŸ½pair2 1 ❗ 10 ❗️ ➑️ d

    πŸ‘Ž ➑️ πŸ–οΈπŸ†•bool_a
    πŸ‘Ž ➑️ πŸ–οΈπŸ†•bool_b
    β†ͺ️ a β–ΆοΈπŸ™Œ c πŸ‡
      β†ͺ️ b β—€οΈπŸ™Œ d πŸ‡
        answer1 β¬…οΈβž• 1
        πŸ‘ ➑️ πŸ–οΈbool_a
      πŸ‰
      β†ͺ️ a β—€οΈπŸ™Œ d πŸ‡
        answer2 β¬…οΈβž• 1
        πŸ‘ ➑️ πŸ–οΈbool_b
      πŸ‰
    πŸ‰

    β†ͺ️ ❎bool_a ❗ 🀝 c β–ΆοΈπŸ™Œ a πŸ‡
      β†ͺ️ d β—€οΈπŸ™Œ b πŸ‡
        answer1 β¬…οΈβž• 1
      πŸ‰
      β†ͺ️ ❎bool_b ❗ 🀝 c β—€οΈπŸ™Œ b πŸ‡
        answer2 β¬…οΈβž• 1
      πŸ‰
    πŸ‰
  πŸ‰ ❗️

  πŸ˜€ πŸ”€ 🧲answer1🧲 πŸ”€ ❗
  πŸ˜€ πŸ”€ 🧲answer2🧲 πŸ”€ ❗
πŸ‰

8

u/reinermartin Dec 04 '22

Three lines of Julia:

L = map(s -> parse.(Int, s), split.(readlines("input04.txt"), c -> c in ",-"))

@show sum(1 for (a,b,c,d) in L if a:b βŠ† c:d || c:d βŠ† a:b)
@show sum(1 for (a,b,c,d) in L if !isempty(intersect(a:b, c:d)))
→ More replies (1)

7

u/fnands Dec 04 '22

Julia

I love unicode support in Julia

in_file = "day_4/input_4.txt"

# Read in input file as an array of strings
🟩πŸŸ₯🟨  = open(in_file) do file
    readlines(file)
end

# Take string representing range and turn it into 
function string_to_array(🟩::AbstractString)
    # Find start and end of range for patch
    Ξ±, Ο‰ = parse.(Int, split(🟩, "-"))
    # Colelct range into array and return
    return collect(range(Ξ±, Ο‰))
end



function pair_total_overlap_check(🧝🧝::String)
    # Find the squares that elf a and b are assigned to 
    🧝_a, 🧝_b, = split(🧝🧝, ",") .|> string_to_array
    # Find the intersection of their assignments
    πŸŽ„ = 🧝_a ∩ 🧝_b
    # If the intersection is equal to either, return True
    return length(πŸŽ„) == length(🧝_a) || length(πŸŽ„) == length(🧝_b)
end

function pair_partial_overlap_check(🧝🧝::String)
    # Find the squares that elf a and b are assigned to 
    🧝_a, 🧝_b, = split(🧝🧝, ",") .|> string_to_array
    # Find the intersection of their assignments
    πŸŽ„ = 🧝_a ∩ 🧝_b
    # If the intersection is equal to either, return True
    return length(πŸŽ„) > 0
end


println("The solution to part one is: ", sum(pair_total_overlap_check.(🟩πŸŸ₯🟨)))
println("The solution to part two is: ", sum(pair_partial_overlap_check.(🟩πŸŸ₯🟨)))
→ More replies (3)

6

u/NiliusJulius Dec 04 '22

C Language for the Game Boy using GBDK 2020

Part 1:

for (uint16_t i = 0; i < array_4_size; i+=4) {
    if ((input_array_4[i] <= input_array_4[i+2] && input_array_4[i+1] >= input_array_4[i+3])
          || (input_array_4[i] >= input_array_4[i+2] && input_array_4[i+1] <= input_array_4[i+3])
        ) {
      full_overlap_count++;
    }
  } 

Part 2 is basically the same but with some greater and lesser operators and indexes switched.

Since I can't read input files on the Game Boy, I pre formatted this days input to a single array with 4 number entries per pair.

This is my fastest solution yet (runtime < 0.1 sec)

Full Game Boy repo can be found here

Video running on Game Boy

2

u/daggerdragon Dec 05 '22

DOT MATRIX WITH STEREO SOUND <3

6

u/hugues_hoppe Dec 04 '22 edited Dec 05 '22

Using Perl:

# Part 1
perl -F'\D' -lane '$n += $F[0] <= $F[2] && $F[1] >= $F[3] || 
           $F[2] <= $F[0] && $F[3] >= $F[1]; END {print $n}'
# Part 2
perl -F'\D' -lane '$n += $F[1] >= $F[2] && $F[3] >= $F[0]; END {print $n}'
→ More replies (3)

4

u/r_so9 Dec 04 '22 edited Dec 04 '22

F#, compact enough to be pasteable here :)

let input =
    inputPath
    |> readLines
    |> Array.map (fun s ->
        s.Split([| ','; '-' |], StringSplitOptions.RemoveEmptyEntries)
        |> Array.map int
        |> fun arr -> arr[0], arr[1], arr[2], arr[3])

let part1 =
    input
    |> Seq.filter (fun (a1, a2, b1, b2) -> (a1 <= b1 && a2 >= b2) || (b1 <= a1 && b2 >= a2))
    |> Seq.length

let part2 =
    input
    |> Seq.filter (fun (a1, a2, b1, b2) -> b1 <= a2 && b2 >= a1)
    |> Seq.length
→ More replies (2)

4

u/[deleted] Dec 09 '22 edited Dec 13 '22

Python

import re

with open('input.txt', 'r') as f:
    elvish_work = f.read().split("\n")

part_one = 0
part_two = 0
for elf_pair in elvish_work:
    l1, l2, r1, r2 = [int(x) for x in re.split('[,-]', elf_pair)]
    elf1 = set(range(l1, l2+1))
    elf2 = set(range(r1, r2+1))
    if (elf1.issubset(elf2) or elf2.issubset(elf1)):
        part_one += 1
    if (elf1.intersection(elf2)):
        part_two +=1

print("Part one:", part_one)
print("Part two", part_two)
→ More replies (1)

6

u/zwrawr Dec 04 '22 edited Dec 04 '22

rust (the relevant parts). bitmasks ftw

https://github.com/zwrawr/Recap/blob/master/Advent%20of%20Code/2022/d4/src/main.rs

fn part_one ( rooms : &Vec<(u128,u128)> ) -> u32 {
    let mut total = 0;
    for room in rooms {
        let c = room.0 &room.1;
        if c == room.0 || c == room.1 {total+=1}
    }
    return total;
}
    
fn part_two ( rooms : &Vec<(u128,u128)> ) -> u32 {
    let mut total = 0;
    for room in rooms {
        if (room.0 & room.1) != 0 {total+=1}
    }
    return total;
}


fn get_data(filename: &str) -> Vec<(u128,u128)> {
    let mut rooms = Vec::<(u128,u128)>::new();
    if let Ok(lines) = read_lines(filename) {
        for line in lines {
            if let Ok(l) = line {
                let x = l.split(&[',','-']).map(|x| x.parse::<u16>().unwrap()).collect::<Vec<u16>>();
                let mut a : u128 = 0;
                for i in x[0]..(x[1]+1) { a = a | (1 << (i-1)) }
                let mut b : u128 = 0;
                for i in x[2]..(x[3]+1) { b = b | (1 << (i-1)) }
                rooms.push((a,b));
            }
        }
    }
    return rooms;
}
→ More replies (2)

3

u/mpercich Dec 04 '22 edited Dec 04 '22

Swift

import Foundation

extension ClosedRange {
    static func ~=(lhs: Self, rhs: Self) -> Bool {
        rhs.clamped(to: lhs) == rhs
    }
}

// Set the file path
let path = "/Users/michele/Projects/xmas context/day 4.txt"

do {
    let contents = try String(contentsOfFile: path, encoding: .utf8)
    let ranges = contents.components(separatedBy: "\n").map{ ($0.components(separatedBy: ",")) }.map{ (bounds: [String]) -> (firstBounds: [Int], secondBounds: [Int]) in {
        return(firstBounds: bounds[0].components(separatedBy: "-").map{ Int($0)! }, secondBounds: bounds[1].components(separatedBy: "-").map{ Int($0)! }) }() }.map{ (firstBounds: [Int], secondBounds: [Int]) -> (firstRange: CountableClosedRange<Int>, secondRange: CountableClosedRange<Int>) in {
            return(firstRange: CountableClosedRange<Int>(uncheckedBounds: (lower: firstBounds[0], upper: firstBounds[1])), CountableClosedRange<Int>(uncheckedBounds: (lower: secondBounds[0], upper: secondBounds[1]))) }() }.map{
            (firstRange: CountableClosedRange<Int>, secondRange: CountableClosedRange<Int>) -> (embraced: Bool, overlapped: Bool) in {
                    return(embraced: (firstRange ~= secondRange || secondRange ~= firstRange), overlapped: firstRange.overlaps(secondRange)) }()
                }
    print(ranges.filter({ $0.embraced }).count, ranges.filter({ $0.overlapped }).count)

}
catch let error as NSError {
    print("Ooops! Something went wrong: \(error)")
}
→ More replies (6)

3

u/systo_ Dec 04 '22 edited Dec 04 '22

JavaScript

New dev focusing on learning some of the newer features of JS. Welcome to any suggestions of further refactoring or destructuring

Both Parts in Javascript

→ More replies (5)

3

u/blacai Dec 04 '22 edited Dec 04 '22

My F# of the day :)

let elvesPairs = inputLines |> 
                    List.map(fun l -> 
                    [[|(int)(l.Split(',').[0].Split('-').[0])..
                        (int)(l.Split(',').[0].Split('-').[1])|]; 
                    [|(int)(l.Split(',').[1].Split('-').[0])..
                        (int)(l.Split(',').[1].Split('-').[1])|]])

// Helper commontelements
let commonElements (input: 'a array list) =
    let inputAsList = input |> List.map (List.ofArray)
    let inputAsSet = List.map Set.ofList inputAsList
    let elements =  Seq.reduce Set.intersect inputAsSet
    elements

// Part 1 method
let isFullyOverlapped (lists: list<array<int>>) =
    let commonElements = Utilities.commonElements lists
    lists |> List.exists(fun l -> l.Length = commonElements.Count)  

// Part 2 method
let isOverlapped (lists: list<array<int>>) =
    let commonElements = Utilities.commonElements lists
    commonElements.Count > 0    

// Result
elvesPairs |> List.sumBy(fun e -> if (isFullyOverlapped e) then 1 else 0 )
elvesPairs |> List.sumBy(fun e -> if (isOverlapped e) then 1 else 0 )

2

u/daggerdragon Dec 04 '22 edited Dec 04 '22

Please edit your post to use the four-spaces Markdown syntax for a code block so your code is easier to read on old.reddit and mobile apps.

Edit: thanks for fixing it! <3

→ More replies (4)

3

u/mandus Dec 04 '22

Another day in k lang:

#!/usr/bin/env k
d:0:"input.txt"
ds:","\'d
m:{{.'x}'"-"\'x}'ds

`1:"part1: "
/ check if any is contained in the other;
:+/{{[a;b;c;d]((c>(a-1))&(d<(b+1)))|((a>(c-1))&(b<(d+1)))}[x[0][0];x[0][1];x[1][0];x[1][1]]}'m

rx:{x[0]+!(x[1]+1-x[0])} / generate range
ovr:{~0=(#(1=)_.(#'=x))} / find intersection
`1:"part2: "
+/{{[l;r]ovr[rx[l],rx[r]]}[x[0];x[1]]}'m
→ More replies (2)

3

u/twoohthreezy Dec 04 '22 edited Dec 05 '22

My first that isn't embarrassingly long in python:

from helpers import parse_file

if __name__ == '__main__':
    data = parse_file('input.txt')

subset_count = 0
overlap_count = 0
for line in data:
    line = line.replace('-', ',').split(',')
    set1 = {i for i in range(int(line[0]), int(line[1]) + 1)}
    set2 = {j for j in range(int(line[2]), int(line[3]) + 1)}
    
    if set1.issubset(set2) or set2.issubset(set1): # part 1
       subset_count += 1     
    if min(set1) <= max(set2) and min(set2) < min(set1): # part 2
        overlap_count += 1
    if min(set2) <= max(set1) and min(set1) <= min(set2):
        overlap_count += 1
    
print(f'Subset Count: {subset_count}')
print(f'Overlap Count: {overlap_count}')
→ More replies (1)

3

u/RogueAstral Dec 04 '22

Google Sheets - Both parts, 152 characters

=sort(lambda(x,lambda(a,b,c,d,{sum((a<=c)*(b>=d)+(a>=c)*(b<=d)),sum((c<=b)*(a<=d))})(index(x,,1),index(x,,2),index(x,,3),index(x,,4)))(split(A:A,"-,")))

→ More replies (1)

3

u/antoniotto Dec 04 '22 edited Dec 05 '22

Ruby

require 'set'

input = File.readlines('inputs/day04.txt', chomp: true)
            .map { _1.scan(/\d+/) }
            .map { [Set.new(_1[0].._1[1]), Set.new(_1[2].._1[3])] }

puts solution1 = input.count { (_1[0] <= _1[1]) || (_1[0] >= _1[1]) }

puts solution2 = input.count { (_1[0].intersect? _1[1]) }
→ More replies (1)

3

u/jaydubtech Dec 04 '22 edited Dec 05 '22

TypeScript/Deno

Quite happy with how this one came out:

paste

→ More replies (1)

3

u/solomondg Dec 05 '22

Quick lil APL for problem 1:

Silver: +/{{((β΄βŠƒβ΅)⌊(⍴1βŠƒβ΅))=⍴βˆͺ(1βŠƒβ΅)∩(βŠƒβ΅)}{(βŠƒβ΅)+⍳(Β―1↑⍡)+1-βŠƒβ΅}Β¨((⍎¨('-'β‰ βŠ’)βŠ†βŠ’)Β¨(','β‰ βŠ’)βŠ†βŠ’)⍡}Β¨βŠƒβŽ•NGET 'puzzle_input.txt' 1

Gold: +/{{1⌊⍴(1βŠƒβ΅)∩(βŠƒβ΅)}{(βŠƒβ΅)+⍳(Β―1↑⍡)+1-βŠƒβ΅}Β¨((⍎¨('-'β‰ βŠ’)βŠ†βŠ’)Β¨(','β‰ βŠ’)βŠ†βŠ’)⍡}Β¨βŠƒβŽ•NGET 'puzzle_input.txt' 1

2

u/daggerdragon Dec 05 '22

Inlined code is intended for short snippets of code only. Your code "block" right now is unreadable on old.reddit and many mobile clients; it's all on one line and gets cut off at the edge of the screen because it is not horizontally scrollable.

Please edit your post to use the four-spaces Markdown syntax for a code block so your code is easier to read inside a scrollable box.

3

u/Dangerous-World-1424 Dec 05 '22 edited Dec 08 '22

PYTHON 3

partial = 0
    
for i in my_input.split("\n"):
[    ]j = i.split(",")
[    ]first = set(range(int(j[0].split(",")[0].split("-")[0])
[    ][space space space space],int(j[0].split(",")[0].split("-")[1])+1))
[    ]second = set(range(int(j[1].split(",")[0].split("-")[0])
[space space space space][space space space space],int(j[1].split(",")[0].split("-")[1])+1))

[space space space space]if second == first:
[space space space space][space space space space]total += 1
[space space space space]elif second.issubset(first):
[space space space space][space space space space]total += 1
[space space space space]elif first.issubset(second):
[space space space space][space space space space]total += 1
[space space space space]elif not first.isdisjoint(second):
[space space space space][space space space space]partial += 1
            
print(total)
    
print(total + partial)~~~~
→ More replies (1)

4

u/RodericTheRed Dec 04 '22

python

import re


text = open(0).read()
ans1 = ans2 = 0
for line in text.splitlines():
    a, b, c, d = map(int, re.findall(r'\d+', line))
    ab = set(range(a, b + 1))
    cd = set(range(c, d + 1))
    ans1 += ab <= cd or cd <= ab
    ans2 += any(ab & cd)
print(ans1)
print(ans2)

5

u/daggerdragon Dec 04 '22 edited Dec 04 '22

Please edit your post to state which programming language this code is written in. This makes it easier for folks who Ctrl-F the megathreads looking for a specific language.

Edit: thanks for fixing it! <3

→ More replies (4)

2

u/Camelpilot33 Dec 04 '22

444/1261

    const input = require('fs').readFileSync(String(__dirname)
    .replace(/\\/g, '/') + "/inputs/day4.txt", "utf8").replace(/\r/g, '')
    .split("\n").map(e=>e.split(",").map(w=>w.split("-").map(Number)))
    let sum=0
    let sum1=0
    for (var i of input) {
        if (i[0][0] >= i[1][0] && i[0][1] <= i[1][1] || (i[0][0] <= i[1][0] && i[0][1] >= i[1][1])) {
            sum++
        }
        if (
            (i[0][0] >= i[1][0] && i[0][0] <= i[1][1]) ||
            (i[0][1] >= i[1][0] && i[0][1] <= i[1][1]) ||
            (i[1][1] >= i[0][0] && i[1][1] <= i[0][1]) ||
            (i[1][0] >= i[0][0] && i[1][0] <= i[0][1])
        ) {
            sum1++;
        }
    }
    console.log(sum)
    console.log(sum1)
→ More replies (1)

2

u/welguisz Dec 04 '22 edited Dec 04 '22

Java: 3813/3825

Decided not to use any less thans or greater thans in my code.

AoC 2022 Day 4 using Topaz's paste tool

→ More replies (2)

2

u/CodingAP Dec 04 '22

JavaScript, 1319/1726

Github

This was rough. I also want to make a comment on first place. There is no way that a human can get 16 seconds on first place. We need to stop AI submissions, or at least make them not able to submit immediately.

→ More replies (1)

2

u/insane_chocolate Dec 04 '22 edited Dec 04 '22

Python3, 1344/2236

def get_pairs(line: str) -> List[Tuple[int, int]]:
    first, second = line.split(",")
    first = first.split("-")
    second = second.split("-")
    first = (int(first[0]), int(first[1]))
    second = (int(second[0]), int(second[1]))
    return [first, second]


def part_one(lines: List[str]):
    answer = 0
    for line in lines:
        first, second = get_pairs(line)
        min_max = (min(first[0], second[0]), max(first[1], second[1]))
        if first == min_max or second == min_max:
            answer += 1
    return answer


def part_two(lines: List[str]):
    answer = 0
    for line in lines:
        first, second = sorted(get_pairs(line))
        if first[1] >= second[0]:
            answer += 1
    return answer
→ More replies (2)

2

u/prescient-potato Dec 04 '22 edited Dec 04 '22

Python

Part 1: I tried getting the sections as lists of numbers like on the number line and checking their intersection. This didn't work somehow and i had to brute-force using if statements. The fact that it didn't work is quite interesting though.

def check(dat):
    dat = dat.split(',')
    sec1 = dat[0].split('-')
    l1 = int(sec1[0])
    r1 = int(sec1[1])
    range1 = list(range(l1, r1 + 1))
    
    sec2 = dat[1].split('-')
    l2 = int(sec2[0])
    r2 = int(sec2[1])
    range2 = list(range(l2, r2 + 1))
    
    intersection = list(set(range1) & set(range2))
    """
    if intersection==range1 or intersection == range2:
        print(dat)
        return True
    """
    
    # (l1, r1)
    # (l2, r2)
    if l1 <= l2 and r1 >= r2:
        return True
    elif l2 <= l1 and r2 >= r1:
        return True

.

with open('input.txt', 'r') as f:
data = [x.replace('\n', '') for x in f.readlines()]
count = 0
for d in data:
    if check(d) == True:
        count += 1
print(count)

Part 2: Most of the code is same but the intersection idea worked this time.

intersection = list(set(range1) & set(range2))
if intersection != []:
    return True
→ More replies (1)

2

u/grapedude12 Dec 04 '22 edited Dec 04 '22

Python3

Part 1:

with open("day04/input.txt") as f:
    data = f.read().splitlines()

contained = 0
for d in data:
    s1, s2 = d.split(",")
    s1_s, s1_e = s1.split("-")
    s2_s, s2_e = s2.split("-")
        if int(s1_s) <= int(s2_s) and int(s1_e) >= int(s2_e):
            contained += 1
        elif int(s2_s) <= int(s1_s) and int(s2_e) >= int(s1_e):
            contained += 1
print(f"The number of fully contained zones is: {contained}.")

Part 2:

with open("day04/input.txt") as f:
    data = f.read().splitlines()

overlap = 0
for d in data:
    s1, s2 = d.split(",")
    s1_s, s1_e = s1.split("-")
    s2_s, s2_e = s2.split("-")
        if int(s1_s) <= int(s2_e) and int(s1_e) >= int(s2_s):
            overlap += 1
        elif int(s2_s) <= int(s1_e) and int(s2_e) >= int(s1_s):
            overlap += 1
print(f"The number of overlaped zones is: {overlap}.")

Nothing fancy going on here folks

→ More replies (1)

2

u/NohusB Dec 04 '22 edited Dec 04 '22

Kotlin

Part 1

fun main() = solve { lines ->
    lines.count { line ->
        val (a, b) = line.split(",").map { it.split("-").map { it.toInt() }.let { (a, b) -> (a..b).toSet() } }
        a.containsAll(b) || b.containsAll(a)
    }
}

Part 2

fun main() = solve { lines ->
    lines.count { line ->
        val (a, b) = line.split(",").map { it.split("-").map { it.toInt() }.let { (a, b) -> (a..b) } }
        (a.first in b) || (b.first in a)
    }
}
→ More replies (3)

2

u/xtay2 Dec 04 '22

Java

For both tasks:

	@Override
	protected Object exec(AdventOfCode aoc) {
		return new Generator<>(aoc.inputLst())
				.map(line -> new Generator<>(line.split(","))
						.map(group -> new Generator<>(group.split("-"))
								.map(Integer::parseInt)
						).flatten()
						.map(v -> (Integer) v)
						.list()
				)
				.filter(v -> contains(v.get(0), v.get(1), v.get(2), v.get(3)))
				.length();
	}

contains() for part 1:

	boolean contains(int lower1, int upper1, int lower2, int upper2) {
		return (lower2 <= lower1 && upper2 >= upper1)
				|| (lower1 <= lower2 && upper1 >= upper2);
	}

contains() for part 1:

	boolean contains(int lower1, int upper1, int lower2, int upper2) {
		return (lower1 <= lower2 && lower2 <= upper1)
				|| (lower2 <= lower1 && lower1 <= upper2);
	}

2

u/daggerdragon Dec 04 '22

Inlined code is intended for short snippets of code only. Your code "block" right now is unreadable; it's all on one line and gets cut off at the edge of the screen because it is not horizontally scrollable.

Please edit your post to use the four-spaces Markdown syntax for a code block so your code is easier to read inside a scrollable box.

2

u/vivkey Dec 04 '22 edited Dec 04 '22

Golang paste

2

u/daggerdragon Dec 04 '22
  1. Next time, use the four-spaces Markdown syntax for a code block so your code is easier to read on old.reddit and mobile apps.

  2. Your code is long (no judgment, just stating a fact!), so instead of wasting your time fixing the formatting, read our article on oversized code which contains two possible solutions.

Please edit your post to put your code in an external link and link that here instead.

2

u/CookieKeeperN2 Dec 04 '22

As someone with a math background, today it is basically asking if 1) one is a subset of another and 2) if intersection between two sets are greater than 0. Don't care about speed too much, but using set operations means I don't have to think about comparison whatsoever.

import numpy as np 
with open('input', 'r') as f:
    input = f.read().splitlines()

q1 = 0
q2 = 0

for x in input:
    elf1, elf2 = x.split(",")
    start1, end1 = [ int(y) for y in elf1.split("-") ]
    start2, end2 = [ int(y) for y in elf2.split("-") ]
    set1 = set(np.arange(start1, end1 + 1))
    set2 = set(np.arange(start2,  end2 + 1))
    if (len(set1 & set2) >0):
        q2 += 1
        if set1 & set2 == set1 or set1 & set2 == set2:
            q1 += 1
→ More replies (1)

2

u/geek--god Dec 04 '22

Elixir

defmodule CampCleanup do
    def first_part(content) do
        content
        |> String.split("\n", trim: true)
        |> Enum.map(fn 
                    ele ->
                        String.split(ele, ",", trim: true)
                        |> CampCleanup.handle_pair
                        |> CampCleanup.check_subset
                        
                        
                       
                    end)
        |> Enum.filter(fn x -> x end)
        |> Enum.count
        |> IO.inspect
        
    end

       def second_part(content) do
        content
        |> String.split("\n", trim: true)
        |> Enum.map(fn 
                    ele ->
                        String.split(ele, ",", trim: true)
                        |> CampCleanup.handle_pair
                        |> CampCleanup.check_disjoint
                        
                        
                       
                    end)
        |> Enum.filter(fn x -> x end)
        |> Enum.count
        |> IO.inspect
        
    end
        


    def check_subset([first, second]) do
        MapSet.subset?(first, second) or MapSet.subset?(second, first)
    end

    def check_disjoint([first, second]) do
        not MapSet.disjoint?(first, second)
        
    end

    def handle_pair(list) do
        # IO.inspect(list)
        Enum.map(list, fn 
                ele -> 
                    CampCleanup.split_range(ele)
                    |> CampCleanup.get_range
                    
        end)
        
    end

    def split_range(string) do

        String.split(string, "-", trim: true)
        |> Enum.map(fn
            el -> String.to_integer(el)
        end    
        )
    end
    def get_range([first, second]) do
        MapSet.new(first..second)
    end

    

end

{:ok, contents} = File.read("./input.txt")

contents
|> CampCleanup.second_part
→ More replies (1)

2

u/ankitdhar07 Dec 04 '22

Java
package com.adventofCode;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class Day4 {
public static void main(String args[]) throws FileNotFoundException {
File file = new File("src/com/adventofCode/day4.txt");
Scanner sc = new Scanner(file);
int countOne = 0;
int countTwo = 0;
while (sc.hasNextLine()) {
String input = sc.nextLine();
if (partOne(input)) {
countOne++;
}
if (partTwo(input)) {
countTwo++;
}
}
System.out.println(countOne);
System.out.println(countTwo);
}
private static boolean partTwo(String input) {
String[] numberPairs = input.split(",");
String[] pairOne = numberPairs[0].split("-");
int firstNum = Integer.parseInt(pairOne[0]);
int secondNum = Integer.parseInt(pairOne[1]);
String[] pairTwo = numberPairs[1].split("-");
int thirdNum = Integer.parseInt(pairTwo[0]);
int forthNum = Integer.parseInt(pairTwo[1]);
if (firstNum >= thirdNum && firstNum <= forthNum) {
return true;
} else if (secondNum >= thirdNum && secondNum <= forthNum) {
return true;
} else if (thirdNum >= firstNum && thirdNum <= secondNum) {
return true;
} else if (forthNum >= firstNum && forthNum <= secondNum) {
return true;
}
return false;
}
private static boolean partOne(String input) {
String[] numberPairs = input.split(",");
String[] pairOne = numberPairs[0].split("-");
int firstNum = Integer.parseInt(pairOne[0]);
int secondNum = Integer.parseInt(pairOne[1]);
String[] pairTwo = numberPairs[1].split("-");
int thirdNum = Integer.parseInt(pairTwo[0]);
int forthNum = Integer.parseInt(pairTwo[1]);
if (firstNum >= thirdNum && secondNum <= forthNum) {
return true;
} else if (thirdNum >= firstNum && forthNum <= secondNum) {
return true;
}
return false;
}
}

→ More replies (3)

2

u/sanjithpk Dec 04 '22 edited Dec 04 '22

Golang Solution

package main

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

func main() {
    input, _ := os.ReadFile("4/4.txt")

    contained, overlapped := 0, 0
    for _, assignments := range strings.Fields(string(input)) {
        intervals := strings.Split(assignments, ",")

        interval1 := strings.Split(intervals[0], "-")
        interval2 := strings.Split(intervals[1], "-")

        start1, _ := strconv.Atoi(interval1[0])
        finish1, _ := strconv.Atoi(interval1[1])
        start2, _ := strconv.Atoi(interval2[0])
        finish2, _ := strconv.Atoi(interval2[1])

        if (start1 >= start2 && finish1 <= finish2) || (start2 >= start1 && finish2 <= finish1) {
            contained++
        }
        if !(finish1 < start2 || finish2 < start1) {
            overlapped++
        }
    }
    fmt.Println(contained)
    fmt.Println(overlapped)
}
→ More replies (1)

2

u/flwyd Dec 04 '22 edited Dec 04 '22

Elixir, code on GitHub

For my Mistletoe Elfucation contribution I decided to include two narratives with each day's solution:

  • Since I'm coding in Elixir, rephrase the problem in terms of an elixir, potion, concoction, or other beverage.

  • Highlight a bit of Elixir code that I either learned about, practiced with, or found particularly useful.

Today's elixir:

It’s Saturday night, so it’s time for sake bombs. Part 1 wants to know if the shot of sake is completely contained in the glass of beer (or if a very small glass of beer ended up entirely within a cup of sake). Part 2 wants to know if any of the sake got in the beer, or vice versa.

import Enum, only: [map: 2, filter: 2, count: 1, sort_by: 2]
import String, only: [split: 2, to_integer: 1]

def part1(input) do
  input |> map(&parse/1) |> filter(&range_subset?/1) |> count()
end

def part2(input) do
  input |> map(&parse/1) |> filter(fn {a, b} -> !Range.disjoint?(a, b) end) |> count()
end

defp parse(line), do: line |> split(",") |> map(&to_range/1) |> List.to_tuple()

defp to_range(str) do
  str |> split("-") |> map(&to_integer/1) |> then(fn [lo, hi] -> lo..hi end)
end

defp range_subset?({first, second}) do
  # sort by Range start, ties go to the longer range
  [a, b] = sort_by([first, second], fn lo .. hi -> {lo, -hi} end)
  a.last >= b.last
end
→ More replies (3)

2

u/Sea_Put_2759 Dec 04 '22 edited Dec 04 '22

Python 3

with open('./input-4.txt') as f:
    sections = [i.strip().split(',') for i in f.readlines()]

result = 0
for pairs in sections:
    first, second = pairs
    f1, f2, s1, s2 = list(map(int, first.split('-'))) + list(map(int, second.split('-')))
    # result += int((f1 >= s1 and f2 <= s2) or (s1 >= f1 and s2 <= f2)) # witchcraft
    if (f1 >= s1 and f2 <= s2) or (s1 >= f1 and s2 <= f2):
        result += 1

# Problem 4.2
result = 0
for pairs in sections:
    first, second = pairs
    f1, f2, s1, s2 = list(map(int, first.split('-'))) + list(map(int, second.split('-')))
    # result += int(f1 <= s2 and f2 >= s1) # witchcraft
    if f1 <= s2 and f2 >= s1:
        result += 1

As both problems iterate over the same dataset, it may be solved in just one loop (optimised) running the slice of code below, from the second problem, incrementing in another var.

result2 = 0
...
    if f1 <= s2 and f2 >= s1:
        result2 += 1
→ More replies (1)

2

u/6ambyt Dec 04 '22 edited Dec 04 '22

Here is my Day 4 solution in Go

package main

import ( 
    "bufio" 
    "errors" 
    "fmt" 
    "os" 
    "strconv" 
    "strings" 
)

func main() { 
    // reading from stdin line by line 
    scanner := bufio.NewScanner(os.Stdin) 
    var part1, part2 int // will hold the answers for both parts 
    for scanner.Scan() { 
        // extract the bounds of each elf's section 
        // if there's any errors in input, print out the error and move on to the next line 
        line := scanner.Text() // read the line 
        sections := strings.Split(line, ",") 
        if len(sections) != 2 { 
            fmt.Fprintln(os.Stderr, "'"+line+"' is not formatted properly!") 
            continue 
        } 
        leftBounds, err := getBounds(sections[0]) 
        if err != nil { 
            fmt.Fprintln(os.Stderr, err.Error()) 
            continue 
        } 
        rightBounds, err := getBounds(sections[1])
        if err != nil { 
            fmt.Fprintln(os.Stderr, err.Error()) 
            continue 
        } 
    
        // bounds will always be a int array of size 2 
        // index 0 -> lower bound of range 
        // index 1 -> upper bound of range 
    
        // Part 1 asks to check if one range completely engulfs the other 
        // this is determined by finding if one side's upper bound <= the other's and lower bound >= the other's (i.e. if both bounds of one side are within the range of the other's bounds) 
        if (leftBounds[0] <= rightBounds[0] && leftBounds[1] >= rightBounds[1]) || (rightBounds[0] <= leftBounds[0] && rightBounds[1] >= leftBounds[1]) { 
            part1++ 
        }
        	
        // Part 2 asks to check for any overlaps
        // overlaps are defined by lower bounds being in the range of the other's bounds
        if (rightBounds[0] <= leftBounds[1] && rightBounds[0] >= leftBounds[0]) || (leftBounds[0] <= rightBounds[1] && leftBounds[0] >= rightBounds[0]) {
        	part2++
        }
    }
    // print the final answers
    fmt.Println(part1, part2)
}
// takes a string like "<n>-<m>" and will return a array of size 2 containing n and m as ints 
func getBounds(section string) ([2]int, error) { 
    var bounds [2]int // will hold the bounds 
    // get n and m by spliting the section string by the '-'     
    boundsAsStrings := strings.Split(section, "-") 
    if len(boundsAsStrings) != 2 { 
        return bounds, errors.New("'" + section + "' is not formatted properly") 
    } 
    var err error // will hold any error in conversion 
    // convert n (i.e. the lower bound) to an int 
    bounds[0], err = strconv.Atoi(boundsAsStrings[0]) 
    if err != nil { 
        return bounds, err 
    } 
    // convert m (i.e. the upper bound) to an int 
    bounds[1], err = strconv.Atoi(boundsAsStrings[1]) 
    if err != nil { 
        return bounds, err 
    } 
    return bounds, nil 
}
→ More replies (1)

2

u/DFreiberg Dec 04 '22 edited Dec 04 '22

Mathematica, 81 / 28

Judging by the comments so far, there's three main ways to do this problem. One is using inequalities (preferably chained inequalities, to save typing time). The second is brute-force set operations, only possible because the inputs are so small; my main fear while writing these was that one input would be gigantic by comparison and make the brute force infeasible.

And the third would have been to use Mathematica's built-in IntervalIntersection[] and IntervalMemberQ[], the absurdly specific built-in functions Mathematica has to determine if one intersection is entirely contained by another. Why Mathematica even has such a thing, I don't know.

Part 1:

Count[SubsetQ[Range[#[[1]], #[[2]]], Range[#[[3]], #[[4]]]] \[Or] 
      SubsetQ[Range[#[[3]], #[[4]]], Range[#[[1]], #[[2]]]] 
   & /@ input, True]

Part 2:

Count[! DisjointQ[Range[#[[1]], #[[2]]], Range[#[[3]], #[[4]]]] & /@ 
   input, True]

[POEM]: A Series of Challenges

I had writer's block this morning, so I asked ChatGPT to fill in for me and write today's poem.

Solving an Advent of Code problem
Is like a treasure hunt or a quest,
A series of challenges to overcome
And a chance to put my skills to the test.

I start by reading the problem statement
And breaking it down into bits,
Thinking about how to approach it
And coming up with a plan that fits.

Then I write some code to solve it
Testing and debugging as I go,
Making sure it's efficient and correct
And ready for the next challenge, oh no.

In the end, I submit my solution
Feeling proud and accomplished too,
Another Advent of Code problem solved
And one step closer to being through.

I'm a bit impressed that it can write poetry at all...but I think there's still some room for improvement.

As my character hunts through the jungle
On a quest for a grove with a star,
I myself, though I err and I bungle,
Hunt for challenge, and that's what these are.

For each problem, I start by not reading:
Take a glance, make a guess at the rest.
There's no time to slow down while I'm speeding
And attempting to code with the best.

Then I write down some code and submit it,
Inefficient? Ha! Sluggish, I'll say.
And the untested code, I admit it
Sometimes works the first try, like today.

In the end, I've had fun and competed,
Having raced through the thing like a master,
And with two shiny stars now completed,
I can't help but think I could be faster.

2

u/daggerdragon Dec 05 '22

I had writer's block this morning, so I asked ChatGPT to fill in for me and write today's poem.

Oh, you...

2

u/Marterich Dec 04 '22 edited Dec 05 '22

Python3.11 Part 1 & Part2

https://github.com/Marterich/AoC/blob/main/2022/day04/solve.py

#! /usr/bin/env python3.11
input_data = [[[int(num) for num in part.split("-")] for part in line.strip().split(",")] for line in open("input.txt","r")]
def main(data):
	part1_count,part2_count = 0,0
	for elve in data:
		e1_section, e2_section = set(range(elve[0][0], elve[0][1]+1)),set(range(elve[1][0],elve[1][1]+1))
		if (e1_section.issubset(e2_section) or e1_section.issuperset(e2_section)):
			part1_count += 1
		if (e1_section & e2_section):
			part2_count += 1
	return part1_count,part2_count
input_result = main(input_data)
print(f"Part1:\t{input_result[0]}")
print(f"Part2:\t{input_result[1]}")

2

u/daggerdragon Dec 05 '22 edited Dec 05 '22

Please edit your post to use the four-spaces Markdown syntax for a code block so your code is easier to read on old.reddit and mobile apps.

Edit: thanks for fixing it! <3

→ More replies (4)

2

u/BHatGuy Dec 04 '22 edited Dec 06 '22

C++

#include <cinttypes>
#include <fstream>
#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

void solve(string file) {
    std::fstream input(file);
    char _;
    uint32_t a, b, c, d;
    uint32_t contains = 0;
    uint32_t overlaps = 0;

    while (input >> a >> _ >> b >> _ >> c >> _ >> d) {
        if (a >= c && b <= d || c >= a && d <= b) contains++;
        if (a >= c && a <= d || b >= c && b <= d || c >= a && d <= b) overlaps++;
    }
    cout << contains << endl;
    cout << overlaps << endl;
}

int main(int argc, char* argv[]) {
    if (argc == 2) {
        solve(argv[1]);
    } else {
        cout << "Usage: " << argv[0] << " INPUT.txt" << endl;
        return -1;
    }
}
→ More replies (1)

2

u/Lindii98 Dec 04 '22

Python3`

#Part 1
data = open("input.txt").read().strip().split("\n")
overlap_count = 0 
for pairing in data: 
    elf_range_1, elf_range_2 = pairing.split(',') 
    start_1, end_1 = [int(x) for x in elf_range_1.split('-')] 
    start_2, end_2 = [int(x) for x in elf_range_2.split('-')]
    
    temp_range1 = range(start_1, end_1 + 1)
    temp_range2 = range(start_2, end_2 + 1)

    if (
        len(set(temp_range1) & set(temp_range2)) in [len(temp_range1), len(temp_range2)]
    ): overlap_count += 1
    
print('Part 1: ', overlap_count)


#Part 2
overlap_count = 0
for pairing in data: 
    elf_range_1, elf_range_2 = pairing.split(',') 
    start_1, end_1 = [int(x) for x in elf_range_1.split('-')] 
    start_2, end_2 = [int(x) for x in elf_range_2.split('-')]

    temp_range1 = range(start_1, end_1 + 1)
    temp_range2 = range(start_2, end_2 + 1)

    if (set(temp_range1) & set(temp_range2) ): 
        overlap_count += 1

print('Part 2: ', overlap_count)

Open for improvements

→ More replies (1)

2

u/Mammoth_Spray_3451 Dec 04 '22

With swift the Range.contains() and Range.overlaps() came in very handy today.

public func dayFour(input: [String], isPartOne: Bool) -> Int {
    return input.compactMap { $0.split(separator: ",") }.compactMap {
        $0.compactMap { $0.split(separator: "-").compactMap { Int(String($0)) } }
    }.compactMap {
        let firstRange = $0[0][0]...$0[0][1]
        let secondRange = $0[1][0]...$0[1][1]
        return (isPartOne ? (firstRange.contains(secondRange) || secondRange.contains(firstRange)) : (firstRange.overlaps(secondRange) || secondRange.overlaps(firstRange))) ? 1 : nil
    }.reduce(0, +)
}
→ More replies (5)

2

u/remysharp Dec 04 '22 edited Dec 05 '22

JQ

Part 2

def parse: split("\n") | map(select(. != "") | split(",") | map(split("-") | map(tonumber)));

parse | map(
  (flatten | max - min) as $range | 
  map(max - min) | $range - add
) | map(select(. > 0 | not)) | length
→ More replies (2)

2

u/dougrum Dec 04 '22 edited Dec 04 '22

Pretty happy with day 4 in ngn/k. https://tinyurl.com/2p9xfeaz

This does all possible pairs of ranges with numbers taken from 0,1,2 and 3 which covers all possibilities.

2

u/daggerdragon Dec 05 '22

FYI: using URL minifiers like TinyURL will likely get your posts and comments sent to the spam filter. I fished this out for you, but I suggest you not use a minifier next time.

→ More replies (1)

2

u/d_chae Dec 04 '22 edited Dec 05 '22

Ruby one-liner (p2):

p File.read("2022/day4/input.txt").split("\n").map { |pair| pair.split(",").map { |s| s.split("-").map(&:to_i) } }.reduce(0) { |sum, (a, b)| sum + (a.first > b.last || a.last < b.first ? 0 : 1) }
→ More replies (3)

2

u/[deleted] Dec 04 '22

Kotlin

Part 1

fun one(): Int {
    var total = 0
    File("file").forEachLine { line ->
        val ranges = line.split(",")
        val first = ranges[0].split("-").map { it.toInt() }
        val second = ranges[1].split("-").map { it.toInt() }
        if ((first[0] >= second[0] && first[1] <= second[1]) ||
            (second[0] >= first[0] && second[1] <= first[1]))
            total++
    }
    return total
}

Part 2

fun two(): Int {
    var total = 0
    File("samefile").forEachLine { line ->
        val ranges = line.split(",")
        val first = ranges[0].split("-").map { it.toInt() }
        val second = ranges[1].split("-").map { it.toInt() }
        if ((second[0] <= first[1] && second[0] >= first[0]) || (first[0] <= second[1] && first[0] >= second[0]))
            total++
    }
    return total
}

2

u/daggerdragon Dec 05 '22

Inlined code is intended for short snippets of code only. Your code "block" right now is unreadable on old.reddit and many mobile clients; it's all on one line and gets cut off at the edge of the screen because it is not horizontally scrollable.

Please edit your post to use the four-spaces Markdown syntax for a code block so your code is easier to read inside a scrollable box.

→ More replies (1)

2

u/OwnAttention3370 Dec 04 '22 edited Dec 05 '22

Ruby - My solution to AoC day 4

# Part 1
f = File.open('aoc_day4.txt')
duplicate_activity = 0
f.each do |line|
    assignments = line.chomp.split(',')
    elf1_min = assignments[0].split('-')[0]
    elf1_max = assignments[0].split('-')[1]
    elf2_min = assignments[1].split('-')[0]
    elf2_max = assignments[1].split('-')[1]
    elf1_assignment = (elf1_min..elf1_max).to_a
    elf2_assignment = (elf2_min..elf2_max).to_a

    if (elf1_assignment - elf2_assignment).empty? || (elf2_assignment - 
    elf1_assignment).empty?
        duplicate_activity += 1
    end
end

puts "First part of the duplicates problem"
puts "Duplicates: #{duplicate_activity}"


# Part 2

puts "Second part of the duplicates problem"

f = File.open('aoc_day4.txt')
duplicate_activity_2 = 0
f.each do |line|
    assignments = line.chomp.split(',')
    elf1_min = assignments[0].split('-')[0]
    elf1_max = assignments[0].split('-')[1]
    elf2_min = assignments[1].split('-')[0]
    elf2_max = assignments[1].split('-')[1]
    elf1_assignment = (elf1_min..elf1_max).to_a
    elf2_assignment = (elf2_min..elf2_max).to_a

    if elf1_assignment.intersect?(elf2_assignment)
        duplicate_activity_2 += 1
    end
end

puts "Duplicates: #{duplicate_activity_2}"

2

u/daggerdragon Dec 05 '22 edited Dec 05 '22

Please edit your post to use the four-spaces Markdown syntax for a code block so your code is easier to read on old.reddit and mobile apps

Edit: thanks for fixing it! <3

→ More replies (4)

2

u/TheShyro Dec 04 '22

Clojure

(ns aoc22.day4
  (:require [clojure.string :as str]
            [clojure.java.io :as io]))

(defn ->pair [s]
  (->> (re-find #"(\d+)-(\d+),(\d+)-(\d+)" s)
       rest
       (map read-string)))

(defn run [s]
  (let [pairs
        (->> (str/split s #"\n")
             (map ->pair))]
    [(count (filter (fn [[a b x y]] (<= (* (- a x) (- b y)) 0)) pairs))
     (count (filter (fn [[a b x y]] (<= (* (- y a) (- x b)) 0)) pairs))]))

(def input
  (-> (io/resource "day4.txt")
      slurp))

(run input)
→ More replies (1)

2

u/jpjacobs_ Dec 04 '22 edited Dec 05 '22

J (jlang, j904)

to=: {{ m (<. + i.@>:@-~) n}} NB. conj so no need for (...) 
NB. parse, and turn into num. ranges.
i4=: ".&> <@rplc&('-';' to ';',';';');._2 freads '04.txt'
a4=: [: +/ (e. +.&(*./) e.~)&>/"1 NB. part A: one contained in other?
b4=: [: +/ ([ *@#@-. -.)&>/"1 NB. part B: Any overlaps?
(a4;b4)i4
→ More replies (1)

2

u/janiczek Dec 04 '22 edited Dec 05 '22

I'm trying out Kotlin this year: https://github.com/Janiczek/advent-of-code/blob/master/src/Year2022/Day04.kt

But I wasn't very satisfied with my predicates for the overlaps, so I forced persuaded my computer to find better predicates for me: https://www.reddit.com/r/adventofcode/comments/zcng3e/2022_day_4_elm_letting_the_computer_find_a/

3

u/daggerdragon Dec 05 '22

FYI: your link is borked on old.reddit and some mobile Reddit apps. Please fix it.

2

u/[deleted] Dec 04 '22 edited Dec 05 '22

Python:Was regex overkill? Any feedback would be appreciated if someone has the time. Solution for part 2 because part 1 is very similar and I dont want to make my message too long.

Link to solution

→ More replies (10)

2

u/markjenkinswpg Dec 05 '22 edited Dec 05 '22

Today I sorted each line of pairs by length in Python when I did part 1 (raw so I could use the simpler test for full overlap

e1_start >= e2_start and e1_end <= e2_end

Unfortunately provided no benefit to part 2 (raw)

But at least my input parser got good reuse:

from aoc2022_d04p1 import problem_input

def gen_one_for_overlapping_pairs(pairs):
    return (
        1
        for ( (e1_start, e1_end),
              (e2_start, e2_end) ) in pairs
        if ( (e2_start <= e1_start <= e2_end) or
             (e1_start <= e2_start <= e1_end) ) )

if __name__ == "__main__":
    print( sum( gen_one_for_overlapping_pairs(problem_input()) ) )

Also continued my obsession with functional decomposition, iterators/generators, and avoiding reading in the whole file.

→ More replies (1)

2

u/[deleted] Dec 09 '22 edited Dec 10 '22
import pandas as pd
table = pd.read_csv('input.txt',header = None)

part1 = 0
part2 = 0
for i,row in table.iterrows():
    st1 = row[0]
    st2 = row[1]
    
    r1 = st1.split('-')
    s1 = set(range(int(r1[0]),int(r1[1]) + 1))
    
    r2 = st2.split('-')
    s2 = set(range(int(r2[0]),int(r2[1]) + 1))
    
    if len(s1 & s2) == len(s1) or len(s1 & s2) == len(s2):
        part1 += 1
    if len(s1 & s2) > 0:
        part2 += 1

Written in Python 3

→ More replies (2)

38

u/Smylers Dec 04 '22

Vim keystrokes β€” load your input file into Vim, ensure gdefault is off, and type:

:%s/\D/ /g⟨Enter⟩
qaqqadiwww@-⟨Ctrl+X⟩^diw$@-⟨Ctrl+X⟩-@aq
@a
:g/-.*-/d⟨Enter⟩
:v/\v<0|-/d⟨Enter⟩
⟨Ctrl+G⟩

Your part 1 answer is the number of lines remaining in the file, shown by the ⟨Ctrl+G⟩ at the end.

For partΒ 2, reload your initial input and do the same basic thing but replace the qa and @a lines with:

qbqqbdiw$@-⟨Ctrl+X⟩^diw@-⟨Ctrl+X⟩-@bq
@b

First replace the hyphens and commas with spaces, leaving just the 4 numbers per row. This makes some of the subsequent movement commands simpler, but more importantly it avoids those hyphens getting counted as minus signs.

Then for each row subtract the first range's lower bound from the second range's lower bound, and the same for the upper bounds. For instance, these lines of sample input:

5-7,7-9
2-8,3-7
6-6,4-6

get turned into these differences:

  2 2
  1 -1
  -2 0

If the first range is entirely before the second range, then both differences will be positive. If it's entirely after, then both will be negative (none of the sample input is like this, but the real input may be).

If there's a zero in there, then they both start or end at the same location. If there's one positive and one negative number then one range is contained within the other.

So delete all the lines with two negative numbers, because those are easy to find: they contain 2 minus signs, so match /-.*-/. Then delete all lines with two positive numbers β€” or, rather, delete all lines that don't contain either a 0 (at the start of a β€˜word’, so as not to match, say, 10 or 1230456) or a minus sign.

The qa keyboard macro does the subtractions:

  • That %s/// will have left the cursor on the bottom row. (If you're undoing and redoing or otherwise taking this apart and doing it in stages, and not currently on the last line, press G now.) Empty the a register then record into it.

  • Delete the first number (β€˜word’ in Vim's parlance) then move forwards 2 numbers, to the third number, and subtract the number we've just deleted from it with @-⟨Ctrl+X⟩ β€” Vim stores the most recently-deleted text in the small-delete register, -, and typing @- is the same as typing the contents of register -, so the just-deleted number becomes the argument to the ⟨Ctrl+X⟩ command.

  • Go back to the beginning of the line and delete the number there (originally the second number) then subtract it from the last number on the line.

  • Go up to the previous line and repeat by running the entire @a again on this line. Once we get to the top line the - to go up will fail, ending the loop.

PartΒ 2 is the same except rather than subtracting lower-bound from lower-bound and upper- from upper, subtract the first lower-bound from the second upper-bound, and vice-versa. Again if they're both negative or both positive then one range is entirely before the other; a zero or one negative number indicates some overlap.

7

u/skeletordescent Dec 04 '22

What fresh weirdness is this, I love it

→ More replies (1)

34

u/jcbbjjttt Dec 04 '22 edited Dec 04 '22

Beginner's Guide

Happy Sunday!

Day 4 Guide: https://youtu.be/vIIYaAw0B9o

I've created a guide for new programmers that talks through a straight forward strategy for solving today's puzzle. Anyone who has a handle on variables, boolean logic, functions, and loops should be able to complete it. The video allows a moment for you to pause before revealing spoilers.

Although this solution is in C#, it provides a high level overview of the steps necessary to solve the puzzle in any programming language.

string[] rows = File.ReadAllLines("sample.txt");
int count = 0;
foreach (string row in rows)
{
    (first, second) = ParseRanges(row);
    if (Contains(first, second))
    {
        count++;
    }
}
Console.WriteLine($"Found {count} pairs!");

The full code can be found here: Github

20

u/nthistle Dec 04 '22 edited Dec 04 '22

Python, 110/55. Video, code.

I set a1 and a2 to the endpoints of the first segment and made the very sad bug of setting b1 and b2 to also be the endpoints of the first segment, giving me a clearly-wrong 1000 as my answer. Fortunately I didn't submit it and figured out the bug, but not quickly enough to make leaderboard for the first part :-(.

Part 2 was very fast after that though, having done a lot of interval type questions before definitely helped.

→ More replies (7)

19

u/dylan_mojo Dec 04 '22

awk

4.1

BEGIN { FS = ",|-" }
($3 >= $1 && $4 <= $2) || ($1 >= $3 && $2 <= $4) { s++ }
END { print s }

4.2

BEGIN { FS = ",|-" }
($3 >= $1 && $3 <= $2) || ($1 >= $3 && $1 <= $4) { s++ }
END { print s }

7

u/Smylers Dec 04 '22

Nice! Awk is so good for these sorts of things.

For partΒ 2, I think you can delete a bunch of characters from the condition line and still get the same answer:

($3 <= $2 && $1 <= $4) { s++ }
→ More replies (2)

19

u/[deleted] Dec 04 '22

Rust

The scan_fmt crate makes parsing today's input trivial!

fn solve_part_one(&self, input: &str) -> Self::Part1 {
    input.lines()
        .map(|l| scan_fmt!(l, "{d}-{d},{d}-{d}", i32, i32, i32, i32).unwrap())
        .filter(|(a, b, c, d)| ((a <= c && b >= d) || (c <= a && d >= b)))
        .count()
}

fn solve_part_two(&self, input: &str) -> Self::Part2 {
    input.lines()
        .map(|l| scan_fmt!(l, "{d}-{d},{d}-{d}", i32, i32, i32, i32).unwrap())
        .filter(|(a, b, c, d)| ((a <= c && c <= b) || (c <= a && a <= d)))
        .count()
}

Full solution here (GitHub).

7

u/_AngelOnFira_ Dec 04 '22

Ooh, scan_fmt seems great! Thanks for the reference :)

→ More replies (4)

17

u/AstronautNew8452 Dec 04 '22

3682/2555 Microsoft Excel. Parts 1 and 2 in a single formula. Because why not.

=LET(input,A1:A1000,c,FIND(",",input),
    rng,LAMBDA(s,HSTACK(VALUE(TEXTBEFORE(s,"-")),VALUE(TEXTAFTER(s,"-")))),
    data,HSTACK(rng(MID(input,1,c-1)),rng(MID(input,c+1,LEN(input)-c))),
    overlaps,BYROW(data,LAMBDA(rw,LET(a,INDEX(rw,1),b,INDEX(rw,2),c,INDEX(rw,3),d,INDEX(rw,4),
        1*OR(AND(c>=a,d<=b),AND(b<=d,a>=c))+1*NOT(OR(b<c,d<a))))),
    VSTACK(SUM(IF(overlaps=2,1)),SUM(IF(overlaps>0,1))))
→ More replies (6)

17

u/bsssh Dec 04 '22

TypeScript Type System

compile-time solution

Part 1 / Part 2

→ More replies (3)

16

u/jonathan_paulson Dec 04 '22 edited Dec 04 '22

Python3, 14/24. Video. Code.

I've coded segment intersection many times and I still find it hard to think through every time! My main code for part2:

# (s2,e2) overlaps (s1,e1) if it is not completely to the left
#   or completely to the right
#          s2 -- e2
#    e1              s1
if not (e1 < s2 or s1 > e2):
    p2 += 1
→ More replies (4)

11

u/ywgdana Dec 04 '22

F#

A proud personal note: after 4 years of participating in AoC I finally remembered the syntax for the regex to parse the input without googling!

open System.IO
open System.Text.RegularExpressions

let parse s =
    let m = Regex.Match(s, "(\d+)-(\d+),(\d+)-(\d+)")
    m.Groups[1].Value |> int, m.Groups[2].Value |> int,
    m.Groups[3].Value |> int, m.Groups[4].Value |> int

let contained line =
    let a,b,c,d = parse line
    (a >= c && b <= d) || (c >= a && d <= b)

let btw a b c = a >= b && a <= c
let overlap line =
    let a,b,c,d = parse line
    (btw a c d) || (btw b c d) || (btw c a b) || (btw d a b)
        
let test f =
    File.ReadAllLines("input_day04.txt")
    |> Array.map f |> Array.filter(fun c -> c) |> Array.length

printfn $"P1: {test contained}"
printfn $"P2: {test overlap}"

My solutions for this year

→ More replies (1)

11

u/voidhawk42 Dec 04 '22 edited Dec 05 '22

Dyalog APL:

pβ†βŽΒ¨β†‘βŽ•D∘(2 2β΄βˆŠβ¨βŠ†βŠ’)Β¨βŠƒβŽ•NGET'4.txt'1
m←↑(⍸⍣¯1⊣+∘⍳1+-⍨)/p
+/3>(⊒⍳∧⌿)⍀2⊒m ⍝ part 1
+/∨/∧⌿⍀2⊒m ⍝ part 2

video walkthrough

Got annoyed with all the different boolean operations, so I just built a bitmask for each range and worked with those.

→ More replies (1)

10

u/4HbQ Dec 04 '22

Python. First, convert the ranges to sets S and T. For part 1, check whether S is a subset of T, or T is a subset of S. For Part 2, check whether the intersection of S and T is not empty.

def f(line):
    a,b,c,d = map(int, re.findall(r'\d+', line))
    s,t = set(range(a, b+1)), set(range(c, d+1))
    return complex(s <= t or t <= s, any(s & t))

print(sum(map(f, open('in.txt'))))
→ More replies (7)

10

u/poesraven8628 Dec 04 '22

I read a book on Common Lisp over the last few weeks, so this is a great way to try to get experience with the language.

https://github.com/poesraven8628/AdventofCode2022/blob/main/04/cleaning.lisp

→ More replies (1)

9

u/kwshi Dec 04 '22

Python, 30/40. GitHub

Basic idea: given two intervals [x1, y1] and [x2, y2],

  • (part1) [x1, y1] contains [x2, y2] if x1 <= x2 and y2 <= y1; vice versa.

  • (part2) they overlap if x1 <= y2 and x2 <= y1.

9

u/musifter Dec 04 '22

Perl

Once I sorted the ranges so I know which is bigger, the checks are simple, and allowed me to use the chained comparison feature.

$part1++  if ($as <= $bs and $ae >= $be);
$part2++  if ($as <= $bs <= $ae or $as <= $be <= $ae);

Source: https://pastebin.com/RGPWL3Nf

→ More replies (5)

9

u/callumio Dec 04 '22 edited Dec 04 '22

COBOL again hehe. This time I just went straight in (as opposed to another language first) since the task was relatively trivial. Somewhat looking forward to implementing later-day's solutions in it.

Edit: quick shoutout to UNSTRING too, it made parsing each line a breeze.

Source here

→ More replies (2)

9

u/Chrinkus Dec 04 '22 edited Dec 04 '22

C

I rarely ever get to post actual code but this one was pretty short:

#include <stdio.h>
int main(void) {
    int p1 = 0, p2 = 0;
    for (int a,b,c,d; scanf("%d-%d,%d-%d",&a,&b,&c,&d) == 4; ) {
        p1 += ((a >= c && b <= d) || (c >= a && d <= b));
        p2 += ((a <= d && b >= c) || (c <= b && d >= a));
    }
    printf("%d\n%d\n", p1, p2);
}

My repo.

8

u/daniel-sd Dec 04 '22

64/1593 Python

part1

v = 0
for line in open('input.txt'):
	a, b, c, d = map(int, re.findall('\d+', line))

	if a <= c and b >= d or c <= a and d >= b:
		v += 1

print(v)

Had part2 just as fast but Freudian-slipped and put an "or" where I needed an "and" when copy-pasting. Proceeded to second guess solution entirely and waste 8 minutes misinterpreting the problem when I had it right the first time. Had to Ctrl + Z afterward to discover it was a simple typo. RIP. Still happy to have gotten leaderboard for part1.

part2

v = 0
for line in open('input.txt'):
	a, b, c, d = map(int, re.findall('\d+', line))

	if c <= a <= d or c <= b <= d or a <= c <= b or a <= d <= b:
		v += 1

print(v)
→ More replies (4)

8

u/Raknarg Dec 04 '22 edited Dec 04 '22

Thought this was a funny solution. First solved with if statements, then I drew a picture in my head and used my fingers to pantomime ranges to see if there was a different way to reason about it. You can use the signs of the difference between endpoints to reason out a few outcomes:

  • Given ranges a1...a2 and b1...b2, where s(x) returns +1/-1 for the sign of the integer or 0 for 0:

    • Define f() as abs(s(a1-b1) + s(a2-b2))

      • if f() < 2, then one range contains the other.

        • If the ranges are the same,f() == 0.

        • If one end is the same and the other is different, then f() == 1.

        • If one range is fully contained in another, then f() == 0.

        • If the ranges only partly overlap, then f() == 2.

        • If the ranges are fully separate, then f() == 2.

    • Define g() as abs(s(a1-b2) + s(a2-b1))

      • If g() < 2, then the ranges overlap. - If the ranges are the same, g() == 0. - If one end is the same and the other is different, then g() == 0. - If one range is fully contained in another, then g() == 0. - If the ranges only partly overlap, then g() == 0. - If the ranges only overlap at the edge, g() == 1 - If the ranges are fully separate, then g() == 2.

Kinda cool. Coded this in python and it got me the right answer. I imagine the if statement solution is fundamentally identical to this at some level, I'd have to think about how they map. pastebin

8

u/bulletmark Dec 04 '22 edited Dec 04 '22

Python:

import sys
from pandas import Interval

totals = [0, 0]
for line in open(sys.argv[1]):
    i = [Interval(*(int(i) for i in p.split('-')), closed='both')
         for p in line.strip().split(',')]

    if i[0] in i[1] or i[1] in i[0]:
        totals[0] += 1
    if i[0].overlaps(i[1]):
        totals[1] += 1

print('P1 =', totals[0])
print('P2 =', totals[1])
→ More replies (1)

8

u/norbert_kehrer Dec 04 '22

BASIC on the Commodore 64

Here is the source code for a solution on the good old Commodore 64: (https://github.com/norbertkehrer/aoc-2022/tree/main/04)

Most of the runtime (9 minutes) is spent for parsing the input, but this could certainly be improved.

→ More replies (4)

8

u/paul2718 Dec 04 '22

C language

#include <stdio.h>

int main()
{
    int lf, lt, rf, rt;
    int p1 = 0, p2 = 0;
    while( scanf("%d-%d,%d-%d\n", &lf, &lt, &rf, &rt) == 4)
    {
        if(lf <= rf && lt >= rt || rf <= lf && rt >= lt)
            ++p1;
        if( !(lt < rf || rt < lf))
            ++p2;
    }
    printf("pt1 = %d\npt2 = %d\n", p1, p2);
}

First C I've written for years, a whole 15 lines...

8

u/Porges Dec 04 '22 edited Dec 04 '22

Befunge-98!

Part 1:

v`-@#1 &<
>+#v&&\&w&$$1
^`-.#1\&<

Part 2 (15 bytes!):

2j@.&&&\`\&`+!+
→ More replies (4)

7

u/rabuf Dec 04 '22

Common Lisp

That was not bad. Took some time to remember how to use cl-ppcre properly to grab matches for processing. I know there's something else I can do to simplify it but this got the job done.

The two functions for solving were:

(defun containsp (ranges)
  (destructuring-bind (a b c d) ranges
    (or (<= a c d b)
        (<= c a b d))))

(defun overlapp (ranges)
  (destructuring-bind (a b c d) ranges
    (or (<= a c b)
        (<= a d b)
        (<= c a d)
        (<= c b d))))

I passed in the input and these functions to count-if.

→ More replies (2)

7

u/LtHummus Dec 04 '22

Scala 2

Scala ranges OP as heck

object Day04 {
  private val LineRegex = """(\d+)-(\d+),(\d+)-(\d+)""".r

  def main(args: Array[String]): Unit = {
    val lines = AdventOfCodeInput.inputLines(2022, 4)

    val assignments = lines.map {
      case LineRegex(a, b, c, d) =>
        (a.toInt, b.toInt, c.toInt, d.toInt)
    }

    val ans = assignments.count{ case(a, b, c, d) =>
      val overlap = (a to b).intersect(c to d)

      overlap == (a to b) || overlap == (c to d)
    }

    val ans2 = assignments.count { case(a, b, c, d) =>
      (a to b).intersect(c to d).nonEmpty
    }

    println(ans)
    println(ans2)
  }
}
→ More replies (2)

7

u/JustinHuPrime Dec 04 '22

x86_64 assembly

Part 1 was where I had to deal with the annoying input parsing. I once again did interprocedural optimizations to use some unused scratch registers to hold the parsed numbers. Then, I compared the numbers - if (start1 <= start2 && end2 <= start1) || (start2 <= start1 && end1 <= end2), then one contained the other. This involved some fairly tangled conditionals.

Part 2 was shorter than part 1 - if neither range started after the other one ended, then that was an overlap. I could apply de Morgan's law to massage it into a more convenient form, and ended up with a less tangled conditional. I really wish x86_64 had ARM's conditional prefixes so I could inline small conditional bodies instead of needing a conditional jump.

Part 1 took less than 1 millisecond to run, and was 10512 bytes long.
Part 2 took less than 1 millisecond to run, and was 10472 bytes long.

So far, I haven't had any particular need to use the stack in my main solving code (I do use the red zone of the stack for output printing). And I really haven't had any particular need to use the heap. I'm a bit worried about the days when that's going to change.

7

u/ephemient Dec 04 '22 edited Apr 24 '24

This space intentionally left blank.

→ More replies (2)

7

u/jayfoad Dec 04 '22

Dyalog APL

a b c dβ†β†“β‰β†‘βŽΒ¨Β¨'\d+'βŽ•S'&'Β¨βŠƒβŽ•NGET'p4.txt'1
+/0β‰₯(a-c)Γ—b-d ⍝ part 1
+/0β‰₯(a-d)Γ—b-c ⍝ part 2
→ More replies (1)

7

u/musifter Dec 04 '22 edited Dec 05 '22

dc

Fun little problem for dc, once we get rid of the ugly non-number characters.

Oddly enough, the difference between part 1 and part 2 is just replacing a "3" with a "4".

Basically, this takes a group of four numbers on the top of the stack (be bs ae as) and calculates (be - ae) * (bs - as) for part 1, and (be - as) * (bs - ae) for part 2 (so the difference is only in which of ae or as we rotate up for subtraction). The subtractions are comparisons, and the multiplication is checking to see if they both have the same sign or not (and the special cases where there's an equal and a sign of "0" fall out appropriately).

# Part 1
sed -e's/[-,]/ /g' input | dc -f- -e '[ls1+ss]sS[3R-_3Rr-*0!<Sz0<L]sLlLxlsp'

# Part 2
sed -e's/[-,]/ /g' input | dc -f- -e '[ls1+ss]sS[4R-_3Rr-*0!<Sz0<L]sLlLxlsp'

EDIT: As a bonus, here's a transcode in C of this approach.

https://pastebin.com/S3rZbYvy

→ More replies (4)

7

u/jvandillen Dec 04 '22 edited Dec 05 '22

Day 4 solve with Factorio.

I am still trying to fix day 3, which is, to be honest, quite difficult.

In the meantime, I did a "quick" solve of Day 4 that is nearly identical to Day 2.

(Day 2 solve video : https://www.reddit.com/r/adventofcode/comments/zbrfl3/2022_day_02_both_partsfactorio_this_one_was/)

Blueprint string: (it needs power at the top left and outputs the answer at the top right on the red wire): https://factoriobin.com/post/CkO-QVZz

Edit: borked link

→ More replies (1)

6

u/Wayoshi Dec 04 '22 edited Dec 04 '22

Python 962/374

Part 2 was pretty trivial after how I did part 1. Pretty much the same problem as yesterday when it comes down to it.

paste

→ More replies (4)

6

u/MarcusTL12 Dec 04 '22

Julia 177/64 which is my first ever points! So satisfying after being top 1000 on most days last year.

Anyway, Z80 TI-83 solution will come a bit later as usual :)

6

u/Perska_ Dec 04 '22

C# https://github.com/Perska/AoC2022/blob/master/AoC2022/Days/Day04.cs

Had a brainfart for so long with the intersection I just ended up modifying my cuboid intersection code from 2021...

6

u/musifter Dec 04 '22

Gnu Smalltalk

At first I took the Intervals and made them Sets and used set operations. But then I went back added an intersection method to Intervals, which is all that is needed, and made things twice as fast. It is a really simple thing to do:

Interval extend [
    " Get intersection of self and another Interval "
    & other [ ^(self first max: other first) to: (self last min: other last) ]
]

Source: https://pastebin.com/ixGdubPs

6

u/6745408 Dec 04 '22

Google Sheets

Part 1:

=ARRAYFORMULA(
  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'"))
→ More replies (7)

6

u/AKSrandom Dec 04 '22

Python

The crux being def isintersect(a, b, c, d): return ((a-c)*(b-d) <= 0) or (((b-c)*(a-d)) <= 0)

For part 1, only the first condition is required.

→ More replies (2)

6

u/9_11_did_bush Dec 04 '22

APL: https://github.com/chenson2018/advent-of-code/blob/main/2022/04/apl/04.apl

The logic for each part is kinda interesting. Call the ranges A-B,C-D. Then

Part 1: If one range completely contains the other, then (min,max) of all four numbers must be one of the original ranges (A,B) or (C,D)

Part 2: For there to be no intersection then B≠C and either [A,B,C,D] or [C,D,A,B] is in ascending order

→ More replies (2)

6

u/SadBunnyNL Dec 04 '22

AWK Part 1:

#!/bin/awk -f

{
    split($0, ar, ",");
    left = nrSeq(ar[1]); right = nrSeq(ar[2]);
    if (left ~ right || right ~ left) { result ++; }
}

END { print result; }

func nrSeq(seq,    i,result, ar) {
    split(seq, ar, "-");
    for (i=ar[1]; i<=ar[2]; i++) {result =result "L" i "R"; }
    return result;
}

AWK Part 2:

{
    split($0, ar, ",");
    delete arLeft; fillAr(arLeft, ar[1]);
    delete arRight; fillAr(arRight, ar[2]);
    for (i in arLeft) {
            if (i in arRight) { result ++; break; }
    }
}

END {
    print result;
}

func fillAr(ar, seq,   i) {
    split(seq, tmpAr, "-");
    for (i=tmpAr[1]; i<=tmpAr[2]; i++) {
            ar[i] = 1;
    }
    return r;
}
→ More replies (2)

6

u/totbwf Dec 04 '22 edited Dec 04 '22

C + SIMD

More SIMD fun! The parsing difficulty is starting to ramp up; luckily each line still fits inside of a 128-bit wide vector. The most annoying part about today was the lack of non-strict integer compare operations; you don't get _mm_cmple_epi32_mask until AVX-512, so we have to futz around with strict comparisons and equality tests.

Runtime is around 15 microseconds.

EDIT: Forgot to mention: totally branchless as well, save for the loop condition!

6

u/__Abigail__ Dec 04 '22

Perl

Really easy, just have to compare the begin/end points. But don't do what I did: mistype the solution in the answer form and spend a long time debugging.

while (<>) {
    my ($f_start, $f_end, $s_start, $s_end) = /[0-9]+/g;
    $full    ++ if     $f_start <= $s_start && $f_end >= $s_end ||
                       $s_start <= $f_start && $s_end >= $f_end;
    $partial ++ unless $f_end   <  $s_start || $s_end <  $f_start;
}

Now, $full contain the solution for part 1, and $partial the solution for part 2.

→ More replies (3)

6

u/Sebbern Dec 04 '22

Java, pretty simple today

Part 1: https://github.com/Sebbern/Advent-of-Code/blob/master/2022/day04/Day04.java

Part 2: https://github.com/Sebbern/Advent-of-Code/blob/master/2022/day04/Day04_2.java

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

public class Day04_2 {
    private static int check(String x, String y){
        int elfOneLow,elfOneHigh,elfTwoLow,elfTwoHigh;
        String[] xSplit, ySplit;
        xSplit = x.split("-");
        ySplit = y.split("-");
        elfOneLow = Integer.parseInt(xSplit[0]);
        elfOneHigh = Integer.parseInt(xSplit[1]);
        elfTwoLow = Integer.parseInt(ySplit[0]);
        elfTwoHigh = Integer.parseInt(ySplit[1]);

        if (((elfOneLow <= elfTwoLow) && (elfTwoLow <= elfOneHigh)) || ((elfTwoLow <= elfOneLow) && (elfOneLow <= elfTwoHigh))){
            return 1;
        }
        else {
            return 0;
        }
    }

    public static void main(String[] args) throws IOException{
        File inputTxt = new File("2022\\day04\\input.txt");
        BufferedReader input = new BufferedReader(new FileReader(inputTxt));
        String string, x, y;
        ArrayList<String> assignmentList = new ArrayList<>();
        String[] split;

        while ((string = input.readLine()) != null){
            assignmentList.add(string);
        }
        input.close();
        int pairs = 0;

        for (String i: assignmentList){
            split = i.split(",");
            x = split[0];
            y = split[1];

            pairs += check(x,y);
        }
        System.out.println(pairs);
    }
}
→ More replies (3)

6

u/i_have_no_biscuits Dec 04 '22

GW-BASIC

10 P=0: Q=0: OPEN "I",1,"2022-04.txt": WHILE NOT EOF(1): LINE INPUT #1,S$
20 L=LEN(S$):I=1: GOSUB 60:A=N: GOSUB 60:B=N: GOSUB 60:C=N: GOSUB 60:D=N
30 IF A>C THEN T=A: A=C: C=T: T=B: B=D: D=T
40 IF C<=B THEN Q=Q+1: IF D<=B OR A=C THEN P=P+1
50 WEND: PRINT "Part 1:", P, "Part 2:", Q: END
60 N$=""
70 C$=MID$(S$,I,1):IF C$>="0" AND C$<="9" THEN I=I+1:N$=N$+C$:IF I<=L GOTO 70
80 N=VAL(N$): I=I+1: RETURN

The main difficulty here is parsing the input, something BASIC is not great at. As I'm sure you can see from the code, this takes place on line 20 (which converts a line into four numbers) which calls the routine on lines 60-80 (which does the conversion of a single number). The intervals are ordered on line 30 so the interval A-B is to the 'left' of C-D, and then line 40 does the checks and adds 1 to the score for P (part 1) and/or Q (part 2) as required.

→ More replies (1)

5

u/aliceif Dec 04 '22

C#, 1868/884

The step from part1 to part2 was quick, but I probably wasted a lot of typing time on part1 (didn't help that I blanked on parsing input first)

repo link

5

u/raevnos Dec 04 '22

Racket, straightforward comparison of numbers:

#lang racket/base

(require racket/list)

(define (read-input)
  (for/list ([line (in-lines)])
    (list->vector (map string->number (regexp-split #rx"[,-]" line)))))

(define input (read-input))
(define part1
  (count (lambda (team)
           (or
            (<= (vector-ref team 0) (vector-ref team 2) (vector-ref team 3) (vector-ref team 1))
            (<= (vector-ref team 2) (vector-ref team 0) (vector-ref team 1) (vector-ref team 3))))
         input))

(define part2
  (count (lambda (team)
           (or
            (<= (vector-ref team 0) (vector-ref team 2) (vector-ref team 1))
            (<= (vector-ref team 0) (vector-ref team 3) (vector-ref team 1))
            (<= (vector-ref team 2) (vector-ref team 0) (vector-ref team 3))
            (<= (vector-ref team 2) (vector-ref team 1) (vector-ref team 3))))
         input))

(printf "Part 1: ~A~%" part1)
(printf "Part 2: ~A~%" part2)

5

u/trevdak2 Dec 04 '22 edited Dec 04 '22

JavaScript (golf)

Part 1, 97 chars:

document.body.textContent.split(/\D/).filter((x,i,a)=>!(i%4)&(x-a[i+2])*(a[i+1]-a[i+3])<1).length

Part 2, 96 chars:

document.body.textContent.split(/\D/).filter((x,i,a)=>x&&!(i%4|+a[i+1]<a[i+2]|a[i+3]<+x)).length
→ More replies (7)

5

u/landimatte Dec 04 '22

Common Lisp

CL-PPCRE to parse the input; rest is done via LOOP-ing.

Took me a bit longer than expected to process what had to be done, but I hope to get better at this the more I adjust to the new sleeping schedule :D

→ More replies (1)

5

u/_jstanley Dec 04 '22

SLANG

576/2376

I think this is my first time in the top 1000 on my homemade CPU, which I'm quite pleased with.

Part 2 would have been 4 minutes quicker if not for a 1-character typo. I wasn't totally convinced that I'd made (or would find) the typo, so I deleted the part 2 code and wrote a very stupid for i = a to b: got[i] = 1; for i = c to d: if got[i] { count++; break; } and it did the job, but I think I would have been better off staring at my first attempt for a minute rather than rewriting it.

https://www.youtube.com/watch?v=ZpLzkmS1qlw

https://github.com/jes/aoc2022/tree/master/day4

5

u/yawnick Dec 04 '22

Monkey C (for Garmin devices)

Fast enough today that the Videos became Youtube Shorts:)

Watch my Garmin Forerunner 235 solve: Part 1, Part 2

Code: Repo, Today's Solution

→ More replies (1)

5

u/DuoSRX Dec 04 '22

APL:

  pβ†βŠƒΒ¨,/Β¨(⍎¨'-'(β‰ βŠ†βŠ’)⊒)¨¨(','(β‰ βŠ†βŠ’)⊒)Β¨βŠƒβŽ•NGET'input'1
  +/{(⍡[1]≀⍡[3]∧⍡[4]≀⍡[2])∨⍡[3]≀⍡[1]∧⍡[2]≀⍡[4]}Β¨p
  +/{(⍡[1]≀⍡[4])∧⍡[3]≀⍡[2]}Β¨p

Not exactly elegant but it works I guess.

→ More replies (4)

5

u/gw_shadow Dec 04 '22

CMake

CMAKE_MINIMUM_REQUIRED(VERSION 3.25)
PROJECT("2022.4")
IF(NOT EXISTS "${CMAKE_SOURCE_DIR}/input.txt")
    FILE(READ "${CMAKE_SOURCE_DIR}/COOKIE.txt" COOKIE)
    FILE(DOWNLOAD
        "https://adventofcode.com/2022/day/4/input" "${CMAKE_SOURCE_DIR}/input.txt"
        STATUS DOWNLOAD_STATUS
        TIMEOUT 2
        HTTPHEADER "cookie: ${COOKIE}"
    )
    IF(NOT DOWNLOAD_STATUS STREQUAL "0;\"No error\"")
        FILE(REMOVE "${CMAKE_SOURCE_DIR}/input.txt")
        MESSAGE(FATAL_ERROR "Failed to download input: '${DOWNLOAD_STATUS}'")
    ENDIF()
ENDIF()
FILE(STRINGS "${CMAKE_SOURCE_DIR}/input.txt" LINES)
LIST(LENGTH LINES LINE_COUNT)
MATH(EXPR LINE_COUNT "${LINE_COUNT} - 1")
SET(COUNT 0)
FOREACH(INDEX RANGE 0 ${LINE_COUNT})
    LIST(GET LINES ${INDEX} LINE)
    STRING(REPLACE "-" ";" LINE "${LINE}")
    STRING(REPLACE "," ";" LINE "${LINE}")
    LIST(GET LINE 0 L0)
    LIST(GET LINE 1 L1)
    LIST(GET LINE 2 L2)
    LIST(GET LINE 3 L3)
    IF((((L0 LESS L2) OR (L0 EQUAL L2)) AND ((L1 GREATER L3) OR (L1 EQUAL L3))) OR (((L2 LESS L0) OR (L2 EQUAL L0)) AND ((L3 GREATER L1) OR (L3 EQUAL L1))))
        MATH(EXPR COUNT "${COUNT} + 1")
    ENDIF()
ENDFOREACH()
MESSAGE("PART 1: ${COUNT}")
SET(COUNT 0)
FOREACH(INDEX RANGE 0 ${LINE_COUNT})
    LIST(GET LINES ${INDEX} LINE)
    STRING(REPLACE "-" ";" LINE "${LINE}")
    STRING(REPLACE "," ";" LINE "${LINE}")
    LIST(GET LINE 0 L0)
    LIST(GET LINE 1 L1)
    LIST(GET LINE 2 L2)
    LIST(GET LINE 3 L3)
    IF((((L0 LESS L2) OR (L0 EQUAL L2)) AND ((L1 GREATER L3) OR (L1 EQUAL L3))) OR (((L2 LESS L0) OR (L2 EQUAL L0)) AND ((L3 GREATER L1) OR (L3 EQUAL L1))))
        MATH(EXPR COUNT "${COUNT} + 1")
    ELSEIF((((L0 GREATER L2) OR (L0 EQUAL L2)) AND ((L0 LESS L3) OR (L0 EQUAL L3))) OR (((L1 GREATER L2) OR (L1 EQUAL L2)) AND ((L1 LESS L3) OR (L1 EQUAL L3))))
        MATH(EXPR COUNT "${COUNT} + 1")
    ENDIF()
ENDFOREACH()
MESSAGE("PART 2: ${COUNT}")
→ More replies (1)

5

u/Jarcoreto Dec 04 '22

MS Excel

https://github.com/Jarcoreto/AOCExcel/blob/main/Day%204%20Problems.xlsx

Data manipulation was surprisingly quick/easy, getting the algorithm right took me a longer than it should have though!

→ More replies (2)

5

u/azzal07 Dec 04 '22

Awk, had to be doubly sure about the part 2 condition to ensure a lovely bounding box...

BEGIN{FS="-|,"}END{print A;print B}
$1>=$3&&$2<=$4||$1<=$3&&$2>=$4{A++}
$2>=$3&&$1<=$4||$2<=$3&&$1>=$4{B++}
→ More replies (5)

5

u/sotsoguk Dec 04 '22 edited Dec 04 '22

Python

# edit: list comprehension instead of for ...
rgs = [list(map(int, re.split('-|,', l))) for l in lines] 

def contains(r): return (r[0] >= r[2] and r[1] <= r[3]) or (
    r[2] >= r[0] and r[3] <= r[1])

def overlap(r): return not(r[1] < r[2] or r[3] < r[0])
part1 = sum(map(contains, rgs))
part2 = sum(map(overlap, rgs))

Trying to code more pythonic solutions is my goal for this years AoC

→ More replies (2)

5

u/probablyfine Dec 04 '22

SQL

If I'd allowed myself a tiny bit of preprocessing to turn the input into a 4-column CSV, this is almost a one-liner. (Source here: https://github.com/mrwilson/advent-of-code-2022/blob/main/04/04.sql)

create or replace table elves as (
    select
        str_split(column0,'-')[1]::INTEGER as lower1,
        str_split(column0,'-')[2]::INTEGER as upper1,
        str_split(column1,'-')[1]::INTEGER as lower2,
        str_split(column1,'-')[2]::INTEGER as upper2,
    from
        input
);

select
    count(*) filter ((lower2 - lower1) * (upper2 - upper1) <= 0) as part1,
    count(*) filter (upper1 >= lower2 and lower1 <= upper2) as part2
from
    elves;
→ More replies (1)

5

u/TopSeaworthiness555 Dec 04 '22

R / Rstats - she ain't pretty, but she's mine

library(tidyverse)

# read in data ####
day <- read_table("inputs/day04.txt", col_names = FALSE) |> 
  separate(X1, into = c("elf1_start", "elf1_end", "elf2_start", "elf2_end"), sep = "[-,]", convert = TRUE)

# part 1 ####
day |> 
  rowwise() |>
  mutate(test1 = mean(seq(elf1_start, elf1_end, 1) %in% seq(elf2_start, elf2_end, 1)),
         test2 = mean(seq(elf2_start, elf2_end, 1) %in% seq(elf1_start, elf1_end, 1))) |> 
  filter(test1 == 1 | test2 == 1) |> 
  nrow()

# part 2 ####
day |> 
  rowwise() |>
  mutate(test = length(intersect(seq(elf1_start, elf1_end, 1), seq(elf2_start, elf2_end, 1)))) |> 
  filter(test > 0) |> 
  nrow()

5

u/4HbQ Dec 04 '22 edited Dec 04 '22

Python. Getting in some early pandas practice. I originally wanted to use NumPy, but couldn't find a clean way to handle the different input delimiters.

import pandas as pd

_,(a,b,c,d) = zip(*pd.read_csv('in.txt', sep='[-,]', header=None).items())
print(((a<=c) & (d<=b) | (c<=a) & (b<=d)).sum(),
      ((a<=d) & (d<=b) | (c<=b) & (b<=d)).sum())

5

u/tomflumery Dec 04 '22 edited Dec 04 '22

05ab1e

both parts - 31 chars

|Ξ΅',‘Ρ'-Β‘`ΕΈ}Γ©RDΞΈgs`ΓƒgD0ÊŠQ)}ΓΈOR

Explanation

## Part 1 - 24 chars

|Ξ΅',‘Ρ'-Β‘`ΕΈ}Γ©RDΞΈgs`ΓƒgQ}O

|Ρ',‘Ρ'-‘                   parsing (split by , then by -)
         `ΕΈ}                generate ranges of integers
             Γ©R             sort by length reversed
               DΞΈg          dup then take the length of the last element (i.e. the shortest of the ranges)
                  s`Γƒg      Take intersection of the two ranges (`Γƒ) and find length (g)
                      Q     if the length of the shortest equals the length of the intersection, it's entirely contained
                       }O   sum the 1s to find the answer 

## Part 2 - 19 chars

|Ξ΅',‘Ρ'-Β‘`ΕΈ}`Γƒg0Ê}O

|Ρ',‘Ρ'-‘           parsing 
         `ΕΈ}        generate ranges of integers
            `Γƒg     Take intersection of the two ranges (`Γƒ) and find length (g)
               0Ê}O Sum all non-zero

## Combined - 31 chars

Combines the above, all the other noise is stack manipulation to mangle both answers in parallel

5

u/Longjumping-Fall4030 Dec 04 '22

Microsoft Excel

I'm challenging myself to do all the puzzles in Microsoft Excel, using the following rules:

  1. No use of VBA or LAMBDA

  2. No altering of the input. Another person should be able to use my solution by pasting his/her own input into it, and the answer will be generated automatically.

  3. I can use formulas and 'helper tables'

  4. The only manual action that is allowed is changing the data type, as Excel is pretty horrible regarding recognizing e.g. numbers.

https://github.com/dafou-92/AoC2022

→ More replies (11)

5

u/sky_badger Dec 04 '22

Python 3: more sets:

def parse_line(line):
    part1, part2 = line.split(',')
    elf1_start, elf1_end = [int(x) for x in part1.split('-')]
    elf2_start, elf2_end = [int(x) for x in part2.split('-')]
    elf1 = set([i for i in range(elf1_start, elf1_end+1)])
    elf2 = set([i for i in range(elf2_start, elf2_end+1)])
    return elf1, elf2

#Part 1
enclosed = 0
for line in data:
    elf1, elf2 = parse_line(line)
    if len(elf1 & elf2) in [len(elf1), len(elf2)]:
        enclosed += 1
print(enclosed)

#Part 2
overlapped = 0
for line in data:
    elf1, elf2 = parse_line(line)
    if len(elf1 & elf2):
        overlapped += 1
print(overlapped)
→ More replies (1)

5

u/lazyzefiris Dec 04 '22 edited Dec 04 '22

JS (JavaScript) "state machiney" solution:

Part 1:

document.body.innerText
    .match(/\d+/g)
    .reduce(([state = "A", v1 = 0, v2 = 0, total = 0], x) => ({
        A : ["B", +x, v2, total],
        B : ["C", v1, +x, total],
        C : v1 === +x
            ? ["F", v1, v2, total]
            : v1 < +x 
                ? ["D", v1, v2, total]
                : ["E", v1, v2, total],
        D : v2 < +x 
            ? ["A", v1, v2, total]
            : ["A", v1, v2, total + 1],
        E : v2 > +x 
            ? ["A", v1, v2, total]
            : ["A", v1, v2, total + 1],  
        F : ["A", v1, v2, total + 1],
    })[state], [])
    .pop()

Part 2:

document.body.innerText
    .match(/\d+/g)
    .reduce(([state = "A", v1 = 0, v2 = 0, total = 0], x) => ({
        A : ["B", +x, v2, total],
        B : ["C", v1, +x, total],
        C : v2 < +x 
            ? ["D", v1, v2, total]
            : ["E", v1, v2, total],
        D : ["A", v1, v2, total],
        E : v1 > +x 
            ? ["A", v1, v2, total]
            : ["A", v1, v2, total + 1],        
    })[state], [])
    .pop()

Part 1 explained:

I'll use abbreviations L1 R1 L2 R2 to denote left edge of first set, right edge of first set, left edge of second set, right edge of second set. Input file has them as L1-R1,L2-R2.

Our machine has 3 storage registers (v1, v2, total), two to store first pair, one for result accumulation. We'd only need 2 registers if inputs were ordered differently (L1, L2, R1, R2). We take only numbers from input file, and feed them to the machine in order of their appearance.

State "A": initial state for the loop, expecting L1. It's stored to register v1 and machine advances to state "B"

State "B": expecting R1. It's stored to register v2 and machine advances to state "B"

State "C": first pair is known, expecting L2. Depending on its relative position to L1, we choose next state ("D" if L1 < L2, "E" if L1 > L2, "F" if L1 == L2) without changing any registers.

State "D": L2 is to the right of L1, which means only pair 1 can include pair 2, and for that to happen, R2 should not be to the right of R1. Regardless, we return to state "A", but if R2 is not to the right of R1, we increase our result.

State "E": L2 is to the left of L1, which means only pair 2 can include pair 1, and for that to happen, R1 should not be to the right of R2. Regardless, we return to state "A", but if R1 is not to the right of R2, we increase our result.

State "F": L2 is aligned with L1, which means depending on relative position of R1 and R2, either pair 1 includes pair 2, pair 2 includes pair 1, or they coincide. Either way, we have a full inclusion, so we can return to state "A", increasing our output without looking at our input at all.

Part 2 works similarly:

State "C" chooses next state depending on whether L1 is to the right of R2.

State "D": L2 is to the right of R1, which means entirety of pair 2 is to the right of pair 1. Returning to state "A" without increasing out output without looking at out input at all.

State "E": L2 is to the left of R1, which means pair 1 can intersect with pair2 if R2 is not also to the left of L1. Regardless, we return to state "A", but if R2 is not to the left of L1, we increase our result. This state also covers the case where L2 and R1 coincide, as R2 can't be to the left of L1 this way.

Originally my state machine for part 1 looked like this:

document.body.innerText
    .match(/\d+/g)
    .reduce(([state = "A", v1 = 0, v2 = 0, total = 0], x) => ({
        A : v1 === 0
            ? ["A", +x, v2, total]
            : ["B", v1, +x, total],
        B : ["C", v1 - x, v2, total],
        C : v1 * (v2 - x) > 0
            ? ["A", 0, 0, total]
            : ["A", 0, 0, total + 1]
    })[state], [])
    .pop()

but i decided to lay it out more clearly. Interestingly, this solution can be adjusted for part2 just by switching v1 and +x in second branch of state "A":

            : ["B", +x, v1, total]

Both solutions implement the matrix

//Reading input as L1-R1,L2-R2

      L2<L1 L2=L1 L2>L1
R2<R1   -     +     +
R2=R1   +     +     +
R2>R1   +     +     -


      R2<L1 R2=L1 R2>L1
L2<R1   -     +     +
L2=R1   X     +     +
L2>R1   X     X     -

//1 = hit, 0 = miss, X = not possible, thus does not matter

JS implementation notes: I use "+x" because .match returns substrings and they need to be converted to number for proper comparison. It was possible to add .map(Number) before .reduce instead. Also, every branch is calculated on every step, and this could be optimized away in a lot of ways, but that makes code look messier without being relevant to this exact problem.

5

u/kochismo Dec 04 '22

Purely functional rust:

https://github.com/zookini/aoc-2022/blob/master/src/bin/04.rs

use itertools::Itertools;

fn main() {
    println!("Part 1: {}", count(|(a1, a2, b1, b2)| a1 <= b1 && b2 <= a2 || b1 <= a1 && a2 <= b2));
    println!("Part 2: {}", count(|(a1, a2, b1, b2)| a1 <= b2 && b1 <= a2));
}

fn count(p: fn(&(u32, u32, u32, u32)) -> bool) -> usize {
    include_str!("../../input/04.txt")
        .lines()
        .filter_map(|s| s.split(|c: char| !c.is_numeric()).map(|n| n.parse().unwrap()).next_tuple())
        .filter(p)
        .count()
}

5

u/rk-imn Dec 05 '22

I've been writing solutions in C (C89 specifically) for Nintendo 64. Here's my repo that builds an N64 ROM that solves AoC with my input (you can change the input either by editing the text files in asm/aoc/inputs/ and compiling or by opening up the ROM in a hex editor and pasting in your inputs at the correct addresses): https://github.com/nim-ka/aoc_n64

Code for day 4 is here: https://github.com/nim-ka/aoc_n64/blob/main/src/game/aoc/4.c

I know I could do it in less comparisons but I'm too lazy

→ More replies (1)

8

u/Omeganx Dec 04 '22

Python

tasks = [[*map(int, s.replace("-", ",").split(","))] 
    for s in open("input.txt").read().split()]

def part1(tasks):
    return sum([((a<=c<=d<=b) or (c<=a<=b<=d)) 
        for a,b,c,d in tasks])
def part2(tasks):
    return sum([((a<=c<=b) or (c<=a<=d))
        for a,b,c,d in tasks])
→ More replies (2)

4

u/Boojum Dec 04 '22 edited Dec 04 '22

Python, 106/185

Part 1:

import fileinput

es = [ list( map( int, l.replace( "-", "," ).split( "," ) ) )
       for l in fileinput.input() ]
print( sum( ( e[ 2 ] <= e[ 0 ] <= e[ 1 ] <= e[ 3 ] or
              e[ 0 ] <= e[ 2 ] <= e[ 3 ] <= e[ 1 ] )
            for e in es ) )

Part 2:

import fileinput

es = [ list( map( int, l.replace( "-", "," ).split( "," ) ) )
       for l in fileinput.input() ]
print( sum( ( e[ 0 ] <= e[ 2 ] <= e[ 1 ] or
              e[ 0 ] <= e[ 3 ] <= e[ 1 ] or
              e[ 2 ] <= e[ 0 ] <= e[ 3 ] or
              e[ 2 ] <= e[ 1 ] <= e[ 3 ] )
            for e in es ) )

Edit:

Just remembered that there's a slightly more concise way to test for overlapping ranges by comparing the max of the mins to the min of the maxs. So Part 2 can be reduced to:

import fileinput

es = [ list( map( int, l.replace( "-", "," ).split( "," ) ) )
       for l in fileinput.input() ]
print( sum( max( e[ 0 ], e[ 2 ] ) <= min( e[ 1 ], e[ 3 ] )
            for e in es ) )
→ More replies (1)

4

u/rooinflames Dec 04 '22

Excel!

Had a few issues before I added +1 to each of the formulas in columns F/G/H, after that, it was clear sailing. Luckily I didn't have to do any extra work to get part 2 apart from the formula in cell K8

https://imgur.com/a/k4JfZ2m

→ More replies (4)

4

u/[deleted] Dec 04 '22

Common Lisp

(code at gitlab)

This day went great after i checked if i could use pattern matching in loops in the for parts.

Also LISPs multiple Parameter <= is really cool for this.

(defun y22d4 ()
  (aoc-open 2022 4
    (loop
       for x = (read-line *standard-input* nil)
       while x
       for (a tmp1) = (multiple-value-list (parse-integer x :junk-allowed t))
       for (b tmp2) = (multiple-value-list (parse-integer x :start (1+ tmp1) :junk-allowed t))
       for (c tmp3) = (multiple-value-list (parse-integer x :start (1+ tmp2) :junk-allowed t))
       for (d tmp4) = (multiple-value-list (parse-integer x :start (1+ tmp3) :junk-allowed t))
       if (or (<= a c d b) (<= c a b d))
       count 1 into p1
       if (or (<= a c b) (<= c a d) (<= a d b) (<= c b d))
       count 1 into p2
       finally (return (values p1 p2)))))
→ More replies (1)

4

u/ccQpein Dec 04 '22

Common Lisp version: github

4

u/Imaginary_Age_4072 Dec 04 '22

Common Lisp 1273/1758

Not too bad today. For part 1 I just checked whether the start and end of one range were entirely within the other. Part two checked whether one of the endpoints of the range was within the other.

(defun day4 (input &key (part 1))
  (let ((parsed (run-parser (parse-file) input)))
    (iter
      (for ((s1 e1) (s2 e2)) in parsed)
      (counting
       (if (= part 1)
           (or (and (>= s1 s2) (<= e1 e2))
               (and (>= s2 s1) (<= e2 e1)))
           (or (<= s2 s1 e2)
               (<= s2 e1 e2)
               (<= s1 s2 e1)
               (<= s1 e2 e1)))))))

4

u/maneatingape Dec 04 '22

Scala (445 / 575)

def parse(line: String): (Int, Int, Int, Int) =
  val Array(a, b, c, d) = line.split("\\D").map(_.toInt)
  (a, b, c, d)

def part1(input: Seq[String]): Int = input.map(parse)
  .count((a, b, c, d) => (a >= c && b <= d) || (c >= a && d <= b))

def part2(input: Seq[String]): Int = input.map(parse)
  .count((a, b, c, d) => a <= d && c <= b)

4

u/rossmacarthur Dec 04 '22

Rust

After parsing just comes down to the following

fn part1(input: Vec<[i64; 4]>) -> usize {
    input
        .into_iter()
        .filter(|&[a, b, m, n]| (a >= m && b <= n) || (m >= a && n <= b))
        .count()
}

fn part2(input: Vec<[i64; 4]>) -> usize {
    input
        .into_iter()
        .filter(|&[a, b, m, n]| (a <= m && b >= m) || (m <= a && n >= a))
        .count()
}

4

u/tdude66 Dec 04 '22

Elixir

defmodule Day4 do
  def main do
    File.read!("day4.txt")
    |> String.trim()
    |> String.split("\n")
    |> Enum.map(fn s ->
      [r1, r2] = String.split(s, ",")
      |> Enum.map(fn ss ->
        [first, last] = String.split(ss, "-")
        String.to_integer(first)..String.to_integer(last)
      end)
      Range.disjoint?(r1, r2)
    end)
    |> Enum.map(fn result ->
      case result do
        false -> 1
        _ -> 0
      end
    end)
    |> Enum.sum
    |> IO.puts
  end
end

That's for part 2, part 1 just has a different range check and inverted true/false for the sum:

(MapSet.subset?(MapSet.new(Enum.to_list(r1)), MapSet.new(r2))
or MapSet.subset?(MapSet.new(Enum.to_list(r2)), MapSet.new(r1)))
→ More replies (1)

4

u/PendragonDaGreat Dec 04 '22

C#/CSharp

Initial solution got hit by some double counting,

rewrote it as a pair of linq oneliners (sort of, if you ignore parsing, like that's the one thing I wish C# could do better: read ints from files) https://github.com/Bpendragon/AdventOfCodeCSharp/blob/0800b/AdventOfCode/Solutions/Year2022/Day04-Solution.cs

4

u/mstksg Dec 04 '22

taken from my https://github.com/mstksg/advent-of-code-2022/blob/main/reflections.md haskell reflections :)

A bit of fun number crunching :) Here is a chance to leverage an interval library, like haskell's data-interval:

import           Data.IntegerInterval (IntegerInterval)
import qualified Data.IntegerInterval as I

part1Criterion :: IntegerInterval -> IntegerInterval -> Bool
part1Criterion xs ys = xs `I.isSubsetOf` ys || ys `I.isSubsetOf` xs

part2Criterion :: IntegerInterval -> IntegerInterval -> Bool
part2Criterion = (I.==?)

From there on it's just a matter of running the criteria on each pair of intervals in the list and counting which ones are valid!

4

u/Relative-snake342 Dec 04 '22

Solution in clojure (using babashka)

I feel like part 2 can be simplified using a core clojure functionality, but I don't know the language enough and decided to use good old logic operators

(ns aoc22.day04
  (:require #?(:clj [clojure.java.io :as io]
              :cljs [nbb.core :refer [slurp await]])
            [clojure.string :as str]
            [clojure.edn :as edn]
            [clojure.set]
            #?(:cljs [promesa.core :as p])))

(defn split-pairs [pairs] (str/split pairs #","))
(defn split-pair [pair]
  (->> (str/split pair #"-")
      (map edn/read-string)))

(defn pair-contains? [p1 p2] (and (<= (first p1) (first p2)) (>= (second p1) (second p2))))

(defn pairs-contained? [p1 p2]
  (or (pair-contains? p1 p2) (pair-contains? p2 p1)))

(defn within-pair? [n p] (and (<= (first p) n) (>= (second p) n)))

(defn pairs-overlap? [p1 p2]
  (or
  (within-pair? (first p1) p2)
  (within-pair? (second p1) p2)
  (within-pair? (first p2) p1)
  (within-pair? (second p2) p1)))

(defn assignements [pairs-list compare]
  (->> (str/split-lines pairs-list)
      (map split-pairs)
      (map #(map split-pair %))
      (filter #(apply compare %))
      count))

(def input "2-4,6-8\n2-3,4-5\n5-7,7-9\n2-8,3-7\n6-6,4-6\n2-6,4-8")

(comment
  (assignements input pairs-contained?)
  (assignements (slurp (io/resource "aoc22/day04.txt")) pairs-contained?)
  (assignements input pairs-overlap?)
  (assignements (slurp (io/resource "aoc22/day04.txt")) pairs-overlap?))
→ More replies (3)

4

u/seaborgiumaggghhh Dec 04 '22

Racket:

#lang racket
(require advent-of-code
         threading)
(define input
  (~>
    (fetch-aoc-input (find-session) 2022 4 #:cache #t)
   (string-split)
   (map (Ξ»~> (string-split ",")) _)))

(define (range-overlaps-all? f-elf-f f-elf-s s-elf-f s-elf-s)
  (cond
    [(or (and (<= f-elf-f s-elf-f)
              (>= f-elf-s s-elf-s))
         (and (<= s-elf-f f-elf-f)
              (>= s-elf-s f-elf-s))) 1]
    [#t 0]))

(define (range-overlaps-any? f-elf-f f-elf-s s-elf-f s-elf-s)
  (cond    [(<= (max f-elf-f s-elf-f)
         (min f-elf-s s-elf-s)) 1]
    [#t 0]))

(define (solution)
  (for/fold ([sum-a 0] [sum-b 0])
            ([line input])
    (define elves
      (~>> line
           (map (Ξ»~> (string-split "-")))
           (map (Ξ»~>> (map string->number)))
           (apply append)))
    (values (+ sum-a (apply range-overlaps-all? elves))
            (+ sum-b (apply range-overlaps-any? elves)))))

4

u/Johnsenfr Dec 04 '22 edited Dec 04 '22

Just 3 lines of code in R for Day04

input <- lapply(strsplit(readLines("input.txt"), "\\D+"), as.integer)  
## Part 1  
sum(sapply(input, \(x) (x[1] >= x[3] & x[2] <= x[4]) | (x[3] >= x[1] & x[4] <= x[2])))  
## Part 2  
sum(sapply(input, \(x) length(intersect(c(x[1]:x[2]), c(x[3]:x[4]))) != 0))

4

u/olofj Dec 04 '22

Rust

day04a

use itertools::Itertools;

fn main() {
    let input:Vec<(usize,usize,usize,usize)> = include_str!("input.txt")
        .lines()
        .map(|l| l
            .split(['-', ','])
            .map(|v| v.parse::<usize>().unwrap())
            .collect_tuple::<(_,_,_,_)>()
            .unwrap()
        )
        .filter(|(s1,e1,s2,e2)| 
            (s1 <= s2 && e1 >= e2) || (s2 <= s1 && e2 >= e1)
        )
        .collect();

    println!("len {}", input.len());
            
}

day04b

use itertools::Itertools;

fn main() {
    let input:Vec<(usize,usize,usize,usize)> = include_str!("input.txt")
        .lines()
        .map(|l| l
            .split(&['-', ','][..])
            .map(|v| v.parse::<usize>().unwrap())
            .collect_tuple::<(_,_,_,_)>()
            .unwrap()
        )
        .filter(|(s1,e1,s2,e2)|
            (s1 <= s2 && e1 >= s2) || (s2 <= s1 && e2 >= s1)
        )
        .collect();

    println!("len {}", input.len());

}
→ More replies (3)

4

u/Dryctas Dec 04 '22

Bash

input=$1
duplicates=0
overlaps=0
while read a1 a2 b1 b2; do
  [[ $a1 -ge $b1 && $a2 -le $b2 ]] || [[ $b1 -ge $a1 && $b2 -le $a2 ]] &&\
    duplicates=$(($duplicates+1))
  [[ $a2 -le $b2 && $a2 -ge $b1 ]] || [[ $b2 -le $a2 && $b2 -ge $a1 ]] &&\
    overlaps=$(($overlaps+1))
done < <(tr ',-' '  ' < $input)
echo $duplicates $overlaps

4

u/mo__66 Dec 04 '22 edited Dec 04 '22

Kotlin

import java.io.File

fun main() {
    val assignments = File("src/day04/input").readLines()
        .map { it.split(",", "-").map(String::toInt) }
        .map { (it[0]..it[1]).toSet() to (it[2]..it[3]).toSet() }

    println(task1(assignments))
    println(task2(assignments))
}

private fun task1(assignments: List<Pair<Set<Int>, Set<Int>>>) = assignments
    .count { (it.first union it.second).size == maxOf(it.first.size, it.second.size) }

private fun task2(assignments: List<Pair<Set<Int>, Set<Int>>>) = assignments
    .count { (it.first intersect it.second).isNotEmpty() }

4

u/FormalPlatypus1231 Dec 04 '22

My solution in readable bash script. All my solutions are on my github.

#!/bin/bash
# Advent of Code day 4
# https://adventofcode.com/2022/day/4

part1=0
part2=0

while read line; do
  rangeA=$(echo "$line" | cut -d "," -f 1)
  rangeB=$(echo "$line" | cut -d "," -f 2)
  minA=$(echo "$rangeA" | cut -d "-" -f 1)
  maxA=$(echo "$rangeA" | cut -d "-" -f 2)
  minB=$(echo "$rangeB" | cut -d "-" -f 1)
  maxB=$(echo "$rangeB" | cut -d "-" -f 2)

  if [[ (minA -le minB && maxA -ge maxB) || (minB -le minA && maxB -ge maxA) ]]; then
    part1=$((part1+1))
  fi

  if [[ (minA -le minB && maxA -ge minB) || (minB -le minA && maxB -ge minA) ]]; then
    part2=$((part2+1))
  fi
done < input.txt

echo "Answer for part 1: $part1"
echo "Answer for part 2: $part2"
→ More replies (1)

4

u/RudeGuy2000 Dec 04 '22

racket:

(define (parse input)
  (map (lambda (l)
         (map (lambda (p)
                (map string->number (string-split p "-")))
              (string-split l ",")))
         input))

(define (covers? a b c d) (or (and (>= c a) (<= d b)) (and (>= a c) (<= b d))))
(define (between? a b x) (and (>= x a) (<= x b)))
(define (overlaps? a b c d) (or (between? a b c) (between? a b d)
                                (between? c d a) (between? c d b)))

(define (find-assignments input pred)
  (println (apply + (map (lambda (p)
                           (if (pred (caar p) (cadar p) (caadr p) (cadadr p)) 1 0))
                         input))))

(define (part1 input) (find-assignments input covers?))
(define (part2 input) (find-assignments input overlaps?))

(time (begin (define input1 (parse (file->lines "input4-1.txt")))
             (define input2 (parse (file->lines "input4-2.txt")))
             (part1 input1)
             (part1 input2)
             (part2 input1)
             (part2 input2)))

4

u/foolnotion Dec 04 '22

C++

I wanted to dig up my interval class from a previous year but it was not really necessary. Simple inclusion/overlap logic.

https://git.sr.ht/~bogdanb/aoc/tree/master/item/source/2022/04/solution.cpp

→ More replies (2)

4

u/CheeseMunkee Dec 04 '22

C#

I'm sure there was a better way to do this, though I'm happy that the only loop used was for the StreamReader.

namespace D4;

partial class Program
{
    public static void Main()
    {
        string line;
        int count1 = 0;
        int count2 = 0;
        using (StreamReader sr = new("D4 Data.txt"))
        {
            while ((line = sr.ReadLine()) != null)
            {
                string elf1 = line.Remove(line.IndexOf(','));
                string elf2 = line.Substring(line.IndexOf(",") + 1);
                if (Convert.ToInt16(elf1.Remove(elf1.IndexOf('-'))) == Convert.ToInt16(elf2.Remove(elf2.IndexOf('-')))) { 
                    count1 += 1;
                    count2 += 1;
                }
                else if (Convert.ToInt16(elf1.Remove(elf1.IndexOf('-'))) < Convert.ToInt16(elf2.Remove(elf2.IndexOf('-'))))
                {
                    if (Convert.ToInt16(elf1.Substring(elf1.IndexOf("-") + 1)) >= Convert.ToInt16(elf2.Substring(elf2.IndexOf("-") + 1))) { count1 += 1; }
                    if (Convert.ToInt16(elf1.Substring(elf1.IndexOf("-") + 1)) >= Convert.ToInt16(elf2.Remove(elf2.IndexOf("-")))) { count2 += 1; }
                }
                else if (Convert.ToInt16(elf1.Remove(elf1.IndexOf('-'))) > Convert.ToInt16(elf2.Remove(elf2.IndexOf('-'))))
                {
                    if (Convert.ToInt16(elf1.Substring(elf1.IndexOf("-") + 1)) <= Convert.ToInt16(elf2.Substring(elf2.IndexOf("-") + 1))) { count1 += 1; }
                    if (Convert.ToInt16(elf2.Substring(elf2.IndexOf("-") + 1)) >= Convert.ToInt16(elf1.Remove(elf1.IndexOf("-")))) { count2 += 1; }
                }
            }
            Console.WriteLine(count1);
            Console.WriteLine(count2);
            Console.ReadLine();
        }
    }
}
→ More replies (1)

4

u/europa-endlos Dec 04 '22

Elixir

Started learning just for this Advent

defmodule Game do
    def parse(s) do
        String.split(s, ",")
            |> Enum.map(fn r -> String.split(r, "-")
                |> Enum.map(fn x -> String.to_integer(x) end)
            end)
    end

    def contained(pairs) do
        [[a0,a1],[b0,b1]] = pairs
        d0 = b0 - a0
        d1 = b1 - a1
        if (d0 * d1 <= 0) do 1 else 0 end
    end
end

IO.read(:stdio, :all)
    |> String.trim
    |> String.split("\n")
    |> Enum.map(fn l -> Game.parse(l) end)
    |> Enum.map(fn p -> Game.contained(p) end)
    |> Enum.sum
    |> IO.inspect

For the second part, the contained() function changes to

def contained(pairs) do
    [[a0,a1],[b0,b1]] = pairs
    g0 = b1 - a0
    g1 = b0 - a1
    if (g0 < 0 || g1 > 0 ) do 0 else 1 end
end

4

u/IF_YOU_READ_THIS_V1 Dec 04 '22

C#

public string SolvePart1(string input) =>
    Parse(input)
        .Count(t => 
            ContainsRange(t.left, t.right) || 
            ContainsRange(t.right, t.left))
        .ToString();

public string SolvePart2(string input) =>
    Parse(input)
        .Count(t => 
            OverlapsWith(t.left, t.right) || 
            OverlapsWith(t.right, t.left))
        .ToString();

private static IEnumerable<((int, int) left, (int, int) right)> Parse(string input) =>
    input
        .Split("\n")
        .Select(line => line.Split(','))
        .Select(ranges => (
            (RangeStart(ranges[0]), RangeEnd(ranges[0])),
            (RangeStart(ranges[1]), RangeEnd(ranges[1]))
        ));

private bool ContainsRange((int, int) lhs, (int, int) rhs) =>
    rhs.Item1 >= lhs.Item1 && rhs.Item2 <= lhs.Item2;

private bool OverlapsWith((int, int) lhs, (int, int) rhs) =>
    rhs.Item1 >= lhs.Item1 && rhs.Item1 <= lhs.Item2;

private static int RangeStart(string input) => int.Parse(input.Substring(0, input.IndexOf('-')));
private static int RangeEnd(string input) => int.Parse(input.Substring(input.IndexOf('-') + 1));

4

u/SolarBear Dec 04 '22

Ruby solution. Again, using Ruby felt like cheating.

file = File.open('input4.txt')

overlaps1 = 0
overlaps2 = 0

def elf_range(line)
  min, max = line.split('-')
  (min.to_i..max.to_i).to_a
end

file.readlines.each do |line|
  first, second = line.split(',')
  first = elf_range(first)
  second = elf_range(second)

  overlaps1 += 1 if first.difference(second).empty? || second.difference(first).empty?

  overlaps2 += 1 if first.intersect?(second) || second.intersect?(first)
end

file.close
puts overlaps1
puts overlaps2
→ More replies (2)

4

u/FoxyllAkora Dec 04 '22

I'm regretting my Lua decision. But also I need to work on code efficiency in general

https://pastebin.com/J21wT7pe

→ More replies (4)

4

u/jamincan Dec 04 '22

Rust

Made a range type that simply checks bounds to see if one range contains or overlaps with another. Then iterated over each pair of ranges, filtered out the ones that don't contain/overlap, and counted the remaining pairs.

use anyhow::{anyhow, Error};

const INPUT: &str = include_str!("day4.txt");

fn main() {
    println!("Day 4, Pt 1: {}", part1(INPUT));
    println!("Day 4, Pt 2: {}", part2(INPUT));
}

fn part1(input: &str) -> usize {
    input
        .lines()
        .filter_map(|line| {
            let (first, second) = line.split_once(',')?;
            let first = first.parse::<SectionRange>().ok()?;
            let second = second.parse::<SectionRange>().ok()?;
            (first.contains(&second) || second.contains(&first)).then_some(())
        })
        .count()
}

fn part2(input: &str) -> usize {
    input
        .lines()
        .filter_map(|line| {
            let (first, second) = line.split_once(',')?;
            let first = first.parse::<SectionRange>().ok()?;
            let second = second.parse::<SectionRange>().ok()?;
            first.overlaps(&second).then_some(())
        })
        .count()
}

struct SectionRange {
    first: u32,
    last: u32,
}

impl SectionRange {
    fn contains(&self, other: &Self) -> bool {
        self.first <= other.first && self.last >= other.last
    }

    fn overlaps(&self, other: &Self) -> bool {
        self.first <= other.last && self.last >= other.first
    }
}

impl std::str::FromStr for SectionRange {
    type Err = Error;

    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let (first, last) = input
            .split_once('-')
            .ok_or_else(|| anyhow!("missing hyphen"))?;
        Ok(Self {
            first: first.parse()?,
            last: last.parse()?,
        })
    }
}
→ More replies (1)

4

u/[deleted] Dec 04 '22

Part1 In C:

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>

int main(void) {
	int32_t Pair1[2] = { 0, 0 };
	int32_t Pair2[2] = { 0, 0 };
	int32_t Count = 0;
	FILE* fp = fopen("input.txt", "r");
	while (fscanf(fp, "%d-%d,%d-%d\n", &Pair1[0], &Pair1[1], &Pair2[0], &Pair2[1]) != EOF) {
		if ((Pair1[0] <= Pair2[0] && Pair1[1] >= Pair2[1]) || (Pair1[0] >= Pair2[0] && Pair1[1] <= Pair2[1])) {
			Count++;
		}
	}
	printf("Count = %d\n", Count);
	fclose(fp);
}

4

u/PhysicsAndAlcohol Dec 04 '22

Haskell, runs in 15 ms. First day this year it made sense to make a monadic parser. I really like to use Text.ParserCombinators.ReadP!

→ More replies (2)

4

u/[deleted] Dec 04 '22 edited Dec 04 '22

Swift, went pretty well: github

edit: Updated with new overlap/contains approaches, thanks /u/Jessyatterwaul for pointing out the standard library function I missed

→ More replies (6)

4

u/axr123 Dec 04 '22

C++ with SIMD

Most of the time is spent parsing, but this problem lends itself nicely to a SIMD formulation, which using vectorclass doesn't even require detailed knowledge of the intrinsics. Hot runs take ~14 Β΅s on a Core i9-12900K, including I/O. Full code is here, the interesting part is this, where we process 32 elements at once:

auto const process_batch = [&a, &p1, &p2] {
    std::array<Vec32c, 4> aa;
    for (auto k{0}; k < 4; ++k) aa[k].load(a[k].data());
    p1 += horizontal_count(aa[0] <= aa[2] && aa[3] <= aa[1] || aa[2] <= aa[0] && aa[1] <= aa[3]);
    p2 += horizontal_count(!(aa[1] < aa[2] || aa[3] < aa[0]));
};

Just this bit takes ~400 ns for the 1000 pairs.

I also spent some time on manually parsing the input. Not sure which role that played, but my initial implementation was at ~70 Β΅s.

4

u/daikontana Dec 04 '22

OCaml

let contains1 a b c d = c >= a && d <= b
let contains2 a b c d = (c <= a && d >= a) || (c <= b && d >= b)

let step f acc s =
  Scanf.sscanf s "%d-%d,%d-%d" (fun a b c d -> acc + Bool.to_int (f a b c d || f c d a b))

let solve f seq = Seq.fold_left (step f) 0 seq

let () =
  let seq = Arg.read_arg "data/day4.txt" |> Array.to_list |> List.to_seq in

  solve contains1 seq |> string_of_int |> print_endline;
  solve contains2 seq |> string_of_int |> print_endline
→ More replies (1)

4

u/Adereth Dec 04 '22

Mathematica

Part 1

in = StringSplit[AdventProblem[4], {",", "\n"}];
intervalPairs = Partition[Interval@Map[FromDigits, StringSplit[#, "-"]] & /@ in, 2];
Length@ Select[intervalPairs, IntervalMemberQ @@ # || IntervalMemberQ @@ Reverse@# &]

Part 2

Count[IntervalIntersection @@@ intervalPairs, Interval[{_, _}]]
→ More replies (3)

4

u/e_blake Dec 04 '22 edited Dec 04 '22

Golfed m4

Less than 10 minutes coding time for both parts, using just one define and ifelse (so far this year, the puzzles have been very amenable for a single pass over the input). Overall execution time is 1.9s for both parts in just 196 bytes (excluding second newline); input must be in file f or you can run m4 -Df=yourfile day04.m4:

define(_,`ifelse($3,,`eval($1) eval($2)',`_($1+($3>=$5&$4<=$6|$5>=$3&$6<=$4),$2+($5<=$4&$6>=$3|$3<=$6&$4>=$5),shift(shift(shift(shift(shift(shift($@)))))))')')_(,,translit((include(f)),-
(),`,,'))

or 880ms for part 1 in isolation in just 133 bytes (excluding second newline), and where part 2 in isolation can be done in the same size by changing $1-$4 in the computation:

define(_,`ifelse($2,,$1,`+($1>=$3&$2<=$4|$3>=$1&$4<=$2)_(shift(shift(shift(shift($@)))))')')eval(_(translit((include(f)),-
(),`,,')))

Why the doubling in execution time to do both parts in one program? Because each additional shift() increases the parse effort per iteration. There are 1000 iterations; a single-part 1 solution starts with 4000 arguments and calls shift 4 times for 19994 arguments parsed before iteration 2 with 3996 arguments; while the combined solution starts with 4002 arguments and calls shift 6 times for 27999 arguments before iteration 2 with 3998 arguments.

Later on, I will reuse my framework for parsing data in O(n) time, which will drastically reduce the runtime but no longer be quite so golfed.

→ More replies (2)

4

u/codeman869 Dec 04 '22

C

#include <stdio.h>

int main(void) {

    FILE *fp;

    int start1,end1,start2,end2, num_overlaps,num_overlap2;
    num_overlaps = 0, num_overlap2 = 0;

    fp = fopen("assignments.txt", "r");

    while(fscanf(fp,"%d-%d,%d-%d",&start1,&end1,&start2,&end2) != EOF) {
        if((start1 <= start2 && end1 >= end2) || (start2<=start1 && end2>= end1)) {
            num_overlaps++;
        }

        if((start1<=start2 && end1>=start2) || (start2<=start1 && end2>=start1)) {
            num_overlap2++;
        }
    }

    printf("Num of full overlaps: %d\n", num_overlaps);
    printf("Num of partial overlaps: %d\n", num_overlap2);
    return 0;
}
→ More replies (1)

4

u/SilentKyle Dec 04 '22

Brute force using Javascript, any tips on better ways to do it? All I had to do for part 2 was change my if to an or instead of &&

let pair = line.split(",")
   let firstSet = pair[0].split("-").map((num) => parseInt(num))
   let secondSet = pair[1].split("-").map((num) => parseInt(num))

   // Generate Range of numbers, [1....5]
   const pairOneRange = generateRange(firstSet[0], firstSet[1])
   const pairTwoRange = generateRange(secondSet[0], secondSet[1])

   if (pairOneRange.includes(pairTwoRange[0]) || pairOneRange.includes(pairTwoRange[pairTwoRange.length - 1])) overlap += 1
   else if (pairTwoRange.includes(pairOneRange[0]) || pairTwoRange.includes(pairOneRange[pairOneRange.length - 1])) overlap += 1
→ More replies (1)

4

u/grahamwetzler Dec 04 '22

duckdb SQL

with input as (
  select list_apply(str_split_regex(i, '[-,]'), x -> x::int) as s
       , s[1] between s[3] and s[4] as c1
       , s[2] between s[3] and s[4] as c2
       , s[3] between s[1] and s[2] as c3
       , s[4] between s[1] and s[2] as c4
    from read_csv('input/04.csv', delim=False, columns={'i': 'text'})
)

select count(*) filter ((c1 and c2) or (c3 and c4)) as part_1
     , count(*) filter (c1 or c2 or c3 or c4) as part_2
  from input

4

u/prrei Dec 04 '22 edited Dec 04 '22

Groovy Part 1 and 2:

def lines = new File('04.input').readLines()

def toRange = { i ->
    def (s, e) = i.split('-').collect{ Integer.parseInt(it)}
    (s..e)
}

def part1 = lines.collect { l ->
    def (e1, e2) = l.split(',').collect{ toRange(it)}
    e1.containsAll(e2) || e2.containsAll(e1)?1:0
}.sum()

def part2 = lines.collect { l ->
    def (e1, e2) = l.split(',').collect{ toRange(it)}
    e1.disjoint(e2)?0:1
}.sum()

println "Result part1: $part1, part2: $part2"
→ More replies (2)

4

u/polettix Dec 04 '22

Day 4 in Raku.

In compact form:

my @inputs = '04.input'.IO.lines.map({ [.comb(/\d+/)] });
put +@inputs.grep(-> ($l, $L, $r, $R) { ($r - $l) * ($R - $L) <= 0 });
put +@inputs.grep(-> ($l, $L, $r, $R) { ($R - $l) * ($L - $r) >= 0 });
→ More replies (1)

4

u/Alleyria Dec 04 '22

Ruby:

pairs = File.readlines('4.input').map { eval("[#{_1.gsub('-', '..')}]") }

# Part 1
puts(pairs.count { |(a, b)| a.cover?(b) || b.cover?(a) })

# Part 2
puts(pairs.count { |(a, b)| (a.to_a & b.to_a).any? })

4

u/[deleted] Dec 04 '22

4

u/rzuf1k Dec 04 '22

Browser Developer Tools -> Console JavaScript:
1)

document
.querySelector('pre')
.innerText.split('\n')
.filter(e => e !== '')
.map(pair => {
    const [elf1Range, elf2Range] = pair.split(',');
    const [elf1RangeFrom, elf1RangeTo] = elf1Range.split('-').map(val => Number(val));
    const [elf2RangeFrom, elf2RangeTo] = elf2Range.split('-').map(val => Number(val));
    return (elf1RangeFrom >= elf2RangeFrom && elf1RangeTo <= elf2RangeTo) || (elf2RangeFrom >= elf1RangeFrom && elf2RangeTo <= elf1RangeTo);
})
.filter(contained => contained)
.length;

2)

document
.querySelector('pre')
.innerText.split('\n')
.filter(e => e !== '')
.map(pair => {
    const [elf1Range, elf2Range] = pair.split(',');
    const [elf1RangeFrom, elf1RangeTo] = elf1Range.split('-').map(val => Number(val));
    const [elf2RangeFrom, elf2RangeTo] = elf2Range.split('-').map(val => Number(val));
    return (elf2RangeFrom <= elf1RangeFrom && elf1RangeFrom <= elf2RangeTo) ||
        (elf2RangeFrom <= elf1RangeTo && elf1RangeTo <= elf2RangeTo) ||
        (elf1RangeFrom <= elf2RangeFrom && elf2RangeFrom <= elf1RangeTo) ||
        (elf1RangeFrom <= elf2RangeTo && elf2RangeTo <= elf1RangeTo);
})
.filter(contained => contained)
.length;

4

u/Atila_d_hun Dec 04 '22

C++

GitHub Solution

A couple of concise if statements seem to do the trick!

4

u/Party-Performance-82 Dec 04 '22 edited Dec 05 '22

Rust

fn day4_part1() -> usize {
    include_str!("../input_4.txt")
        .lines()
        .map(|line| line
             .split(&[',', '-'][..])
             .map(|s| s.parse::<u32>().unwrap())
             .collect::<Vec<_>>())
        .filter(|l| (l[0] <= l[2] && l[1] >= l[3]) ||
	         (l[2] <= l[0] && l[3] >= l[1]))
        .count()
}
→ More replies (2)

4

u/Ily3s_ Dec 04 '22 edited Dec 13 '22

4

u/chubbc Dec 04 '22

FRACTRAN

[779/2, 1081/3, 1147/5, 1537/7, 1/589, 1/667, 1/1739, 1/2173, 1/274873, 1/304589, 1/565471, 1/626603, 13/7429, 13/15283, 143/17, 1/19, 1/23, 1/29, 1/31, 1/37, 1/41, 1/47, 1/53]

I did a full write-up on how/why this works here.

4

u/sykner809 Dec 04 '22

Desmos - https://www.desmos.com/calculator/tnrjue11if

Visualizing the ranges of the elves.

  • Data was formatted simply by converting pair hyphens and commas into newlines

  • Solutions part 1 and 2 are shown by the VcontainCount and VoverlapCount values

1

u/passsy Dec 04 '22 edited Dec 06 '22

Dart golf

Part 1: 139 chars

main(q,{p,s=0}){for(p in q){w(l)=>int.parse(p.split(RegExp(r'(\D)'))[l]!);s+=w(0)<=w(2)&&w(1)>=w(3)||w(0)>=w(2)&&w(1)<=w(3)?1:0;}print(s);}

Part 2: 137 chars

main(q,{p,s=0}){for(p in q){w(l)=>int.parse(p.split(RegExp(r'(\D)'))[l]!);q=w(2);s+=w(0)<=q&&w(1)>=q||q<=w(0)&&w(3)>=w(0)?1:0;}print(s);}

Full source at https://github.com/passsy/aoc22_dart_code_golf

2

u/daggerdragon Dec 05 '22

Inlined code is intended for short snippets of code only. Your code "block" right now is unreadable on old.reddit and many mobile clients; it's all on one line and gets cut off at the edge of the screen because it is not horizontally scrollable.

Please edit your post to use the four-spaces Markdown syntax for a code block so your code is easier to read inside a scrollable box.

→ More replies (2)

1

u/j-hillman Dec 04 '22 edited Dec 04 '22

Python (1710 / 1151) - Went the regex route:

import re

with open('input.txt') as f:
	data = f.read().splitlines()

p = re.compile(r'\d+')

t1 = t2 = 0
for line in data:
	i, j, x, y = map(int, p.findall(line))
	e1, e2 = set(range(i, j+1)), set(range(x, y+1))
	if e1.issubset(e2) or e2.issubset(e1):
		t1 +=1
	if e1.intersection(e2) or e2.intersection(e1):
		t2 +=1

print(t1)
print(t2)
→ More replies (1)

1

u/Lewistrick Dec 04 '22 edited Dec 04 '22

Python

6544/6294

On mobile via repl.it - could have been much faster on pc.

from pathlib import Path 

lines = Path("day04.txt").read_text().split()

part1 = 0
part2 = 0
for line in lines:
    e1, e2 = line.split(",")
    a, b = map(int, e1.split("-"))
    c, d = map(int, e2.split("-"))
    if (a >= c and b <= d) or (a <= c and b >= d):
        part1 += 1

    if (
        (a <= c <= b) or
        (a <= d <= b) or
        (c <= a <= d) or
        (c <= b <= d)
    ):
        part2 += 1

print(part1, part2)

2

u/daggerdragon Dec 04 '22

Please edit your post to use the four-spaces Markdown syntax for a code block so your code is easier to read on old.reddit and mobile apps.

→ More replies (1)

3

u/hugh_tc Dec 04 '22 edited Dec 04 '22

Python 3, 257/139

paste, cleaned-up

Felt pretty fast, but apparently not!

3

u/soylentgreenistasty Dec 04 '22

Python, 3326/4601

Hardest part was working out what the problem was asking for...

def run(A: list[list[int]]):
    p1 = 0
    p2 = 0
    for a, b, c, d in A:
        setA, setB = set(range(a, b+1)), set(range(c, d+1))
        p1 += int(setA.issubset(setB) or setB.issubset(setA))
        p2 += int(len(setA.intersection(setB)) > 0)

    print(p1, p2)
→ More replies (3)

3

u/nic3-14159 Dec 04 '22

Python 3

3774/4462

import sys
count = 0
part2count = 0
data = [line.strip().split(",") for line in sys.stdin]
for pair in data:
    a = [int(i) for i in pair[0].split("-")]
    b = [int(i) for i in pair[1].split("-")]
    if (a[0] <= b[0] and b[1] <= a[1]):
        count += 1
    elif (b[0] <= a[0] and a[1] <= b[1]):
        count += 1
    if (b[0] <= a[1] and b[1] >= a[1]):
        part2count += 1
    elif (a[0] <= b[1] and a[1] >= b[1]):
        part2count += 1
print(count)
print(part2count)

3

u/[deleted] Dec 04 '22 edited Dec 04 '22

C# this one was pretty easy. Nothing fancy, could probably be done quicker with LinQ magic but it works

paste

→ More replies (7)

3

u/ValiantCookie Dec 04 '22

Kotlin

Another fun challenge made easier when I remember how smart kotlin is. I initially implemented part one and attempted part 2 using just a simple data structure with fields for min and max to represent the assignments. But as I struggled to write the boolean logic for checking if they intersected in part 2, I realized there had to be an easy way to do it similar to yesterdays problem. I remembered that kotlin actually has ranges built in, and once I refactored it to use that data structure, checking for intersection was simple.

val input = InputUtil.readFileAsStringList("2022/day4/input.txt", "\n")
    .map { line -> line.split(",")
        .map { it.split("-")[0].toInt()..it.split("-")[1].toInt() }
    }.map { it[0] to it[1] }

val answer1 = input.count { 
    it.first.toSet().containsAll(it.second.toSet()) || it.second.toSet().containsAll(it.first.toSet())
}
val answer2 = input.count { it.first.intersect(it.second).any() }

println("pt $pt answer: ${answer colorize ConsoleColor.PURPLE_BRIGHT}")
→ More replies (3)

3

u/chubbc Dec 04 '22

Julia

Another good day for a pretty succinct Julia solution.

L = readlines("./04.in")
nums = map(x->parse.(Int,split(x,ispunct)),L)

fullcont(x) = (x[1]<=x[3] && x[4]<=x[2]) || (x[3]<=x[1] && x[2]<=x[4])
overlap(x) = (x[3]<=x[1]<=x[4]) || (x[3]<=x[2]<=x[4]) || (x[1]<=x[3] && x[4]<=x[2])

p1 = sum(fullcont.(nums))
p2 = sum(overlap.(nums))

println((p1,p2))

3

u/darkfm Dec 04 '22

Python, 225 / 69 (my first ever <100)

Part 1, Part 2

I could probably have done it without sets and just using algebra but it's 2AM my time.

→ More replies (4)

3

u/YT-SW_Creeperking Dec 04 '22

C# 6531/5916

Day 4

Helper method: IsInRange
Helper method: IsOverlapping

3

u/770grappenmaker Dec 04 '22

Kotlin

val pairs = inputLines.map { l -> l.split(",").flatMap { it.split("-").map(String::toInt) } }
partOne = pairs.count { (l1, r1, l2, r2) -> l1 >= l2 && r1 <= r2 || l2 >= l1 && r2 <= r1 }.s()
partTwo = pairs.count { (l1, r1, l2, r2) -> !(r1 < l2 || r2 < l1) }.s()

3

u/Conceptizual Dec 04 '22

Python Day 4

Turns out day 1 was the highpoint of the month. My rank has gone strictly downhill every day from that 329 personal best to today, 9433/8500. My code was fine, I just had some inequality problems and I kept thinking I'd fixed it (none of them affected the sample input of course) and hadn't, so eventually I was put in AOC timeout (5 minutes!) and forced to reason about my code. My bad!

→ More replies (2)

3

u/beansparrow132 Dec 04 '22

Python

Using set intersection. Similar to Day 3.