Compare commits
4 Commits
11b29a4d57
...
de535303d4
Author | SHA1 | Date | |
---|---|---|---|
de535303d4 | |||
50b6d045e7 | |||
d2defae8a2 | |||
cd8900d936 |
@ -12,3 +12,6 @@ itertools = "0.13.0"
|
|||||||
rayon = "1.10.0"
|
rayon = "1.10.0"
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
thread_local = "1.1.8"
|
thread_local = "1.1.8"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
12
src/day10.rs
12
src/day10.rs
@ -29,12 +29,12 @@ impl TrailMap {
|
|||||||
.collect_vec()
|
.collect_vec()
|
||||||
}
|
}
|
||||||
fn count_reachable_from(&self, pos: &(i64, i64), needle: u8, visited: &mut Grid<bool>) -> u64 {
|
fn count_reachable_from(&self, pos: &(i64, i64), needle: u8, visited: &mut Grid<bool>) -> u64 {
|
||||||
if visited.get(pos.0, pos.1) == Some(true) {
|
if visited.get(pos) == Some(true) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
visited.set(pos.0, pos.1, true);
|
visited.set(pos, true);
|
||||||
}
|
}
|
||||||
let our_val = self.map.get(pos.0, pos.1).unwrap();
|
let our_val = self.map.get(pos).unwrap();
|
||||||
if our_val == needle {
|
if our_val == needle {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -42,7 +42,7 @@ impl TrailMap {
|
|||||||
[(-1, 0), (1, 0), (0, -1), (0, 1)] // left, right, up, down
|
[(-1, 0), (1, 0), (0, -1), (0, 1)] // left, right, up, down
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(x_ofs, y_ofs)| (pos.0 + x_ofs, pos.1 + y_ofs)) // get target position
|
.map(|(x_ofs, y_ofs)| (pos.0 + x_ofs, pos.1 + y_ofs)) // get target position
|
||||||
.map(|(x, y)| ((x, y), self.map.get(x, y))) // get value at that position
|
.map(|target_pos| (target_pos, self.map.get(&target_pos))) // get value at that position
|
||||||
.filter(|(_, val)| *val == Some(our_val + 1)) // only interested if it's our value + 1
|
.filter(|(_, val)| *val == Some(our_val + 1)) // only interested if it's our value + 1
|
||||||
.map(|(pos, _)| pos) // discard the value
|
.map(|(pos, _)| pos) // discard the value
|
||||||
.map(|pos| self.count_reachable_from(&pos, needle, visited))
|
.map(|pos| self.count_reachable_from(&pos, needle, visited))
|
||||||
@ -50,14 +50,14 @@ impl TrailMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn count_paths_to(&self, pos: &(i64, i64), needle: u8) -> u64 {
|
fn count_paths_to(&self, pos: &(i64, i64), needle: u8) -> u64 {
|
||||||
let our_val = self.map.get(pos.0, pos.1).unwrap();
|
let our_val = self.map.get(pos).unwrap();
|
||||||
if our_val == needle {
|
if our_val == needle {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
[(-1, 0), (1, 0), (0, -1), (0, 1)] // left, right, up, down
|
[(-1, 0), (1, 0), (0, -1), (0, 1)] // left, right, up, down
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(x_ofs, y_ofs)| (pos.0 + x_ofs, pos.1 + y_ofs)) // get target position
|
.map(|(x_ofs, y_ofs)| (pos.0 + x_ofs, pos.1 + y_ofs)) // get target position
|
||||||
.map(|(x, y)| ((x, y), self.map.get(x, y))) // get value at that position
|
.map(|target_pos| (target_pos, self.map.get(&target_pos))) // get value at that position
|
||||||
.filter(|(_, val)| *val == Some(our_val + 1)) // only interested if it's our value + 1
|
.filter(|(_, val)| *val == Some(our_val + 1)) // only interested if it's our value + 1
|
||||||
.map(|(pos, _)| pos) // discard the value
|
.map(|(pos, _)| pos) // discard the value
|
||||||
.map(|mov| self.count_paths_to(&mov, needle))
|
.map(|mov| self.count_paths_to(&mov, needle))
|
||||||
|
21
src/day11.rs
21
src/day11.rs
@ -1,4 +1,4 @@
|
|||||||
use aoc_runner_derive::{aoc, aoc_generator};
|
use aoc_runner_derive::aoc;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
@ -26,7 +26,6 @@ impl From<&str> for Stones {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[aoc_generator(day11)]
|
|
||||||
fn parse(input: &str) -> Stones {
|
fn parse(input: &str) -> Stones {
|
||||||
Stones::from(input)
|
Stones::from(input)
|
||||||
}
|
}
|
||||||
@ -47,8 +46,8 @@ impl Stone {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn count_blinks(stone: &Stone, blink: usize, cache: &mut Vec<CacheType>) -> IntType {
|
fn count_blinks(stone: &Stone, blink: usize, cache: &mut Vec<CacheType>) -> IntType {
|
||||||
if cache[blink].contains_key(&stone) {
|
if cache[blink].contains_key(stone) {
|
||||||
return cache[blink][&stone].clone();
|
return cache[blink][stone];
|
||||||
}
|
}
|
||||||
let stones = stone.blink_once();
|
let stones = stone.blink_once();
|
||||||
let result = if blink == 0 {
|
let result = if blink == 0 {
|
||||||
@ -63,10 +62,10 @@ fn count_blinks(stone: &Stone, blink: usize, cache: &mut Vec<CacheType>) -> IntT
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
cache[blink].insert(stone.clone(), result);
|
cache[blink].insert(stone.clone(), result);
|
||||||
cache[blink][&stone].clone()
|
cache[blink][stone]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn blink_stones(stones: &Stones, blinks: usize) -> IntType {
|
fn blink_stones(stones: Stones, blinks: usize) -> IntType {
|
||||||
let mut cache = Vec::from_iter(repeat(CacheType::new()).take(blinks));
|
let mut cache = Vec::from_iter(repeat(CacheType::new()).take(blinks));
|
||||||
stones
|
stones
|
||||||
.0
|
.0
|
||||||
@ -76,12 +75,14 @@ fn blink_stones(stones: &Stones, blinks: usize) -> IntType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[aoc(day11, part1)]
|
#[aoc(day11, part1)]
|
||||||
fn part1(stones: &Stones) -> IntType {
|
pub fn part1(input: &str) -> IntType {
|
||||||
|
let stones = parse(input);
|
||||||
blink_stones(stones, 25)
|
blink_stones(stones, 25)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[aoc(day11, part2)]
|
#[aoc(day11, part2)]
|
||||||
fn part2(stones: &Stones) -> IntType {
|
pub fn part2(input: &str) -> IntType {
|
||||||
|
let stones = parse(input);
|
||||||
blink_stones(stones, 75)
|
blink_stones(stones, 75)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,11 +93,11 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn part1_example() {
|
fn part1_example() {
|
||||||
assert_eq!(part1(&parse(EXAMPLE)), 55312);
|
assert_eq!(part1(EXAMPLE), 55312);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn part2_example() {
|
fn part2_example() {
|
||||||
assert_eq!(part2(&parse(EXAMPLE)), 65601038650482);
|
assert_eq!(part2(EXAMPLE), 65601038650482);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
61
src/day6.rs
61
src/day6.rs
@ -1,5 +1,7 @@
|
|||||||
use aoc_runner_derive::{aoc, aoc_generator};
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
|
use rayon::iter::ParallelIterator;
|
||||||
|
use rayon::slice::ParallelSlice;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::{BufRead, Lines};
|
use std::io::{BufRead, Lines};
|
||||||
use std::ops::BitAnd;
|
use std::ops::BitAnd;
|
||||||
@ -14,10 +16,10 @@ pub fn get_input(input: &[u8]) -> Map {
|
|||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
enum FacingDirection {
|
enum FacingDirection {
|
||||||
Up = b'^',
|
Up = 1,
|
||||||
Down = b'v',
|
Down = 2,
|
||||||
Left = b'<',
|
Left = 4,
|
||||||
Right = b'>',
|
Right = 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FacingDirection {
|
impl FacingDirection {
|
||||||
@ -45,6 +47,7 @@ enum StepOutcome {
|
|||||||
Continue,
|
Continue,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq)]
|
||||||
enum RunOutcome {
|
enum RunOutcome {
|
||||||
LeftMap,
|
LeftMap,
|
||||||
LoopFound,
|
LoopFound,
|
||||||
@ -98,7 +101,7 @@ impl<T: BufRead> From<Lines<T>> for Map {
|
|||||||
let grid = Grid::from(input);
|
let grid = Grid::from(input);
|
||||||
let mut visited_from: Grid<DirectionSet> = Grid::new(grid.width() as i64);
|
let mut visited_from: Grid<DirectionSet> = Grid::new(grid.width() as i64);
|
||||||
visited_from.data.resize(grid.data.len(), DirectionSet::empty());
|
visited_from.data.resize(grid.data.len(), DirectionSet::empty());
|
||||||
let guard_pos = grid.find(b'^').expect("Guard not found");
|
let guard_pos = grid.find(&b'^').expect("Guard not found");
|
||||||
let guard_facing = FacingDirection::Up;
|
let guard_facing = FacingDirection::Up;
|
||||||
Self {
|
Self {
|
||||||
grid,
|
grid,
|
||||||
@ -112,31 +115,24 @@ impl<T: BufRead> From<Lines<T>> for Map {
|
|||||||
|
|
||||||
impl Map {
|
impl Map {
|
||||||
fn look(&self, dir: &FacingDirection) -> Option<u8> {
|
fn look(&self, dir: &FacingDirection) -> Option<u8> {
|
||||||
match dir {
|
self.grid.get(&dir.pos_ofs(self.guard_pos))
|
||||||
FacingDirection::Up => self.grid.get(self.guard_pos.0, self.guard_pos.1 - 1),
|
|
||||||
FacingDirection::Down => self.grid.get(self.guard_pos.0, self.guard_pos.1 + 1),
|
|
||||||
FacingDirection::Left => self.grid.get(self.guard_pos.0 - 1, self.guard_pos.1),
|
|
||||||
FacingDirection::Right => self.grid.get(self.guard_pos.0 + 1, self.guard_pos.1),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/// Move one step in the facing direction, return if we are still inside the bounds
|
/// Move one step in the facing direction, return if we are still inside the bounds
|
||||||
fn step_guard<const RECORD_PATH: bool>(&mut self) -> StepOutcome {
|
fn step_guard<const RECORD_PATH: bool>(&mut self) -> StepOutcome {
|
||||||
let new_pos = self.guard_facing.pos_ofs(self.guard_pos);
|
let new_pos = self.guard_facing.pos_ofs(self.guard_pos);
|
||||||
if self
|
if self
|
||||||
.visited_from
|
.visited_from
|
||||||
.get(new_pos.0, new_pos.1)
|
.get(&new_pos)
|
||||||
.is_some_and(|dirs| dirs.contains(self.guard_facing.into()))
|
.is_some_and(|dirs| dirs.contains(self.guard_facing.into()))
|
||||||
{
|
{
|
||||||
return StepOutcome::LoopFound;
|
StepOutcome::LoopFound
|
||||||
}
|
} else if self.grid.set(&new_pos, b'X').is_some() {
|
||||||
if self.grid.set(new_pos.0, new_pos.1, b'X') {
|
|
||||||
if RECORD_PATH {
|
if RECORD_PATH {
|
||||||
self.path.push((new_pos, self.guard_facing));
|
self.path.push((new_pos, self.guard_facing));
|
||||||
}
|
}
|
||||||
self.visited_from.set(
|
self.visited_from.set(
|
||||||
new_pos.0,
|
&new_pos,
|
||||||
new_pos.1,
|
self.visited_from.get(&new_pos).unwrap() | self.guard_facing.into(),
|
||||||
self.visited_from.get(new_pos.0, new_pos.1).unwrap() | self.guard_facing.into(),
|
|
||||||
);
|
);
|
||||||
self.guard_pos = new_pos;
|
self.guard_pos = new_pos;
|
||||||
StepOutcome::Continue
|
StepOutcome::Continue
|
||||||
@ -168,7 +164,7 @@ pub fn part1(map: &Map) -> u64 {
|
|||||||
let mut map = map.clone();
|
let mut map = map.clone();
|
||||||
map.run_guard::<false>();
|
map.run_guard::<false>();
|
||||||
|
|
||||||
(map.grid.count(b'X') + map.grid.count(b'-') + map.grid.count(b'|') + map.grid.count(b'^')) as u64
|
map.grid.count(&b'X') as u64 + 1 // 'X' path positions + 1 starting position
|
||||||
}
|
}
|
||||||
|
|
||||||
// PROBLEM 2 solution
|
// PROBLEM 2 solution
|
||||||
@ -178,28 +174,19 @@ pub fn part2(input_map: &Map) -> u64 {
|
|||||||
let mut path_map = input_map.clone();
|
let mut path_map = input_map.clone();
|
||||||
path_map.run_guard::<true>();
|
path_map.run_guard::<true>();
|
||||||
|
|
||||||
let mut tested_position: grid::Grid<bool> = grid::Grid::new(path_map.grid.width() as i64);
|
path_map
|
||||||
tested_position.data.resize(path_map.grid.data.len(), false);
|
.path
|
||||||
|
.par_windows(2)
|
||||||
let mut loop_count = 0u64;
|
.filter(|prev_cur| {
|
||||||
let mut last_posdir = (input_map.guard_pos, input_map.guard_facing);
|
let last_posdir = prev_cur[0];
|
||||||
|
|
||||||
for ((x, y), dir) in path_map.path.iter() {
|
|
||||||
if !tested_position.get(*x, *y).unwrap() {
|
|
||||||
tested_position.set(*x, *y, true);
|
|
||||||
let mut test_map = input_map.clone();
|
let mut test_map = input_map.clone();
|
||||||
test_map.grid.set(*x, *y, b'#');
|
test_map.grid.set(&prev_cur[1].0, b'#').unwrap();
|
||||||
test_map.guard_pos = last_posdir.0;
|
test_map.guard_pos = last_posdir.0;
|
||||||
test_map.guard_facing = last_posdir.1;
|
test_map.guard_facing = last_posdir.1;
|
||||||
|
|
||||||
if let RunOutcome::LoopFound = test_map.run_guard::<false>() {
|
test_map.run_guard::<false>() == RunOutcome::LoopFound
|
||||||
loop_count += 1
|
})
|
||||||
}
|
.count() as u64
|
||||||
last_posdir = ((*x, *y), *dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loop_count
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -43,7 +43,7 @@ impl AntennaMap {
|
|||||||
let offset = (a.0 - b.0, a.1 - b.1);
|
let offset = (a.0 - b.0, a.1 - b.1);
|
||||||
for i in (start..).map_while(|i| if Some(i - start) != reps { Some(i as i64) } else { None }) {
|
for i in (start..).map_while(|i| if Some(i - start) != reps { Some(i as i64) } else { None }) {
|
||||||
let node_pos = (a.0 + i * offset.0, a.1 + i * offset.1);
|
let node_pos = (a.0 + i * offset.0, a.1 + i * offset.1);
|
||||||
if !antinodes.set(node_pos.0, node_pos.1, true) {
|
if antinodes.set(&node_pos, true).is_none() {
|
||||||
// left the grid
|
// left the grid
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -58,14 +58,14 @@ impl AntennaMap {
|
|||||||
#[aoc(day8, part1)]
|
#[aoc(day8, part1)]
|
||||||
pub fn part1(map: &AntennaMap) -> u64 {
|
pub fn part1(map: &AntennaMap) -> u64 {
|
||||||
let antinodes = map.find_antinodes(1, Some(1));
|
let antinodes = map.find_antinodes(1, Some(1));
|
||||||
antinodes.count(true) as u64
|
antinodes.count(&true) as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
// PROBLEM 2 solution
|
// PROBLEM 2 solution
|
||||||
#[aoc(day8, part2)]
|
#[aoc(day8, part2)]
|
||||||
pub fn part2(map: &AntennaMap) -> u64 {
|
pub fn part2(map: &AntennaMap) -> u64 {
|
||||||
let antinodes = map.find_antinodes(0, None);
|
let antinodes = map.find_antinodes(0, None);
|
||||||
antinodes.count(true) as u64
|
antinodes.count(&true) as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
22
src/lib.rs
22
src/lib.rs
@ -1,15 +1,15 @@
|
|||||||
mod day11;
|
|
||||||
use aoc_runner_derive::aoc_lib;
|
use aoc_runner_derive::aoc_lib;
|
||||||
|
|
||||||
mod day1;
|
pub mod day1;
|
||||||
mod day2;
|
pub mod day2;
|
||||||
mod day3;
|
pub mod day3;
|
||||||
mod day4;
|
pub mod day4;
|
||||||
mod day5;
|
pub mod day5;
|
||||||
mod day6;
|
pub mod day6;
|
||||||
mod day7;
|
pub mod day7;
|
||||||
mod day8;
|
pub mod day8;
|
||||||
mod day9;
|
pub mod day9;
|
||||||
mod day10;
|
pub mod day10;
|
||||||
|
pub mod day11;
|
||||||
|
|
||||||
aoc_lib! { year = 2024 }
|
aoc_lib! { year = 2024 }
|
||||||
|
@ -4,6 +4,42 @@ use std::{
|
|||||||
iter::repeat,
|
iter::repeat,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Coord2d {
|
||||||
|
pub x: i64,
|
||||||
|
pub y: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait AsCoord2d {
|
||||||
|
fn to_coord(self) -> Coord2d;
|
||||||
|
fn x(&self) -> i64;
|
||||||
|
fn y(&self) -> i64;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsCoord2d for Coord2d {
|
||||||
|
fn to_coord(self) -> Coord2d {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn x(&self) -> i64 {
|
||||||
|
self.x
|
||||||
|
}
|
||||||
|
fn y(&self) -> i64 {
|
||||||
|
self.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsCoord2d for (i64, i64) {
|
||||||
|
fn to_coord(self) -> Coord2d {
|
||||||
|
Coord2d { x: self.0, y: self.1 }
|
||||||
|
}
|
||||||
|
fn x(&self) -> i64 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
fn y(&self) -> i64 {
|
||||||
|
self.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Grid<T> {
|
pub struct Grid<T> {
|
||||||
pub data: Vec<T>,
|
pub data: Vec<T>,
|
||||||
@ -29,8 +65,8 @@ impl<T: Copy + Eq + PartialEq + Display + Debug> Grid<T> {
|
|||||||
pub fn height(&self) -> usize {
|
pub fn height(&self) -> usize {
|
||||||
return self.data.len() / self.width();
|
return self.data.len() / self.width();
|
||||||
}
|
}
|
||||||
fn pos(&self, x: i64, y: i64) -> i64 {
|
fn pos<C: AsCoord2d>(&self, c: &C) -> i64 {
|
||||||
y * self.width + x
|
c.y() * self.width + c.x()
|
||||||
}
|
}
|
||||||
pub fn coord(&self, pos: i64) -> Option<(i64, i64)> {
|
pub fn coord(&self, pos: i64) -> Option<(i64, i64)> {
|
||||||
if pos < 0 || pos >= self.data.len() as i64 {
|
if pos < 0 || pos >= self.data.len() as i64 {
|
||||||
@ -39,57 +75,58 @@ impl<T: Copy + Eq + PartialEq + Display + Debug> Grid<T> {
|
|||||||
Some((pos % self.width, pos / self.width))
|
Some((pos % self.width, pos / self.width))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn valid_pos(&self, x: i64, y: i64) -> Option<usize> {
|
fn valid_pos<C: AsCoord2d>(&self, c: &C) -> Option<usize> {
|
||||||
if x < 0 || x >= self.width {
|
if c.x() < 0 || c.x() >= self.width {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if y < 0 || y >= self.data.len() as i64 / self.width {
|
if c.y() < 0 || c.y() >= self.data.len() as i64 / self.width {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let pos = self.pos(x, y);
|
let pos = self.pos(c);
|
||||||
if pos < 0 || pos as usize >= self.data.len() {
|
if pos < 0 || pos as usize >= self.data.len() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
self.pos(x, y).try_into().ok()
|
self.pos(c).try_into().ok()
|
||||||
}
|
}
|
||||||
pub fn get(&self, x: i64, y: i64) -> Option<T> {
|
pub fn get<C: AsCoord2d>(&self, c: &C) -> Option<T> {
|
||||||
match self.valid_pos(x, y) {
|
match self.valid_pos(c) {
|
||||||
Some(pos) => Some(self.data[pos]),
|
Some(pos) => Some(self.data[pos]),
|
||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn set(&mut self, x: i64, y: i64, val: T) -> bool {
|
pub fn set<C: AsCoord2d>(&mut self, c: &C, val: T) -> Option<T> {
|
||||||
match self.valid_pos(x, y) {
|
match self.valid_pos(c) {
|
||||||
Some(pos) => {
|
Some(pos) => {
|
||||||
|
let res = Some(self.data[pos]);
|
||||||
self.data[pos] = val;
|
self.data[pos] = val;
|
||||||
true
|
res
|
||||||
}
|
}
|
||||||
None => false,
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn row(&self, y: i64) -> Option<&[T]> {
|
pub fn row(&self, y: i64) -> Option<&[T]> {
|
||||||
if y < self.height() as i64 {
|
if y < self.height() as i64 {
|
||||||
Some(&self.data[self.pos(0, y) as usize..self.pos(self.width, y) as usize])
|
Some(&self.data[self.pos(&(0, y)) as usize..self.pos(&(self.width, y)) as usize])
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find(&self, haystack: T) -> Option<(i64, i64)> {
|
pub fn find(&self, haystack: &T) -> Option<(i64, i64)> {
|
||||||
self.coord(
|
self.coord(
|
||||||
self.data
|
self.data
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find_map(|(pos, val)| if *val == haystack { Some(pos as i64) } else { None })
|
.find_map(|(pos, val)| if val == haystack { Some(pos as i64) } else { None })
|
||||||
.unwrap_or(-1),
|
.unwrap_or(-1),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pub fn count(&self, haystack: T) -> usize {
|
pub fn count(&self, haystack: &T) -> usize {
|
||||||
self.data.iter().filter(|item| **item == haystack).count()
|
self.data.iter().filter(|item| *item == haystack).count()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn forward_slice(&self, x: i64, y: i64, len: i64) -> Option<&[T]> {
|
pub fn forward_slice<C: AsCoord2d>(&self, start: &C, len: i64) -> Option<&[T]> {
|
||||||
let pos = (self.valid_pos(x, y), self.valid_pos(x + len - 1, y));
|
let pos = (self.valid_pos(start), self.valid_pos(&(start.x() + len - 1, start.y())));
|
||||||
match pos {
|
match pos {
|
||||||
(Some(pos1), Some(pos2)) => Some(&self.data[pos1..pos2 + 1]),
|
(Some(pos1), Some(pos2)) => Some(&self.data[pos1..pos2 + 1]),
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -151,7 +188,7 @@ impl Display for Grid<u8> {
|
|||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
for y in 0..self.height() {
|
for y in 0..self.height() {
|
||||||
for x in 0..self.width() {
|
for x in 0..self.width() {
|
||||||
f.write_fmt(format_args!("{}",self.get(x as i64, y as i64).unwrap() as char))?;
|
f.write_fmt(format_args!("{}", self.get(&(x as i64, y as i64)).unwrap() as char))?;
|
||||||
}
|
}
|
||||||
f.write_char('\n')?;
|
f.write_char('\n')?;
|
||||||
}
|
}
|
||||||
@ -181,21 +218,21 @@ FBCG";
|
|||||||
#[test]
|
#[test]
|
||||||
fn indexing() {
|
fn indexing() {
|
||||||
let grid = unchecked_load();
|
let grid = unchecked_load();
|
||||||
assert_eq!(grid.get(0, 0), Some(b'A'));
|
assert_eq!(grid.get(&(0, 0)), Some(b'A'));
|
||||||
assert_eq!(grid.get(3, 3), Some(b'G'));
|
assert_eq!(grid.get(&(3, 3)), Some(b'G'));
|
||||||
assert_eq!(grid.get(-1, 0), None);
|
assert_eq!(grid.get(&(-1, 0)), None);
|
||||||
assert_eq!(grid.get(0, -1), None);
|
assert_eq!(grid.get(&(0, -1)), None);
|
||||||
assert_eq!(grid.get(5, 0), None);
|
assert_eq!(grid.get(&(5, 0)), None);
|
||||||
assert_eq!(grid.get(0, 5), None);
|
assert_eq!(grid.get(&(0, 5)), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn forward_slice() {
|
fn forward_slice() {
|
||||||
let grid = unchecked_load();
|
let grid = unchecked_load();
|
||||||
assert_eq!(grid.forward_slice(0, 0, 2), Some(b"AB".as_slice()));
|
assert_eq!(grid.forward_slice(&(0, 0), 2), Some(b"AB".as_slice()));
|
||||||
assert_eq!(grid.forward_slice(2, 0, 2), Some(b"CD".as_slice()));
|
assert_eq!(grid.forward_slice(&(2, 0), 2), Some(b"CD".as_slice()));
|
||||||
assert_eq!(grid.forward_slice(2, 0, 3), None);
|
assert_eq!(grid.forward_slice(&(2, 0), 3), None);
|
||||||
assert_eq!(grid.forward_slice(0, 2, 4), Some(b"IJKL".as_slice()));
|
assert_eq!(grid.forward_slice(&(0, 2), 4), Some(b"IJKL".as_slice()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user