Compare commits

..

2 Commits

Author SHA1 Message Date
71db768227 Day 12 2025-12-13 15:51:59 +00:00
26d64ba4c9 Day 11 - Cleanup 2025-12-12 00:23:51 +00:00
7 changed files with 1735 additions and 338 deletions

View File

@@ -47,6 +47,9 @@ path = "src/day10/main.rs"
name = "day11"
path = "src/day11/main.rs"
[[bin]]
name = "day12"
path = "src/day12/main.rs"
[dependencies]
anyhow = "1.0.100"

22
a Normal file
View File

@@ -0,0 +1,22 @@
Found Valid ans 0
Could not Find valid answer 1
Could not Find valid answer 2
sol1: 1

View File

@@ -1,11 +1,10 @@
use anyhow::{Ok, Result};
use core::panic;
use rand::seq::{IteratorRandom, SliceRandom};
use rand::seq::SliceRandom;
use std::{
collections::{HashMap, HashSet, VecDeque},
fmt::Debug,
fs,
io::{self, prelude::*},
ops::RangeInclusive,
u64, vec,
};
@@ -292,7 +291,6 @@ impl Simplyfy for Vec<EqPart> {
trait EqSystem {
fn cleanup(&mut self) -> Option<u64>;
fn cleanup_quiet(&mut self, allow_vars: bool) -> Option<u64>;
fn apply(&mut self, var: u64, replc: Vec<EqPart>) -> &mut Self;
fn apply_num(&mut self, var: u64, replc: i64) -> &mut Self;
// Return true if success
fn find_1_coe_on_other_side_and_swap(&mut self, k: EqPart) -> bool;
@@ -304,10 +302,12 @@ impl EqSystem for HashMap<EqPart, Vec<EqPart>> {
let mut new_values = 0;
let mut to_delete = Vec::new();
for (k, v) in self.iter() {
println!("{:?} = {:?}", k, v);
let idx = match k {
EqPart::Var(idx, _) => idx,
_ => continue,
_ => {
println!("{:?} = {:?}", k, v);
continue;
}
};
if v.len() == 1 {
if let EqPart::Num(v) = v[0] {
@@ -315,18 +315,19 @@ impl EqSystem for HashMap<EqPart, Vec<EqPart>> {
println!("\t Invalid state {}! applying", idx);
return None;
}
println!("\t Found part sol for {}! applying", idx);
to_delete.push(*k);
new_values += v as u64;
}
} else if v.len() == 0 {
println!("\t Found part sol for {} it's 0!", idx);
to_delete.push(*k);
}
}
print!("Found: ");
for i in to_delete {
self.remove(&i);
let r = self.remove(&i);
print!("{:?} {:?} ", i, r.unwrap());
}
print!("\n");
return Some(new_values);
}
@@ -334,7 +335,7 @@ impl EqSystem for HashMap<EqPart, Vec<EqPart>> {
let mut new_values = 0;
let mut to_delete = Vec::new();
for (k, v) in self.iter() {
let idx = match k {
let _ = match k {
EqPart::Var(idx, _) => idx,
EqPart::Num(n) => {
if allow_vars {
@@ -368,13 +369,6 @@ impl EqSystem for HashMap<EqPart, Vec<EqPart>> {
return Some(new_values);
}
fn apply(&mut self, var: u64, replc: Vec<EqPart>) -> &mut Self {
for v in self.values_mut() {
v.smart_insert(EqPart::Var(var, 1), replc.clone());
}
self
}
fn apply_num(&mut self, var: u64, replc: i64) -> &mut Self {
for v in self.values_mut() {
if replc == 0 {
@@ -517,34 +511,6 @@ impl EqSystem for HashMap<EqPart, Vec<EqPart>> {
}
}
fn get_presses_for_m(target: &Vec<u64>, buttons: &Vec<Vec<u64>>, i: usize) -> Option<u64> {
if i >= buttons.len() {
return None;
}
let button: &Vec<u64> = buttons[i].as_ref();
let max_can_add = button
.iter()
.fold(u64::MAX, |m, i| m.min(target[*i as usize]));
if max_can_add == 0 {
return get_presses_for_m(target, &buttons, i + 1);
}
for to_remove in (0..=max_can_add).rev() {
let mut n_target = target.clone();
for i in button.iter() {
n_target[*i as usize] -= to_remove;
}
// println!("max {:?}: {} - {:?}", button, to_remove, n_target);
if n_target.iter().all(|a| *a == 0) {
return Some(to_remove);
}
if let Some(v) = get_presses_for_m(&n_target, &buttons, i + 1) {
return Some(to_remove + v);
}
}
return None;
}
fn main() -> Result<()> {
let text = fs::read_to_string("src/day10/act.txt")?;
@@ -698,222 +664,216 @@ fn main() -> Result<()> {
}
}
// if try_later.len() >= 1 {
// fn try_later_mult(
// hash_t: &mut HashMap<EqPart, Vec<EqPart>>,
// machine: &Machine,
// try_later: Vec<usize>,
// ) -> (u64, Vec<usize>) {
// let mut sol2 = hash_t.cleanup().unwrap();
if try_later.len() >= 1 {
fn try_later_mult(
hash_t: &mut HashMap<EqPart, Vec<EqPart>>,
machine: &Machine,
try_later: Vec<usize>,
) -> (u64, Vec<usize>) {
let mut sol2 = hash_t.cleanup().unwrap();
// println!("Something failed to get need to try later");
// for (k, v) in hash_t.iter() {
// println!("{:?} = {:?}", k, v)
// }
println!("Something failed to get need to try later");
for (k, v) in hash_t.iter() {
println!("{:?} = {:?}", k, v)
}
// let mut try_later_2 = Vec::new();
// 'try_later: for i in try_later {
// // Get the one based on the index
// let cur_options = hash_t.remove(&EqPart::Index(i)).unwrap();
// // Insert the actual value one
// let k = EqPart::Num(machine.req[i] as i64);
// hash_t.insert(k, cur_options);
let mut try_later_2 = Vec::new();
'try_later: for i in try_later {
// Get the one based on the index
let cur_options = hash_t.remove(&EqPart::Index(i)).unwrap();
// Insert the actual value one
let k = EqPart::Num(machine.req[i] as i64);
hash_t.insert(k, cur_options);
// if !hash_t.find_1_coe_on_other_side_and_swap(k) {
// // removed value based one not to screw with next step
// let cur_options = hash_t.remove(&k).unwrap();
// hash_t.insert(EqPart::Index(i), cur_options.clone());
if !hash_t.find_1_coe_on_other_side_and_swap(k) {
// removed value based one not to screw with next step
let cur_options = hash_t.remove(&k).unwrap();
hash_t.insert(EqPart::Index(i), cur_options.clone());
// // Ok maybe we can swap some things around
// let vars: Vec<u64> = cur_options
// .iter()
// .filter(|a| a.is_var())
// .map(|a| {
// let (idx, _) = a.to_var();
// idx
// })
// .collect();
// Ok maybe we can swap some things around
let vars: Vec<u64> = cur_options
.iter()
.filter(|a| a.is_var())
.map(|a| {
let (idx, _) = a.to_var();
idx
})
.collect();
// let mut possible_swap = Vec::new();
let mut possible_swap = Vec::new();
// for (k, v) in hash_t.clone() {
// if k.is_var() {
// let mut count_exact = 0;
// for i in v.iter() {
// if i.is_var() {
// let (_id, c) = i.to_var();
// if c.abs() == 1 {
// count_exact += 1;
// }
// }
// }
// println!(
// "Trying to find swap on {:?} = {:?} =====> {} {}({:?})",
// k,
// v,
// count_exact,
// vars.len(),
// vars
// );
// if count_exact >= 1 {
// possible_swap.push(k.clone());
// }
// }
// }
for (k, v) in hash_t.clone() {
if k.is_var() {
let mut count_exact = 0;
for i in v.iter() {
if i.is_var() {
let (_id, c) = i.to_var();
if c.abs() == 1 {
count_exact += 1;
}
}
}
println!(
"Trying to find swap on {:?} = {:?} =====> {} {}({:?})",
k,
v,
count_exact,
vars.len(),
vars
);
if count_exact >= 1 {
possible_swap.push(k.clone());
}
}
}
// if possible_swap.len() >= 1 {
// println!("We can swap! picking randomly from {:?}", possible_swap);
if possible_swap.len() >= 1 {
println!("We can swap! picking randomly from {:?}", possible_swap);
// let k = *possible_swap.choose(&mut rand::thread_rng()).unwrap();
let k = *possible_swap.choose(&mut rand::thread_rng()).unwrap();
// if !hash_t.find_1_coe_on_other_side_and_swap(k) {
// panic!("unrechable");
// }
if !hash_t.find_1_coe_on_other_side_and_swap(k) {
panic!("unrechable");
}
// sol2 += hash_t.cleanup().unwrap();
sol2 += hash_t.cleanup().unwrap();
// println!("Swapped!");
// // Get the one based on the index
// let cur_options = hash_t.remove(&EqPart::Index(i)).unwrap();
// // Insert the actual value one
// let k = EqPart::Num(machine.req[i] as i64);
// hash_t.insert(k, cur_options.clone());
println!("Swapped!");
// Get the one based on the index
let cur_options = hash_t.remove(&EqPart::Index(i)).unwrap();
// Insert the actual value one
let k = EqPart::Num(machine.req[i] as i64);
hash_t.insert(k, cur_options.clone());
// if !hash_t.find_1_coe_on_other_side_and_swap(k) {
// println!(
// "Failed trying later {:?} try_ing one more time even with swap",
// cur_options
// );
// let cur_options = hash_t.remove(&k).unwrap();
// hash_t.insert(EqPart::Index(i), cur_options);
// // In this case we don't restore to the index based one
// try_later_2.push(i);
// continue 'try_later;
// }
if !hash_t.find_1_coe_on_other_side_and_swap(k) {
println!(
"Failed trying later {:?} try_ing one more time even with swap",
cur_options
);
let cur_options = hash_t.remove(&k).unwrap();
hash_t.insert(EqPart::Index(i), cur_options);
// In this case we don't restore to the index based one
try_later_2.push(i);
continue 'try_later;
}
// continue 'try_later;
// }
// println!(
// "Failed trying later {:?} try_ing one more time",
// cur_options
// );
// try_later_2.push(i);
// continue;
// }
// }
continue 'try_later;
}
println!(
"Failed trying later {:?} try_ing one more time",
cur_options
);
try_later_2.push(i);
continue;
}
}
// let mut try_later_3 = Vec::new();
// if try_later_2.len() > 0 {
// println!("!!!Still some failirues last try!!!");
// sol2 += hash_t.cleanup().unwrap();
// for i in try_later_2 {
// let k_org = EqPart::Index(i);
// println!("Trying to find divisors for {:?}", k_org);
// if !k_org.is_var() {
// let mut ops = hash_t.remove(&k_org).unwrap();
// let org = ops.clone();
// let num = ops.pop_num().unwrap_or(0);
// let k = machine.req[i] as i64 + -num;
// if ops.len() == 0 && k == 0 {
// println!("Found inline sol for {}", i);
// continue;
// }
// let div = if ops.len() > 1 {
// //
// // Check to see if everyone is div by min
// //
// let vars: Vec<Var> = ops
// .clone()
// .into_iter()
// .filter(|a| a.is_var())
// .map(|a| a.to_var())
// .collect();
let mut try_later_3 = Vec::new();
if try_later_2.len() > 0 {
println!("!!!Still some failirues last try!!!");
sol2 += hash_t.cleanup().unwrap();
for i in try_later_2 {
let k_org = EqPart::Index(i);
println!("Trying to find divisors for {:?}", k_org);
if !k_org.is_var() {
let mut ops = hash_t.remove(&k_org).unwrap();
let org = ops.clone();
let num = ops.pop_num().unwrap_or(0);
let k = machine.req[i] as i64 + -num;
if ops.len() == 0 && k == 0 {
println!("Found inline sol for {}", i);
continue;
}
let div = if ops.len() > 1 {
//
// Check to see if everyone is div by min
//
let vars: Vec<Var> = ops
.clone()
.into_iter()
.filter(|a| a.is_var())
.map(|a| a.to_var())
.collect();
// let min = vars.iter().fold(i64::MAX, |m, (_, c)| m.min(c.abs()));
let min = vars.iter().fold(i64::MAX, |m, (_, c)| m.min(c.abs()));
// if !(k.abs() % min == 0
// && vars.iter().all(|(_, v)| v.abs() % min == 0))
// {
// println!(
// "--Could not find eql divisor for {} = {:?}",
// machine.req[i] as i64, org
// );
// hash_t.insert(EqPart::Index(i), org);
// try_later_3.push(i);
// continue;
// }
if !(k.abs() % min == 0
&& vars.iter().all(|(_, v)| v.abs() % min == 0))
{
println!(
"--Could not find eql divisor for {} = {:?}",
machine.req[i] as i64, org
);
hash_t.insert(EqPart::Index(i), org);
try_later_3.push(i);
continue;
}
// min
// } else {
// let (_id, v) = ops[0].to_var();
// if k.abs() % v.abs() != 0 {
// println!(
// "Could not find eql divisor for {} = {:?}",
// machine.req[i], org
// );
// hash_t.insert(EqPart::Index(i), org);
// try_later_3.push(i);
// continue;
// }
// v.abs()
// };
min
} else {
let (_id, v) = ops[0].to_var();
if k.abs() % v.abs() != 0 {
println!(
"Could not find eql divisor for {} = {:?}",
machine.req[i], org
);
hash_t.insert(EqPart::Index(i), org);
try_later_3.push(i);
continue;
}
v.abs()
};
// println!(
// "Found divisor for {:?} => {} = {:?} at {}",
// k_org, machine.req[i], org, div,
// );
println!(
"Found divisor for {:?} => {} = {:?} at {}",
k_org, machine.req[i], org, div,
);
// let k = k / div;
// let ops: Vec<EqPart> = ops
// .into_iter()
// .map(|mut m| {
// m.i_div(div);
// m
// })
// .collect();
let k = k / div;
let ops: Vec<EqPart> = ops
.into_iter()
.map(|mut m| {
m.i_div(div);
m
})
.collect();
// let k = EqPart::Num(k);
// hash_t.insert(k, ops);
// if !hash_t.find_1_coe_on_other_side_and_swap(k) {
// panic!(
// "this should be impossilbe we kinda of grarantee that there will always a div"
// );
// }
// }
// }
let k = EqPart::Num(k);
hash_t.insert(k, ops);
if !hash_t.find_1_coe_on_other_side_and_swap(k) {
panic!(
"this should be impossilbe we kinda of grarantee that there will always a div"
);
}
}
}
// sol2 += hash_t.cleanup().unwrap();
// }
// return (sol2, try_later_3);
// }
sol2 += hash_t.cleanup().unwrap();
}
return (sol2, try_later_3);
}
// let mut loop_c = 1;
// loop {
// let (t_sol2, t2) = try_later_mult(&mut hash_t, &machine, try_later);
// sol2 += t_sol2;
// if t2.len() == 0 {
// break;
// }
// if loop_c % 1000 == 0 {
// println!("Could not simply any fruther");
// for i in t2 {
// let mut to_r = hash_t.remove(&EqPart::Index(i)).unwrap();
// let num = to_r.pop_num().unwrap_or(0);
// hash_t.insert(EqPart::Num(machine.req[i] as i64 - num), to_r);
// }
// sol2 += hash_t.cleanup().unwrap();
// break;
// }
// try_later = t2;
// loop_c += 1;
// }
// }
for i in try_later {
let mut loop_c = 1;
loop {
let (t_sol2, t2) = try_later_mult(&mut hash_t, &machine, try_later);
sol2 += t_sol2;
if t2.len() == 0 {
break;
}
if loop_c % 50 == 0 {
println!("Could not simply any fruther");
for i in t2 {
let mut to_r = hash_t.remove(&EqPart::Index(i)).unwrap();
let num = to_r.pop_num().unwrap_or(0);
hash_t.insert(EqPart::Num(machine.req[i] as i64 - num), to_r);
}
sol2 += hash_t.cleanup().unwrap();
break;
}
try_later = t2;
loop_c += 1;
}
}
sol2 += hash_t.cleanup().unwrap();
@@ -929,90 +889,6 @@ fn main() -> Result<()> {
println!("colected vars {:?}", vars);
// loop {
// let mut cleanup: Vec<u64> = Vec::new();
// 'vars: for v in vars.iter() {
// let mut neg_one_count = 0;
// 'part: for part in hash_t.values() {
// let n = match part
// .iter()
// .find(|a| if let EqPart::Num(_) = *a { true } else { false })
// {
// Some(EqPart::Num(v)) => v,
// None => &0,
// a => panic!("not sure what to do here {:?} -> {:?}", part, a),
// };
// let mut other_vars = 0;
// let mut our_found = false;
// for item in part.iter() {
// if let EqPart::Var(idx, v_value) = item {
// if *idx != *v {
// other_vars += 1;
// } else {
// our_found = true;
// // If the value is negative one it does not change the number
// // of clicks so we can remove if all other parts are also right
// if *v_value == -1 {
// if neg_one_count == 0 {
// neg_one_count += 1;
// continue 'part;
// }
// }
// // If the number is positive and our value
// // is negative we can not skip it because this means
// // that we might be able to lower the num
// if *n > 0 && *v_value < 0 {
// println!(
// "cannot clean up {} because number is positive and we are negative",
// (v + 97) as u8 as char
// );
// continue 'vars;
// }
// // If the number is negative and our value
// // is positive we can not skip it because this means
// // that we MUST be able to raise the num
// if *n < 0 && *v_value > 0 {
// println!(
// "cannot clean up {} because number is negative and we are positive",
// (v + 97) as u8 as char
// );
// continue 'vars;
// }
// }
// }
// }
// // If our is not found then we can just skip this part
// if !our_found {
// continue 'part;
// }
// // If one of the other checks did not catch here
// // but we have other vars we cannot really clean it up
// if other_vars > 0 {
// println!(
// "cannot clean up {} because there are other var",
// (v + 97) as u8 as char
// );
// continue 'vars;
// }
// }
// // If were able pass through all the parts that
// // means we are able to clean up
// println!("Clearning up {}", (v + 97) as u8 as char);
// cleanup.push(*v);
// }
// if cleanup.len() == 0 {
// break;
// }
// for var in cleanup {
// for v in hash_t.values_mut() {
// v.smart_insert(EqPart::Var(var, 1), Vec::new());
// }
// vars.remove(&var);
// }
// sol2 += hash_t.cleanup().unwrap();
// }
if vars.len() == 0 {
println!("finsihed machine with {}", sol2);
sol2_main += sol2;
@@ -1031,24 +907,12 @@ fn main() -> Result<()> {
if var.is_none() {
continue 'part;
}
let (idx, var) = var.unwrap();
let (_, var) = var.unwrap();
// n is positive and we are negative then
// we can only really go up to the n
if n > 0 && var < 0 && part.len() == 2 {
max = max.min(n / var.abs());
}
// n is positive and we are negative and we are the
// only things here
// then we have a min
// println!(
// "h: {} {} {} {}",
// (idx + 97) as u8 as char,
// n,
// var,
// part.len()
// );
if n < 0 && var > 0 && part.len() == 2 {
min = min.max(((n.abs() as f64) / var as f64).ceil() as i64);
}
@@ -1130,8 +994,6 @@ fn main() -> Result<()> {
println!("finsihed machine with {}", sol2);
sol2_main += sol2;
// panic!("todo");
}
println!("Sol2: {}", sol2_main);

View File

@@ -120,6 +120,5 @@ fn sol2() -> Result<()> {
fn main() -> Result<()> {
sol1()?;
sol2()?;
Ok(())
sol2()
}

1030
src/day12/act.txt Normal file

File diff suppressed because it is too large Load Diff

448
src/day12/main.rs Normal file
View File

@@ -0,0 +1,448 @@
use anyhow::Result;
use std::{
collections::{HashMap, HashSet},
fmt::Debug,
fs,
};
#[derive(Debug)]
struct Area {
width: u64,
height: u64,
reqs: Vec<usize>,
hash: HashMap<usize, usize>,
}
impl Into<Area> for &str {
fn into(self) -> Area {
let mut niter = self.split(":");
let mut positer = niter.next().unwrap().split("x");
let width: u64 = positer.next().unwrap().parse().unwrap();
let height: u64 = positer.next().unwrap().parse().unwrap();
let (reqs, hash) = niter.next().unwrap().trim().split(" ").enumerate().fold(
(Vec::new(), HashMap::new()),
|(mut v, mut h), (i, to_num)| {
h.insert(i, to_num.parse().unwrap());
for _ in 0..to_num.parse().unwrap() {
v.push(i);
}
(v, h)
},
);
Area {
width,
height,
reqs,
hash,
}
}
}
fn try_all_vars(
area: &Area,
shapes: &HashMap<usize, Vec<StrictShape>>,
list_of_reqs: Vec<usize>,
cur_shape: StrictShape,
) -> bool {
if list_of_reqs.len() == 0 {
return true;
}
let mut reqs = list_of_reqs.clone().into_iter();
let cur_idx = reqs.next().unwrap();
let reqs: Vec<usize> = reqs.collect();
// TODO check if the current shape fits in the box
// We don't have to loop because if we can not fit the first
// we will never be able to fit any way
for s in shapes.get(&cur_idx).unwrap().iter() {
let possibles = cur_shape.try_to_attach_all(area, &s);
for p in possibles {
if try_all_vars(area, shapes, reqs.clone(), p) {
return true;
}
}
}
false
}
impl Area {
fn valid(&self, shapes: &HashMap<usize, Vec<StrictShape>>) -> bool {
let mut reqs = self.reqs.clone().into_iter();
let cur_idx = reqs.next().unwrap();
let reqs: Vec<usize> = reqs.collect();
// TODO check if the current shape fits in the box
// We don't have to loop because if we can not fit the first
// we will never be able to fit any way
// also we only need to test one here and this one "sets" the orientaion of the world
if try_all_vars(
self,
shapes,
reqs.clone(),
shapes.get(&cur_idx).unwrap().iter().next().unwrap().clone(),
) {
return true;
}
false
}
}
#[derive(Eq, PartialEq, Clone, Hash)]
struct Shape {
lines: Vec<Vec<bool>>,
}
#[derive(Eq, PartialEq, Clone, Hash)]
// It can not rotate or flip but it's faster for comparions
struct StrictShape {
lines: Vec<u64>,
width: i64,
}
const ALL_ONES: u64 = 0b1111111111111111111111111111111111111111111111111111111111111111;
impl StrictShape {
fn get_attach_poins(&self) -> Vec<(i64, i64)> {
let mut attach_points = Vec::new();
for (y, line) in self.lines.iter().enumerate() {
let mut line = *line ^ ALL_ONES;
while line != 0 {
let i = line.trailing_zeros();
line ^= 1 << i;
if 64 - i < self.width as u32 {
attach_points.push((y as i64, 64 - i as i64));
}
}
}
attach_points
}
fn get_size(&self) -> (i64, i64) {
(self.lines.len() as i64, self.width)
}
fn try_to_attach(&self, to_attach: &StrictShape, y: i64, x: i64) -> Option<StrictShape> {
// Calculate the matrix
let (s_h, s_w) = self.get_size();
let (a_h, a_w) = to_attach.get_size();
let height = if y < 0 {
(y.abs() + s_h).max(a_h + y)
} else {
s_h.max(a_h + y)
};
let width = if x < 0 {
(x.abs() + s_w).max(a_w + x)
} else {
s_w.max(a_w + x)
};
let mut lines = Vec::new();
// i_<> is the offset into the to_attach shape it can go out of bounds on the positive side
// o_<> is the offset into the self shape it can go out of bound both sides
for i_y in 0..height {
let self_y = i_y + y.min(0);
let to_y = i_y - y.max(0);
if (self_y < 0 || self_y >= s_h) && (to_y < 0 || to_y >= a_h) {
lines.push(0);
} else if self_y < 0 || self_y >= s_h {
lines.push(to_attach.lines[to_y as usize] >> x.max(0));
} else if to_y < 0 || to_y >= a_h {
lines.push(self.lines[self_y as usize] >> x.min(0).abs());
} else {
let a_line = to_attach.lines[to_y as usize] >> x.max(0);
let self_line = self.lines[self_y as usize] >> x.min(0).abs();
// There is an itersection
if a_line & self_line > 0 {
return None;
}
lines.push(a_line | self_line);
}
}
Some(StrictShape { lines, width })
}
fn try_to_attach_all(&self, area: &Area, to_attach: &StrictShape) -> Vec<StrictShape> {
// println!(
// "Trying to attach {:?} \n{:?}\n with \n{:?}\n",
// area, self, to_attach
// );
let (s_y, s_x) = self.get_size();
let (a_y, a_x) = to_attach.get_size();
let min_x = (-(a_x as i64)).max(-(area.width as i64 - s_x));
let max_x = (s_x + a_x).min(area.width as i64 - a_x as i64);
let min_y = (-(a_y as i64)).max(-(area.height as i64 - s_y));
let max_y = (s_y + a_y).min(area.height as i64 - a_y as i64);
if min_x > max_x || min_y > max_y {
//println!("Could never attach");
return Vec::new();
}
// println!("found bounds {} {} -> {} {}", min_y, min_x, max_y, max_x);
// Try edges
let mut new_possible_shapes = Vec::new();
for y in min_y..0 {
for x in min_x..=max_x {
if let Some(merged) = self.try_to_attach(to_attach, y, x) {
// println!("Found shape {y} {x} {merged:?} ");
new_possible_shapes.push(merged);
} else {
// println!("Could not find shape {y} {x}");
}
}
}
for y in s_y..=max_y {
for x in min_x..max_x {
if let Some(merged) = self.try_to_attach(to_attach, y, x) {
// println!("Found shape {y} {x} {merged:?} ");
new_possible_shapes.push(merged);
} else {
// println!("Could not find shape {y} {x}");
}
}
}
for y in 0..=(s_y).min(max_y) {
for x in min_x..0 {
if let Some(merged) = self.try_to_attach(to_attach, y, x) {
// println!("Found shape {y} {x} {merged:?} ");
new_possible_shapes.push(merged);
} else {
// println!("Could not find shape {y} {x}");
}
}
for x in s_x..max_x {
if let Some(merged) = self.try_to_attach(to_attach, y, x) {
// println!("Found shape {y} {x} {merged:?} ");
new_possible_shapes.push(merged);
} else {
// println!("Could not find shape {y} {x}");
}
}
}
let r_y = min_y..=max_y;
let r_x = min_x..=max_x;
for (p_y, p_x) in self.get_attach_poins() {
// println!("in {p_y} {p_x}");
if r_y.contains(&p_y) && r_x.contains(&p_x) {
if let Some(merged) = self.try_to_attach(to_attach, p_y, p_x) {
// println!("Found shape {p_y} {p_x}{merged:?}");
new_possible_shapes.push(merged);
} else {
// println!("Could not find shape {p_y} {p_x}");
}
}
}
new_possible_shapes.sort_by(|a, b| {
(a.width * a.lines.len() as i64).cmp(&(b.width * b.lines.len() as i64))
});
// if new_possible_shapes > 0 {
// println!("Best shape {:?}", new_possible_shapes[0]);
// }
new_possible_shapes
}
}
impl Debug for StrictShape {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "\n")?;
for line in self.lines.iter() {
let line = format!("{line:064b}");
let line = line[0..(self.width as usize)]
.to_string()
.replace("0", ".")
.replace("1", "#");
write!(f, "{}\n", line)?;
}
write!(f, "")
}
}
impl Shape {
fn new() -> Shape {
Shape { lines: Vec::new() }
}
fn add_line(&mut self, text: &str) {
let mut line = Vec::new();
for c in text.chars() {
match c {
'#' => line.push(true),
'.' => line.push(false),
c => panic!("Not sure what to do {}", c),
}
}
self.lines.push(line);
}
fn rotate_right(&self) -> Self {
let mut lines = Vec::new();
let height = self.lines.len();
assert!(height > 0, "Something is wrong {:?}", self);
let width = self.lines[0].len();
for x in (0..width).rev() {
let mut new_line = Vec::new();
for y in 0..height {
new_line.push(self.lines[y][x]);
}
lines.push(new_line);
}
Self { lines }
}
fn flip(&self) -> Self {
let mut lines = Vec::new();
let height = self.lines.len();
let width = self.lines[0].len();
for y in (0..height).rev() {
let mut new_line = Vec::new();
for x in (0..width).rev() {
new_line.push(self.lines[y][x]);
}
lines.push(new_line);
}
Self { lines }
}
fn to_strict(self) -> StrictShape {
let mut lines = Vec::new();
for line in self.lines.iter() {
let mut n_line = 0;
for (i, c) in line.iter().enumerate() {
n_line = n_line | (*c as u64) << 63 - i;
}
lines.push(n_line);
}
StrictShape {
lines,
width: self.lines[0].len() as i64,
}
}
fn get_varients(self) -> Vec<StrictShape> {
let mut shapes_list = HashSet::new();
let shape1 = self.rotate_right();
let shape2 = shape1.rotate_right();
let shape3 = shape2.rotate_right();
shapes_list.insert(shape1.to_strict());
shapes_list.insert(shape2.to_strict());
shapes_list.insert(shape3.to_strict());
let fliped = self.flip();
let shape1 = fliped.rotate_right();
let shape2 = shape1.rotate_right();
let shape3 = shape2.rotate_right();
shapes_list.insert(self.to_strict());
shapes_list.insert(fliped.to_strict());
shapes_list.insert(shape1.to_strict());
shapes_list.insert(shape2.to_strict());
shapes_list.insert(shape3.to_strict());
shapes_list.into_iter().collect()
}
}
impl Debug for Shape {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "\n")?;
for line in self.lines.iter() {
for c in line {
write!(f, "{}", if *c { "#" } else { "." })?;
}
write!(f, "\n")?;
}
write!(f, "")
}
}
fn main() -> Result<()> {
let text = fs::read_to_string("src/day12/act.txt")?;
let mut areas: Vec<Area> = Vec::new();
let mut shapes = HashMap::new();
let mut cur_shape = Shape::new();
for line in text.split("\n") {
if line == "" {
continue;
} else if line.contains("x") {
if cur_shape.lines.len() != 0 {
let vars = cur_shape.get_varients();
println!("Shape: {:?} {}", vars[0], vars.len());
shapes.insert(shapes.values().len(), vars);
cur_shape = Shape::new();
}
areas.push(line.into());
} else if line.contains(":") {
if cur_shape.lines.len() == 0 {
continue;
}
let vars = cur_shape.get_varients();
println!("Shape: {:?} {}", vars[0], vars.len());
shapes.insert(shapes.values().len(), vars);
cur_shape = Shape::new();
} else {
cur_shape.add_line(line);
}
}
let mut valid = 0;
for a in areas.iter() {
let mut count_of_1 = *a.hash.get(&1).unwrap();
let by_6 = count_of_1 / 6;
let left_over = count_of_1 % 6;
let mut area = a.width / 3 * a.height / 3;
if (a.width / 12 * a.height / 3) as usize > by_6
|| (a.width / 3 * a.height / 12) as usize > by_6
{
count_of_1 = left_over;
area -= (by_6 * 4) as u64;
}
let mut sum: u64 = 0;
for (i, v) in a.hash.iter() {
if *i == 1 {
sum += count_of_1 as u64;
} else {
sum += *v as u64;
}
}
if area >= sum {
valid += 1;
}
}
println!("sol1: {}", valid);
panic!("mad");
// We know that 3 only nicly packs with itself
let mut valid = 0;
for (i, a) in areas.iter().enumerate() {
if a.valid(&shapes) {
println!("Found Valid ans {i}\n\n\n\n\n\n");
valid += 1;
} else {
println!("Could not Find valid answer {i}\n\n\n\n\n\n");
}
}
println!("sol1: {}", valid);
Ok(())
}

33
src/day12/test.txt Normal file
View File

@@ -0,0 +1,33 @@
0:
###
##.
##.
1:
###
##.
.##
2:
.##
###
##.
3:
##.
###
##.
4:
###
#..
###
5:
###
.#.
###
4x4: 0 0 0 0 2 0
12x5: 1 0 1 0 2 2
12x5: 1 0 1 0 3 2