Rucksack Reorganization
In Day 3 we learn that there is a method to the madness of the elves organization of their rucksacks. The rucksacks have 2 compartments and we are gauranteed that the two portions are equal (halves).
Part 1
Our puzzle input is 300 lines of characters where each line represents and rucksack that must be inspected.
As is commonplace now, I created the input file and read that data in.
fn main() {
let input: &str = include_str!("./day3_input.txt");
let lines = input.split('\n');
/* ... */
}
I then decided to ge the low hanging fruit first by writing the method that will get the points for a given character.
fn points_from_char(c: char) -> i32 {
let c_point = c as i8;
if c.is_lowercase() {
return (c_point - 96) as i32;
}
return (c_point - 38) as i32;
}
Now I needed a method to test that any character from the first string is present inside the 2nd half of the string.
Looking back, I could/should refactor this, which will be a different post since I am so far behind.
fn get_duplicate_char(test_char: &char, string_half: &str) -> i32 {
for c in string_half.char_indices() {
if c.1.eq(test_char) {
return points_from_char(c.1);
}
}
return 0;
}
Finally, I can start the main method.
I created a total varible to keep the aggregated total of points.
I then iterated over each line, splitting it in half, and then calling my get_duplicate_char
method for each character in the first half.
Then I printed the grand total.
fn main() {
let input = include_str!("./day3.input.txt");
let lines = input.split('\n');
let mut total = 0;
for line in lines {
let count = line.chars().count();
let first_half = &line[..count/2].chars().into_iter();
let last_half = &line[count/2 .. count];
for c in line[..count/2].chars() {
let dup_points = get_duplicate_char(&c, last_half);
if dup_points > 0 {
total += dup_points;
println!("Dup Points: {:?} Char: {:?}, Char as int {:?}", dup_points, c, c as i8);
break;
}
}
}
println!("TOTAL: {:?}", total);
}
Part 2
For part 2 we find that the elves are in groups of 3 and they need to keep the rucksacks for their group. This can be indicated by the common character that appears in all three rucksacks.
We get to reuse the points_from_char
method from part 1.
fn points_from_char(c: char) -> i32 {
let c_point = c as i8;
if c.is_lowercase() {
return (c_point - 96) as i32;
}
return (c_point - 38) as i32;
}
Now we need to find the common character across the different lines. I started with the method that evaluates the strings.
fn find_common_char(c1: &str, c2: &str, c3: &str) -> i32 {
for c in c1.chars() {
if c2.contains(c) && c3.contains(c) {
return points_from_char(c);
}
}
return 0;
}
I next used the peekable()
method to get 3 lines at a time and afford a bit of protection from index-out-of-bounds errors.
Final Solution
Here is the whole file after I was done:
fn main() {
let input = include_str!("./day3.input.txt");
let lines= input.split('\n');
let mut total = 0;
let mut x = lines.peekable();
while x.peek().is_some() {
let grp: Vec<&str> = x.by_ref().take(3).collect();
if grp.len() < 3 {
println!("{:?}", total);
return;
}
total += find_common_char(grp[0], grp[1], grp[2]);
}
}
fn find_common_char(c1: &str, c2: &str, c3: &str) -> i32 {
for c in c1.chars() {
if c2.contains(c) && c3.contains(c) {
return points_from_char(c);
}
}
return 0;
}
fn points_from_char(c: char) -> i32 {
let c_point = c as i8;
if c.is_lowercase() {
return (c_point - 96) as i32;
}
return (c_point - 38) as i32;
}