Skip to content

Commit

Permalink
d6p2 (very slow)
Browse files Browse the repository at this point in the history
  • Loading branch information
SOF3 committed Dec 8, 2024
1 parent 608c8fa commit 12c5cc7
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 31 deletions.
4 changes: 4 additions & 0 deletions src/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,11 @@ macros::all! {
part 1 {
"ticked-fxhash-loc" => p1_ticked_fxhash_loc,
"ticked-fxhash-index" => p1_ticked_fxhash_index,
"ticked-boolvec" => p1_ticked_boolvec,
"ticked-bitvec" => p1_ticked_bitvec,
}
part 2 {
"brute-fxhash-loc" => p2_brute_fxhash_loc,
}
}
}
4 changes: 2 additions & 2 deletions src/all/d4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub fn p1_brute(input: String) -> u32 {
for (index, _) in input.match_indices('X') {
let loc = grid.index_to_loc(index).unwrap();
for &dir in DirectBoth::ALL {
let mut iter = loc.direct_iter(dir, grid).skip(1).take(3).map(|loc| grid.get(loc));
let mut iter = loc.direct_iter(dir, &grid).skip(1).take(3).map(|loc| grid.get(loc));
let chars: [_; 3] = array::from_fn(|_| iter.next().flatten());
if chars == [Some(b'M'), Some(b'A'), Some(b'S')] {
count += 1;
Expand All @@ -33,7 +33,7 @@ pub fn p2_brute(input: String) -> u32 {
[DirectDiagonal::RightUp, DirectDiagonal::LeftDown],
]
.map(|ends| {
let values = ends.map(|direct| grid.get(loc.direct(direct, grid)?));
let values = ends.map(|direct| grid.get(loc.direct(direct, &grid)?));
values == [Some(b'M'), Some(b'S')] || values == [Some(b'S'), Some(b'M')]
});
if matched[0] && matched[1] {
Expand Down
121 changes: 115 additions & 6 deletions src/all/d6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use rustc_hash::FxHashSet;

use crate::util::{DirectTaxicab, GridLoc, GridView};

trait Collector {
trait LocCounter {
fn new(capacity: usize) -> Self;
fn insert(&mut self, loc: impl FnOnce() -> GridLoc, index: impl FnOnce() -> u32);
fn count(&self) -> u32;
}

fn p1_ticked<CollectorT: Collector>(input: String) -> u32 {
fn p1_ticked<CollectorT: LocCounter>(input: String) -> u32 {
let grid = GridView::new(&input);

let mut loc = grid.index_to_loc(input.find('^').unwrap()).unwrap();
Expand All @@ -22,7 +22,7 @@ fn p1_ticked<CollectorT: Collector>(input: String) -> u32 {
collector.insert(|| loc, || grid.loc_to_index(loc));

'directs: loop {
match loc.direct(direct, grid) {
match loc.direct(direct, &grid) {
None => return collector.count(), // leave map
Some(new_loc) => {
match grid.get(new_loc).unwrap() {
Expand All @@ -42,7 +42,7 @@ fn p1_ticked<CollectorT: Collector>(input: String) -> u32 {
}
}

impl<S: BuildHasher + Default> Collector for HashSet<GridLoc, S> {
impl<S: BuildHasher + Default> LocCounter for HashSet<GridLoc, S> {
fn new(capacity: usize) -> Self {
Self::with_capacity_and_hasher(capacity, S::default())
}
Expand All @@ -56,7 +56,7 @@ impl<S: BuildHasher + Default> Collector for HashSet<GridLoc, S> {
}
}

impl<S: BuildHasher + Default> Collector for HashSet<u32, S> {
impl<S: BuildHasher + Default> LocCounter for HashSet<u32, S> {
fn new(capacity: usize) -> Self {
Self::with_capacity_and_hasher(capacity, S::default())
}
Expand All @@ -70,7 +70,28 @@ impl<S: BuildHasher + Default> Collector for HashSet<u32, S> {
}
}

impl Collector for BitVec {
impl LocCounter for Vec<bool> {
fn new(capacity: usize) -> Self {
vec![false; capacity]
}

fn insert(&mut self, _: impl FnOnce() -> GridLoc, index: impl FnOnce() -> u32) {
self[index() as usize] = true;
}

fn count(&self) -> u32 {
let mut output = 0;
// we don't use Iterator::count() here because it uses usize instead of u32
for &b in self {
if b {
output += 1;
}
}
output
}
}

impl LocCounter for BitVec {
fn new(capacity: usize) -> Self {
Self::repeat(false, capacity)
}
Expand All @@ -86,4 +107,92 @@ impl Collector for BitVec {

pub fn p1_ticked_fxhash_loc(input: String) -> u32 { p1_ticked::<FxHashSet<GridLoc>>(input) }
pub fn p1_ticked_fxhash_index(input: String) -> u32 { p1_ticked::<FxHashSet<u32>>(input) }
pub fn p1_ticked_boolvec(input: String) -> u32 { p1_ticked::<Vec<bool>>(input) }
pub fn p1_ticked_bitvec(input: String) -> u32 { p1_ticked::<BitVec>(input) }

trait LoopDetector {
fn new(capacity: usize) -> Self;
fn clear(&mut self);

fn insert(&mut self, loc: impl FnOnce() -> GridLoc, index: impl FnOnce() -> u32, direct: DirectTaxicab) -> IsLooped;
}

#[derive(PartialEq, Eq)]
enum IsLooped {
Repeating,
NewStep,
}

fn is_looping<DetectorT: LoopDetector>(grid: &GridView<impl AsRef<[u8]>>, det: &mut DetectorT, initial: GridLoc) -> bool {
det.clear();

let mut loc = initial;
let mut direct = DirectTaxicab::Up;

'ticks: loop {
if det.insert(|| loc, || grid.loc_to_index(loc), direct) == IsLooped::Repeating {
return true;
}

'directs: loop {
match loc.direct(direct, grid) {
None => return false, // leave map
Some(new_loc) => {
match grid.get(new_loc).unwrap() {
b'^' | b'.' => {
loc = new_loc;
continue 'ticks
}
b'#' => {
direct = direct.clockwise();
continue 'directs
}
_ => unreachable!(),
}
}
}
}
}
}

fn p2_brute<LoopDetectorT: LoopDetector>(input: String) -> u32 {
let initial_index = input.find('^').unwrap();
let size = input.len();
let mut det = LoopDetectorT::new(size);

let input = input.into_bytes();
let mut grid = GridView::new(input);
let initial = grid.index_to_loc(initial_index).unwrap();

let mut count = 0;
for index in 0..size {
if grid.input[index] == b'.' {
grid.input[index] = b'#';
if is_looping(&grid, &mut det, initial) {
count += 1;
}
grid.input[index] = b'.';
}
}
count
}

impl<S: BuildHasher+Default> LoopDetector for HashSet<(GridLoc, DirectTaxicab), S> {
fn new(capacity: usize) -> Self {
HashSet::with_capacity_and_hasher(capacity, S::default())
}

fn clear(&mut self) {
HashSet::clear(self)
}

fn insert(&mut self, loc: impl FnOnce() -> GridLoc, _: impl FnOnce() -> u32, direct: DirectTaxicab) -> IsLooped {
if HashSet::insert(self, (loc(), direct)) {
IsLooped::NewStep
} else {
IsLooped::Repeating
}
}
}

pub fn p2_brute_fxhash_loc(input: String) -> u32 { p2_brute::<FxHashSet<(GridLoc, DirectTaxicab)>>(input) }
46 changes: 23 additions & 23 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@
use std::iter;

#[derive(Clone, Copy)]
pub struct GridView<'a> {
input: &'a [u8],
width: u32,
height: u32,
pub struct GridView<Input> {
pub input: Input,
pub width: u32,
pub height: u32,
}

impl<'a> GridView<'a> {
pub fn new(input: &'a impl AsRef<[u8]>) -> Self {
let input = input.as_ref();
let width = input.iter().position(|&b| b == b'\n').unwrap() as u32 + 1;
Self { input, width, height: (input.len() as u32).div_ceil(width) }
impl<Input: AsRef<[u8]>> GridView<Input> {
pub fn new(input: Input) -> Self {
let width = input.as_ref().iter().position(|&b| b == b'\n').unwrap() as u32 + 1;
let height = (input.as_ref().len() as u32).div_ceil(width);
Self { input, width, height }
}

pub fn get(&self, loc: GridLoc) -> Option<u8> {
self.input.get(self.loc_to_index(loc) as usize).copied()
self.input.as_ref().get(self.loc_to_index(loc) as usize).copied()
}

pub fn loc_to_index(&self, loc: GridLoc) -> u32 {
Expand All @@ -43,7 +43,7 @@ pub struct GridLoc {

impl GridLoc {
pub fn left(self) -> Option<Self> { Some(Self { x: self.x.checked_sub(1)?, y: self.y }) }
pub fn right(self, grid: GridView) -> Option<Self> {
pub fn right(self, grid: &GridView<impl AsRef<[u8]>>) -> Option<Self> {
Some(Self {
x: match self.x.checked_add(1)? {
x if x < grid.width - 1 => x,
Expand All @@ -53,7 +53,7 @@ impl GridLoc {
})
}
pub fn up(self) -> Option<Self> { Some(Self { x: self.x, y: self.y.checked_sub(1)? }) }
pub fn down(self, grid: GridView) -> Option<Self> {
pub fn down(self, grid: &GridView<impl AsRef<[u8]>>) -> Option<Self> {
Some(Self {
x: self.x,
y: match self.y.checked_add(1)? {
Expand All @@ -63,15 +63,15 @@ impl GridLoc {
})
}

pub fn direct(self, direct: impl Direct, grid: GridView) -> Option<Self> {
pub fn direct(self, direct: impl Direct, grid: &GridView<impl AsRef<[u8]>>) -> Option<Self> {
direct.apply(self, grid)
}

pub fn direct_iter<D: Direct>(
pub fn direct_iter<D: Direct, Input: AsRef<[u8]>>(
self,
direct: D,
grid: GridView,
) -> impl Iterator<Item = Self> + use<'_, D> {
grid: &GridView<Input>,
) -> impl Iterator<Item = Self> + use<'_, D, Input> {
let mut loc = Some(self);
iter::from_fn(move || {
let output = loc?;
Expand All @@ -84,10 +84,10 @@ impl GridLoc {
pub trait Direct: Copy + 'static {
const ALL: &[Self];

fn apply(self, loc: GridLoc, grid: GridView) -> Option<GridLoc>;
fn apply(self, loc: GridLoc, grid: &GridView<impl AsRef<[u8]>>) -> Option<GridLoc>;
}

#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum DirectTaxicab {
Left,
Right,
Expand All @@ -109,7 +109,7 @@ impl DirectTaxicab {
impl Direct for DirectTaxicab {
const ALL: &[Self] = &[Self::Left, Self::Right, Self::Up, Self::Down];

fn apply(self, loc: GridLoc, grid: GridView) -> Option<GridLoc> {
fn apply(self, loc: GridLoc, grid: &GridView<impl AsRef<[u8]>>) -> Option<GridLoc> {
match self {
Self::Left => loc.left(),
Self::Right => loc.right(grid),
Expand All @@ -119,7 +119,7 @@ impl Direct for DirectTaxicab {
}
}

#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum DirectBoth {
Left,
Right,
Expand All @@ -143,7 +143,7 @@ impl Direct for DirectBoth {
Self::RightDown,
];

fn apply(self, loc: GridLoc, grid: GridView) -> Option<GridLoc> {
fn apply(self, loc: GridLoc, grid: &GridView<impl AsRef<[u8]>>) -> Option<GridLoc> {
match self {
Self::Left => loc.left(),
Self::Right => loc.right(grid),
Expand All @@ -157,7 +157,7 @@ impl Direct for DirectBoth {
}
}

#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum DirectDiagonal {
LeftUp,
RightUp,
Expand All @@ -168,7 +168,7 @@ pub enum DirectDiagonal {
impl Direct for DirectDiagonal {
const ALL: &[Self] = &[Self::LeftUp, Self::RightUp, Self::LeftDown, Self::RightDown];

fn apply(self, loc: GridLoc, grid: GridView) -> Option<GridLoc> {
fn apply(self, loc: GridLoc, grid: &GridView<impl AsRef<[u8]>>) -> Option<GridLoc> {
match self {
Self::LeftUp => loc.left().and_then(GridLoc::up),
Self::RightUp => loc.right(grid).and_then(GridLoc::up),
Expand Down

0 comments on commit 12c5cc7

Please sign in to comment.