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;
|
use grid::Grid;
|
||||||
|
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut grid = Grid::from_file("grid.txt");
|
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