Completed day 6 part 1

This commit is contained in:
Tyler Hallada 2019-01-01 20:59:58 -05:00
parent 41eaeb8192
commit bd6c348581
3 changed files with 327 additions and 170 deletions

50
inputs/6.txt Normal file
View File

@ -0,0 +1,50 @@
84, 212
168, 116
195, 339
110, 86
303, 244
228, 338
151, 295
115, 49
161, 98
60, 197
40, 55
55, 322
148, 82
86, 349
145, 295
243, 281
91, 343
280, 50
149, 129
174, 119
170, 44
296, 148
152, 160
115, 251
266, 281
269, 285
109, 242
136, 241
236, 249
338, 245
71, 101
254, 327
208, 231
289, 184
282, 158
352, 51
326, 230
88, 240
292, 342
352, 189
231, 141
280, 350
296, 185
226, 252
172, 235
137, 161
207, 90
101, 133
156, 234
241, 185

View File

@ -3,17 +3,26 @@ extern crate regex;
use std::error::Error; use std::error::Error;
use std::fs::File; use std::fs::File;
use std::io::{BufRead, BufReader}; use std::io::{BufRead, BufReader};
use std::{fmt, mem}; use std::fmt;
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
use regex::{Regex, Captures}; use regex::{Regex, Captures};
static ALPHABET: [char; 52] = [
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z',
];
const INPUT: &str = "inputs/6.txt"; const INPUT: &str = "inputs/6.txt";
#[derive(Debug, PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone, Eq, Hash)]
struct Coordinate { struct Coordinate {
x: u32, x: u32,
y: u32, y: u32,
letter: char,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -35,6 +44,44 @@ enum GridPoint {
}, },
} }
#[derive(Debug, PartialEq)]
struct Grid {
points: Vec<GridPoint>,
boundary_coord: Coordinate,
}
impl fmt::Display for Coordinate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.letter)
}
}
impl fmt::Display for Grid {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "\n-----")?;
for (index, point) in self.points.iter().enumerate() {
if index as u32 % (self.boundary_coord.x + 1) == 0 {
write!(f, "\n")?;
}
match point {
GridPoint::Unfilled { x: _, y: _ } => { write!(f, "-")?; },
GridPoint::Tied { x: _, y: _, closest_dist: _} => {
write!(f, ".")?;
},
GridPoint::Filled { x, y, closest_coord, closest_dist: _ } => {
if *x == closest_coord.x && *y == closest_coord.y {
write!(f, "#")?;
} else {
write!(f, "{}", closest_coord)?;
}
},
}
}
write!(f, "\n-----")?;
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
struct MalformedCoordinate { struct MalformedCoordinate {
details: String details: String
@ -58,6 +105,15 @@ impl Error for MalformedCoordinate {
} }
} }
pub fn solve_part1() -> Result<u32, Box<Error>> {
let coords = read_coordinates(INPUT)?;
let boundary_coord = get_boundary_coordinate(&coords);
let mut grid = create_grid(boundary_coord);
fill_grid(&mut grid, &coords).unwrap();
println!("{}", grid);
Ok(find_largest_coord_area(grid))
}
fn read_coordinates(filename: &str) -> Result<Vec<Coordinate>, Box<Error>> { fn read_coordinates(filename: &str) -> Result<Vec<Coordinate>, Box<Error>> {
let mut records: Vec<Coordinate> = Vec::new(); let mut records: Vec<Coordinate> = Vec::new();
lazy_static! { lazy_static! {
@ -65,12 +121,13 @@ fn read_coordinates(filename: &str) -> Result<Vec<Coordinate>, Box<Error>> {
r"(?P<x>\d+), (?P<y>\d+)").unwrap(); r"(?P<x>\d+), (?P<y>\d+)").unwrap();
} }
let file = File::open(filename)?; let file = File::open(filename)?;
for line in BufReader::new(file).lines() { for (index, line) in BufReader::new(file).lines().enumerate() {
match COORDINATE_REGEX.captures(&line?) { match COORDINATE_REGEX.captures(&line?) {
Some(captures) => { Some(captures) => {
records.push(Coordinate { records.push(Coordinate {
x: get_captured_field(&captures, "x")?.parse()?, x: get_captured_field(&captures, "x")?.parse()?,
y: get_captured_field(&captures, "y")?.parse()?, y: get_captured_field(&captures, "y")?.parse()?,
letter: ALPHABET[index],
}); });
}, },
None => return Err(Box::new(MalformedCoordinate { None => return Err(Box::new(MalformedCoordinate {
@ -90,8 +147,8 @@ fn get_captured_field(captures: &Captures, field: &str) -> Result<String, Box<Er
} }
} }
fn get_boundary_coordinate(coords: Vec<Coordinate>) -> Coordinate { fn get_boundary_coordinate(coords: &Vec<Coordinate>) -> Coordinate {
let mut boundary_coord = Coordinate { x: 0, y: 0 }; let mut boundary_coord = Coordinate { x: 0, y: 0, letter: '+' };
for coord in coords { for coord in coords {
if coord.x > boundary_coord.x { if coord.x > boundary_coord.x {
boundary_coord.x = coord.x; boundary_coord.x = coord.x;
@ -103,97 +160,109 @@ fn get_boundary_coordinate(coords: Vec<Coordinate>) -> Coordinate {
boundary_coord boundary_coord
} }
fn create_grid(boundary_coord: Coordinate) -> Vec<GridPoint> { fn create_grid(boundary_coord: Coordinate) -> Grid {
let mut grid = Vec::new(); let mut points = Vec::new();
for x in 0..boundary_coord.x + 1 { for y in 0..boundary_coord.y + 1 {
for y in 0..boundary_coord.y + 1 { for x in 0..boundary_coord.x + 1 {
grid.push(GridPoint::Unfilled { x, y }); points.push(GridPoint::Unfilled { x, y });
} }
} }
grid Grid { points, boundary_coord }
} }
fn fill_grid( fn fill_grid<'a>(
grid: &mut Vec<GridPoint>, grid: &'a mut Grid,
coords: Vec<Coordinate>, coords: &'a Vec<Coordinate>,
boundary_coord: Coordinate, ) -> Result<&'a mut Grid, Box<Error>> {
) -> Result<&mut Vec<GridPoint>, Box<Error>> {
for coord in coords { for coord in coords {
let start_index = (coord.x * (boundary_coord.y + 1)) + coord.y; let start_index = (coord.x * (grid.boundary_coord.y + 1)) + coord.y;
fill_grid_with_coordinate(grid, start_index, coord, boundary_coord, 0)?; fill_grid_with_coordinate(
grid,
start_index,
*coord,
)?;
} }
Ok(grid) Ok(grid)
} }
fn fill_grid_with_coordinate( fn fill_grid_with_coordinate(
grid: &mut Vec<GridPoint>, grid: &mut Grid,
index: u32, index: u32,
coord: Coordinate, coord: Coordinate,
boundary_coord: Coordinate, ) -> Result<&mut Grid, Box<Error>> {
iterations: u32, let mut visited_indices = HashSet::new();
) -> Result<&mut Vec<GridPoint>, Box<Error>> { for point in &mut grid.points {
if iterations == 10 { return Ok(grid); } visited_indices.insert(index);
println!("index: {}", index); match *point {
println!("grid: {:?}", grid); GridPoint::Unfilled { x, y } => {
let point = &mut grid.get_mut(index as usize).unwrap(); *point = GridPoint::Filled {
match point { x: x,
GridPoint::Unfilled { x, y } => { y: y,
grid[index as usize] = GridPoint::Filled {
x: *x,
y: *y,
closest_coord: coord,
closest_dist: manhattan_dist(coord.x, coord.y, *x, *y),
};
},
GridPoint::Tied { x, y, closest_dist } |
GridPoint::Filled { x, y, closest_coord: _, closest_dist } => {
let dist = manhattan_dist(coord.x, coord.y, *x, *y);
if dist < *closest_dist {
grid[index as usize] = GridPoint::Filled {
x: *x,
y: *y,
closest_coord: coord, closest_coord: coord,
closest_dist: dist, closest_dist: manhattan_dist(coord.x, coord.y, x, y),
}; };
} else if dist == *closest_dist { },
grid[index as usize] = GridPoint::Tied { GridPoint::Tied { x, y, closest_dist } => {
x: *x, let dist = manhattan_dist(coord.x, coord.y, x, y);
y: *y, if dist < closest_dist {
closest_dist: dist, *point = GridPoint::Filled {
}; x: x,
} y: y,
}, closest_coord: coord,
closest_dist: dist,
};
}
},
GridPoint::Filled { x, y, closest_coord, closest_dist } => {
let dist = manhattan_dist(coord.x, coord.y, x, y);
if dist < closest_dist {
*point = GridPoint::Filled {
x: x,
y: y,
closest_coord: coord,
closest_dist: dist,
};
} else if dist == closest_dist && closest_coord != coord {
*point = GridPoint::Tied {
x: x,
y: y,
closest_dist: dist,
};
}
},
}
} }
let row_index = index / (boundary_coord.y + 1);
let col_index = index % (boundary_coord.y + 1);
println!("row_index: {}", row_index);
println!("col_index: {}", col_index);
// South
if col_index < boundary_coord.y {
println!("south: {}", index + 1);
fill_grid_with_coordinate(grid, index + 1, coord, boundary_coord, iterations + 1)?;
}
// North
if col_index > 0 {
println!("north: {}", index - 1);
fill_grid_with_coordinate(grid, index - 1, coord, boundary_coord, iterations + 1)?;
}
// East
if row_index < boundary_coord.x {
println!("east: {}", index + (boundary_coord.y + 1));
fill_grid_with_coordinate(grid, index + (boundary_coord.y + 1), coord, boundary_coord, iterations + 1)?;
}
// West
if row_index > 0 {
println!("west: {}", index - (boundary_coord.y + 1));
fill_grid_with_coordinate(grid, index - (boundary_coord.y + 1), coord, boundary_coord, iterations + 1)?;
}
println!("returning grid");
Ok(grid) Ok(grid)
} }
fn manhattan_dist(x1: u32, y1: u32, x2: u32, y2: u32) -> u32 { fn manhattan_dist(x1: u32, y1: u32, x2: u32, y2: u32) -> u32 {
((x2 as i32 - x1 as i32) + (y2 as i32 - y1 as i32)).abs() as u32 ((x2 as i32 - x1 as i32).abs() + (y2 as i32 - y1 as i32).abs()) as u32
}
fn find_largest_coord_area(
grid: Grid,
) -> u32 {
let mut point_count = HashMap::new();
let mut infinite_coords = HashSet::new();
for point in grid.points.iter() {
match point {
GridPoint::Filled { x, y, closest_coord: coord, closest_dist: _ } => {
if *x == 0 || *x == grid.boundary_coord.x ||
*y == 0 || *y == grid.boundary_coord.y {
point_count.remove(coord);
infinite_coords.insert(coord);
continue;
}
if !infinite_coords.contains(coord) {
let count = point_count.entry(coord).or_insert(0);
*count += 1;
}
},
GridPoint::Unfilled { x: _, y: _ } |
GridPoint::Tied { x: _, y: _, closest_dist: _ } => {}
}
}
*point_count.values().max().unwrap_or(&0)
} }
#[cfg(test)] #[cfg(test)]
@ -208,75 +277,89 @@ mod tests {
Coordinate { Coordinate {
x: 1, x: 1,
y: 1, y: 1,
letter: 'a',
}, },
Coordinate { Coordinate {
x: 1, x: 1,
y: 6, y: 6,
letter: 'b',
}, },
Coordinate { Coordinate {
x: 8, x: 8,
y: 3, y: 3,
letter: 'c',
}, },
Coordinate { Coordinate {
x: 3, x: 3,
y: 4, y: 4,
letter: 'd',
}, },
Coordinate { Coordinate {
x: 5, x: 5,
y: 5, y: 5,
letter: 'e',
}, },
Coordinate { Coordinate {
x: 8, x: 8,
y: 9, y: 9,
letter: 'f',
}, },
]); ]);
} }
#[test] #[test]
fn gets_boundary_coordinate() { fn gets_boundary_coordinate() {
assert_eq!(get_boundary_coordinate(vec![ assert_eq!(get_boundary_coordinate(&vec![
Coordinate { Coordinate {
x: 1, x: 1,
y: 1, y: 1,
letter: 'a',
}, },
Coordinate { Coordinate {
x: 5, x: 5,
y: 5, y: 5,
letter: 'b',
}, },
Coordinate { Coordinate {
x: 2, x: 2,
y: 7, y: 7,
letter: 'c',
} }
]), ]),
Coordinate { Coordinate {
x: 5, x: 5,
y: 7, y: 7,
letter: '+',
} }
) )
} }
#[test] #[test]
fn creates_grid() { fn creates_grid() {
let boundary_coord = Coordinate { x: 1, y: 1, letter: '+' };
assert_eq!( assert_eq!(
create_grid(Coordinate { x: 1, y: 1 }), create_grid(boundary_coord),
vec![ Grid {
GridPoint::Unfilled { points: vec![
x: 0, GridPoint::Unfilled {
y: 0, x: 0,
}, y: 0,
GridPoint::Unfilled { },
x: 0, GridPoint::Unfilled {
y: 1, x: 1,
}, y: 0,
GridPoint::Unfilled { },
x: 1, GridPoint::Unfilled {
y: 0, x: 0,
}, y: 1,
GridPoint::Unfilled { },
x: 1, GridPoint::Unfilled {
y: 1, x: 1,
}, y: 1,
]) },
],
boundary_coord,
})
} }
#[test] #[test]
@ -288,72 +371,94 @@ mod tests {
#[test] #[test]
fn fills_grid_with_one_coord() { fn fills_grid_with_one_coord() {
let boundary_coord = Coordinate { x: 1, y: 1 }; let boundary_coord = Coordinate { x: 1, y: 1, letter: '+' };
let mut grid = create_grid(boundary_coord); let mut grid = create_grid(boundary_coord);
let coord = Coordinate { x: 0, y: 0 }; let coord = Coordinate { x: 0, y: 0, letter: 'a' };
assert_eq!( assert_eq!(
fill_grid(&mut grid, vec![coord], boundary_coord).unwrap(), fill_grid(&mut grid, &vec![coord]).unwrap(),
&mut vec![ &mut Grid {
GridPoint::Filled { points: vec![
x: 0, GridPoint::Filled {
y: 0, x: 0,
closest_coord: coord, y: 0,
closest_dist: 0, closest_coord: coord,
}, closest_dist: 0,
GridPoint::Filled { },
x: 0, GridPoint::Filled {
y: 1, x: 1,
closest_coord: coord, y: 0,
closest_dist: 1, closest_coord: coord,
}, closest_dist: 1,
GridPoint::Filled { },
x: 1, GridPoint::Filled {
y: 0, x: 0,
closest_coord: coord, y: 1,
closest_dist: 1, closest_coord: coord,
}, closest_dist: 1,
GridPoint::Filled { },
x: 1, GridPoint::Filled {
y: 1, x: 1,
closest_coord: coord, y: 1,
closest_dist: 2, closest_coord: coord,
}, closest_dist: 2,
] },
],
boundary_coord
}
); );
} }
#[test] #[test]
fn fills_grid_with_two_coords() { fn fills_grid_with_two_coords() {
let boundary_coord = Coordinate { x: 1, y: 1 }; let boundary_coord = Coordinate { x: 1, y: 1, letter: '+' };
let mut grid = create_grid(boundary_coord); let mut grid = create_grid(boundary_coord);
let coord_a = Coordinate { x: 0, y: 0 }; let coord_a = Coordinate { x: 0, y: 0, letter: 'a' };
let coord_b = Coordinate { x: 1, y: 1 }; let coord_b = Coordinate { x: 1, y: 1, letter: 'b' };
assert_eq!( assert_eq!(
fill_grid(&mut grid, vec![coord_a, coord_b], boundary_coord).unwrap(), fill_grid(&mut grid, &vec![coord_a, coord_b]).unwrap(),
&mut vec![ &mut Grid {
GridPoint::Filled { points: vec![
x: 0, GridPoint::Filled {
y: 0, x: 0,
closest_coord: coord_a, y: 0,
closest_dist: 0, closest_coord: coord_a,
}, closest_dist: 0,
GridPoint::Tied { },
x: 0, GridPoint::Tied {
y: 1, x: 1,
closest_dist: 1, y: 0,
}, closest_dist: 1,
GridPoint::Tied { },
x: 1, GridPoint::Tied {
y: 0, x: 0,
closest_dist: 1, y: 1,
}, closest_dist: 1,
GridPoint::Filled { },
x: 1, GridPoint::Filled {
y: 1, x: 1,
closest_coord: coord_b, y: 1,
closest_dist: 2, closest_coord: coord_b,
}, closest_dist: 0,
] },
],
boundary_coord
}
);
}
#[test]
fn finds_largest_coord_area() {
let boundary_coord = Coordinate { x: 2, y: 2, letter: '+' };
let mut grid = create_grid(boundary_coord);
let coords = vec![
Coordinate { x: 0, y: 0, letter: 'a' },
Coordinate { x: 2, y: 2, letter: 'b' },
Coordinate { x: 1, y: 1, letter: 'c' },
];
fill_grid(&mut grid, &coords).unwrap();
assert_eq!(
find_largest_coord_area(grid),
1
); );
} }
} }

View File

@ -9,19 +9,21 @@ mod day5;
mod day6; mod day6;
fn main() { fn main() {
println!("Day 1:"); // println!("Day 1:");
println!("{}", day1::solve_part1().unwrap()); // println!("{}", day1::solve_part1().unwrap());
println!("{}", day1::solve_part2().unwrap().unwrap()); // println!("{}", day1::solve_part2().unwrap().unwrap());
println!("Day 2:"); // println!("Day 2:");
println!("{}", day2::solve_part1().unwrap()); // println!("{}", day2::solve_part1().unwrap());
println!("{}", day2::solve_part2().unwrap().unwrap()); // println!("{}", day2::solve_part2().unwrap().unwrap());
println!("Day 3:"); // println!("Day 3:");
println!("{}", day3::solve_part1().unwrap()); // println!("{}", day3::solve_part1().unwrap());
println!("{}", day3::solve_part2().unwrap().unwrap()); // println!("{}", day3::solve_part2().unwrap().unwrap());
println!("Day 4:"); // println!("Day 4:");
println!("{}", day4::solve_part1().unwrap()); // println!("{}", day4::solve_part1().unwrap());
println!("{}", day4::solve_part2().unwrap()); // println!("{}", day4::solve_part2().unwrap());
println!("Day 5:"); // println!("Day 5:");
println!("{}", day5::solve_part1().unwrap()); // println!("{}", day5::solve_part1().unwrap());
println!("{}", day5::solve_part2().unwrap()); // println!("{}", day5::solve_part2().unwrap());
println!("Day 6:");
println!("{}", day6::solve_part1().unwrap());
} }