use std::cmp::max;
use std::str::FromStr;
pub struct Claim {
id: usize,
x: usize,
y: usize,
l: usize,
h: usize,
}
pub struct Fabric {
claims: Vec<Claim>,
overlaps: Vec<Vec<u8>>,
}
pub fn read_claim(input: &str) -> Claim {
let num: Vec<usize> = input
.split(|c| "#@,:x ".contains(c))
.filter_map(|c| usize::from_str(c).ok())
.collect();
debug_assert!(num.len() == 5);
Claim {
id: num[0],
x: num[1],
y: num[2],
l: num[3],
h: num[4],
}
}
pub fn read(input: &str) -> Fabric {
let mut dimensions = (0, 0);
let claims: Vec<Claim> = input
.lines()
.map(str::trim)
.filter(|s| !s.is_empty())
.map(read_claim)
.inspect(|c| {
dimensions.0 = max(c.x + c.l, dimensions.0);
dimensions.1 = max(c.y + c.h, dimensions.1);
}).collect();
let mut overlaps = vec![vec![0; dimensions.1]; dimensions.0];
for claim in claims.iter() {
for x in claim.x..claim.x + claim.l {
for y in claim.y..claim.y + claim.h {
overlaps[x][y] += 1;
}
}
}
Fabric { claims, overlaps }
}
pub fn part1(fabric: &Fabric) -> usize {
fabric
.overlaps
.iter()
.flat_map(|v| v.iter())
.filter(|c| **c > 1)
.count()
}
pub fn part2(fabric: &Fabric) -> usize {
for claim in fabric.claims.iter() {
let mut overlap = false;
for x in claim.x..claim.x + claim.l {
for y in claim.y..claim.y + claim.h {
if fabric.overlaps[x][y] > 1 {
overlap = true
}
}
}
if !overlap {
return claim.id;
}
}
0
}
#[test]
fn examples() {
let fabric = read(
r"
#1 @ 1,3: 4x4
#2 @ 3,1: 4x4
#3 @ 5,5: 2x2
",
);
assert_eq!(4, part1(&fabric));
assert_eq!(3, part2(&fabric))
}
#[test]
fn solution() {
let fabric = read(include_str!("input/3"));
assert_eq!(116491, part1(&fabric));
assert_eq!(707, part2(&fabric));
}