finish 11
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub struct Coordinate {
|
||||
pub x: usize,
|
||||
pub y: usize,
|
||||
}
|
||||
|
||||
impl Coordinate {
|
||||
pub fn new(x: usize, y: usize) -> Self {
|
||||
Self { x, y }
|
||||
}
|
||||
|
||||
pub fn from_coordinate_pairs(x_idxs: [usize; 4], y_idxs: [usize; 4]) -> [Self; 4] {
|
||||
let result: Vec<_> = x_idxs
|
||||
.iter()
|
||||
.zip(y_idxs)
|
||||
.map(|(x, y)| Self::new(*x, y))
|
||||
.collect();
|
||||
result.try_into().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Coordinate {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let inner = &format!("{},{}", self.x, self.y);
|
||||
f.write_str(inner)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Show {
|
||||
fn show(&self) -> String;
|
||||
}
|
||||
|
||||
impl Show for [Coordinate; 4] {
|
||||
fn show(&self) -> String {
|
||||
self.iter().map(|c| format!("{},{} --", c.x, c.y)).collect()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#[derive(Debug)]
|
||||
pub enum Direction {
|
||||
Down,
|
||||
Right,
|
||||
DiagonalUp,
|
||||
DiagonalDown,
|
||||
}
|
||||
|
||||
impl Iterator for Direction {
|
||||
type Item = (Self, bool);
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self {
|
||||
Direction::Down => Some((Direction::Right, false)),
|
||||
Direction::Right => Some((Direction::DiagonalUp, false)),
|
||||
Direction::DiagonalUp => Some((Direction::DiagonalDown, false)),
|
||||
Direction::DiagonalDown => Some((Direction::Down, true)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
use crate::neighbours::Neighbours;
|
||||
|
||||
type Data = u32;
|
||||
|
||||
pub struct Grid {
|
||||
grid: Vec<Vec<Data>>,
|
||||
neighbours: Neighbours,
|
||||
}
|
||||
|
||||
impl Grid {
|
||||
pub fn from_file(filename: &str) -> Self {
|
||||
let grid: Vec<Vec<_>> = std::fs::read_to_string(filename)
|
||||
.unwrap()
|
||||
.split_terminator('\n')
|
||||
.map(|line| {
|
||||
line.split_whitespace()
|
||||
.map(|cell| cell.parse::<u8>().unwrap() as Data)
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
let ny = grid.len();
|
||||
let nx = grid[0].len();
|
||||
let neighbours = Neighbours::new(nx, ny);
|
||||
Grid { grid, neighbours }
|
||||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
let mut largest = 0;
|
||||
while let Some(coordinates) = self.neighbours.next() {
|
||||
let value = coordinates.iter().map(|c| self.grid[c.y][c.x]).product();
|
||||
if value > largest {
|
||||
largest = value;
|
||||
}
|
||||
}
|
||||
println!("{largest}");
|
||||
}
|
||||
}
|
||||
+5
-186
@@ -1,190 +1,9 @@
|
||||
use std::{fmt::Debug, fs};
|
||||
mod coordinate;
|
||||
mod direction;
|
||||
mod grid;
|
||||
mod neighbours;
|
||||
|
||||
const LENGTH: usize = 4;
|
||||
|
||||
type Data = u32;
|
||||
type Neighbours = Vec<Coordinate>;
|
||||
|
||||
struct Coordinate {
|
||||
x: usize,
|
||||
y: usize,
|
||||
}
|
||||
|
||||
impl Coordinate {
|
||||
fn new(x: usize, y: usize) -> Self {
|
||||
Self { x, y }
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Coordinate {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let inner = &format!("{},{}", self.x, self.y);
|
||||
f.write_str(inner)
|
||||
}
|
||||
}
|
||||
|
||||
struct Grid {
|
||||
grid: Vec<Vec<Data>>,
|
||||
nx: usize,
|
||||
ny: usize,
|
||||
curr_x: usize,
|
||||
curr_y: usize,
|
||||
curr_direction: Direction,
|
||||
done: bool,
|
||||
}
|
||||
|
||||
impl Grid {
|
||||
fn from_file(filename: &str) -> Self {
|
||||
let grid: Vec<Vec<_>> = fs::read_to_string(filename)
|
||||
.unwrap()
|
||||
.split_terminator('\n')
|
||||
.map(|line| {
|
||||
line.split_whitespace()
|
||||
.map(|cell| cell.parse::<u8>().unwrap() as Data)
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
let ny = grid.len();
|
||||
let nx = grid[0].len();
|
||||
Grid {
|
||||
grid,
|
||||
nx,
|
||||
ny,
|
||||
curr_x: 0,
|
||||
curr_y: 0,
|
||||
curr_direction: Direction::None,
|
||||
done: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn run(&mut self) {
|
||||
let mut largest = 0;
|
||||
loop {
|
||||
if let Some(coordinates) = self.next() {
|
||||
let value = coordinates.iter().map(|c| self.grid[c.y][c.x]).product();
|
||||
if value > largest {
|
||||
largest = value;
|
||||
}
|
||||
}
|
||||
if self.done {
|
||||
break;
|
||||
}
|
||||
}
|
||||
println!("{largest}");
|
||||
}
|
||||
|
||||
fn advance_index(&mut self) {
|
||||
if self.curr_x == self.nx - 1 {
|
||||
self.curr_x = 0;
|
||||
self.curr_y += 1;
|
||||
if self.curr_y == self.ny {
|
||||
self.done = true;
|
||||
}
|
||||
} else {
|
||||
self.curr_x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn get_neighbours(&self) -> Option<Neighbours> {
|
||||
match self.curr_direction {
|
||||
Direction::Down => self.get_neighbours_down(),
|
||||
Direction::Right => self.get_neighbours_right(),
|
||||
Direction::DiagonalUp => self.get_neighbours_diag_up(),
|
||||
Direction::DiagonalDown => self.get_neighbours_diag_down(),
|
||||
Direction::None => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_neighbours_down(&self) -> Option<Neighbours> {
|
||||
let max_y = self.curr_y + LENGTH;
|
||||
if max_y > self.ny {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
(self.curr_y..max_y)
|
||||
.map(|y| Coordinate::new(self.curr_x, y))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_neighbours_right(&self) -> Option<Neighbours> {
|
||||
let max_x = self.curr_x + LENGTH;
|
||||
if max_x > self.nx {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
(self.curr_x..max_x)
|
||||
.map(|x| Coordinate::new(x, self.curr_y))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_neighbours_diag_up(&self) -> Option<Neighbours> {
|
||||
let max_x = self.curr_x + LENGTH;
|
||||
let min_y = self.curr_y.wrapping_sub(LENGTH);
|
||||
if max_x > self.nx || min_y > self.ny {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
(self.curr_x..max_x)
|
||||
.zip(self.curr_y..min_y)
|
||||
.map(|(x, y)| Coordinate::new(x, y))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_neighbours_diag_down(&self) -> Option<Neighbours> {
|
||||
let max_x = self.curr_x + LENGTH;
|
||||
let max_y = self.curr_y + LENGTH;
|
||||
if max_x > self.nx || max_y > self.ny {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
(self.curr_x..max_x)
|
||||
.zip(self.curr_y..max_y)
|
||||
.map(|(x, y)| Coordinate::new(x, y))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Grid {
|
||||
type Item = Neighbours;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let has_wrapped;
|
||||
(self.curr_direction, has_wrapped) = self.curr_direction.next();
|
||||
if has_wrapped {
|
||||
self.advance_index();
|
||||
};
|
||||
self.get_neighbours()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Direction {
|
||||
None,
|
||||
Down,
|
||||
Right,
|
||||
DiagonalUp,
|
||||
DiagonalDown,
|
||||
}
|
||||
|
||||
impl Direction {
|
||||
fn next(&self) -> (Self, bool) {
|
||||
match self {
|
||||
Direction::None => (Direction::Down, false),
|
||||
Direction::Down => (Direction::Right, false),
|
||||
Direction::Right => (Direction::DiagonalUp, false),
|
||||
Direction::DiagonalUp => (Direction::DiagonalDown, false),
|
||||
Direction::DiagonalDown => (Direction::Down, true),
|
||||
}
|
||||
}
|
||||
}
|
||||
use grid::Grid;
|
||||
|
||||
fn main() {
|
||||
let mut grid = Grid::from_file("grid.txt");
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
use crate::coordinate::Coordinate;
|
||||
use crate::direction::Direction;
|
||||
|
||||
const LENGTH: usize = 4;
|
||||
|
||||
pub struct Neighbours {
|
||||
nx: usize,
|
||||
ny: usize,
|
||||
x: usize,
|
||||
y: usize,
|
||||
current_direction: Direction,
|
||||
done: bool,
|
||||
}
|
||||
|
||||
impl Neighbours {
|
||||
pub fn new(nx: usize, ny: usize) -> Self {
|
||||
Self {
|
||||
nx,
|
||||
ny,
|
||||
x: 0,
|
||||
y: 0,
|
||||
current_direction: Direction::Down,
|
||||
done: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn iterate_direction(&mut self) {
|
||||
let (new_direction, has_wrapped) = self.current_direction.next().unwrap();
|
||||
self.current_direction = new_direction;
|
||||
if has_wrapped {
|
||||
self.x += 1;
|
||||
if self.x == self.nx {
|
||||
self.x = 0;
|
||||
self.y += 1;
|
||||
if self.y == self.ny {
|
||||
self.done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Neighbours {
|
||||
type Item = [Coordinate; 4];
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.done {
|
||||
return None;
|
||||
}
|
||||
|
||||
let x = self.x;
|
||||
let y = self.y;
|
||||
|
||||
let x_idxs;
|
||||
let y_idxs;
|
||||
|
||||
match self.current_direction {
|
||||
Direction::Down => {
|
||||
x_idxs = [x; 4];
|
||||
y_idxs = [y, y + 1, y + 2, y + 3];
|
||||
}
|
||||
Direction::Right => {
|
||||
x_idxs = [x, x + 1, x + 2, x + 3];
|
||||
y_idxs = [y; 4];
|
||||
}
|
||||
Direction::DiagonalUp => {
|
||||
if y < LENGTH {
|
||||
self.iterate_direction();
|
||||
return self.next();
|
||||
}
|
||||
x_idxs = [x, x + 1, x + 2, x + 3];
|
||||
y_idxs = [y, y - 1, y - 2, y - 3];
|
||||
}
|
||||
Direction::DiagonalDown => {
|
||||
x_idxs = [x, x + 1, x + 2, x + 3];
|
||||
y_idxs = [y, y + 1, y + 2, y + 3];
|
||||
}
|
||||
}
|
||||
|
||||
if x_idxs.iter().any(|x| *x >= self.nx) || y_idxs.iter().any(|y| *y >= self.ny) {
|
||||
self.iterate_direction();
|
||||
return self.next();
|
||||
}
|
||||
|
||||
let result = Coordinate::from_coordinate_pairs(x_idxs, y_idxs);
|
||||
|
||||
self.iterate_direction();
|
||||
|
||||
Some(result)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Neighbours;
|
||||
use crate::coordinate::Coordinate as C;
|
||||
|
||||
#[test]
|
||||
fn neighbours() {
|
||||
let mut n = Neighbours::new(20, 20);
|
||||
n.next()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.zip([C::new(0, 0), C::new(0, 1), C::new(0, 2), C::new(0, 3)])
|
||||
.for_each(|(c1, c2)| assert_eq!(*c1, c2));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user