Skip to content

Commit

Permalink
minor day 10 optimization because I didn't realize the starting tile …
Browse files Browse the repository at this point in the history
…was guaranteed to only have two pipes connecting to it
  • Loading branch information
kcaffrey committed Dec 11, 2023
1 parent b3349b6 commit 086ae68
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 47 deletions.
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,19 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www.

| Day | Part 1 | Part 2 |
| :---: | :---: | :---: |
| [Day 1](./src/bin/01.rs) | `34.2µs` | `38.0µs` |
| [Day 2](./src/bin/02.rs) | `42.3µs` | `41.3µs` |
| [Day 3](./src/bin/03.rs) | `83.6µs` | `99.8µs` |
| [Day 4](./src/bin/04.rs) | `53.5µs` | `50.4µs` |
| [Day 5](./src/bin/05.rs) | `20.8µs` | `24.3µs` |
| [Day 6](./src/bin/06.rs) | `203.0ns` | `103.0ns` |
| [Day 7](./src/bin/07.rs) | `93.8µs` | `91.4µs` |
| [Day 8](./src/bin/08.rs) | `72.7µs` | `161.5µs` |
| [Day 9](./src/bin/09.rs) | `58.5µs` | `50.6µs` |
| [Day 10](./src/bin/10.rs) | `394.2µs` | `775.3µs` |
| [Day 11](./src/bin/11.rs) | `16.1µs` | `15.7µs` |

**Total: 2.22ms**
| [Day 1](./src/bin/01.rs) | `36.8µs` | `35.1µs` |
| [Day 2](./src/bin/02.rs) | `41.6µs` | `41.4µs` |
| [Day 3](./src/bin/03.rs) | `83.7µs` | `98.7µs` |
| [Day 4](./src/bin/04.rs) | `49.3µs` | `50.0µs` |
| [Day 5](./src/bin/05.rs) | `20.5µs` | `24.1µs` |
| [Day 6](./src/bin/06.rs) | `208.0ns` | `102.0ns` |
| [Day 7](./src/bin/07.rs) | `97.3µs` | `94.0µs` |
| [Day 8](./src/bin/08.rs) | `72.7µs` | `160.2µs` |
| [Day 9](./src/bin/09.rs) | `58.2µs` | `58.4µs` |
| [Day 10](./src/bin/10.rs) | `320.4µs` | `640.5µs` |
| [Day 11](./src/bin/11.rs) | `16.6µs` | `15.9µs` |

**Total: 2.02ms**
<!--- benchmarking table --->

---
Expand Down
61 changes: 27 additions & 34 deletions src/bin/10.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub fn part_one(input: &str) -> Option<u32> {
}

pub fn part_two(input: &str) -> Option<u32> {
let mut field = input.parse::<Field>().expect("valid input");
let field = input.parse::<Field>().expect("valid input");

// Figure out where the loop is, and construct a new binary map of loop/not loop.
let (loop_position, _) = field.find_definite_loop_position()?;
Expand Down Expand Up @@ -48,25 +48,6 @@ pub fn part_two(input: &str) -> Option<u32> {
cur = next;
}

// Figure out the missing tile for the start position to make things easier later on.
let starting_tile = Tile::pipes().find(|&pipe| {
pipe.neighbors(field.starting_position).all(|pos| {
let is_in_loop = field
.index(pos)
.map(|index| is_in_loop[index])
.unwrap_or(false);
let is_connected = field
.pipe_neighbors(pos)
.any(|p| p == field.starting_position);
is_in_loop && is_connected
})
})?;
if let Some(cell) = field.get_mut(field.starting_position) {
*cell = starting_tile;
} else {
return None;
}

// Create a helper that will let us determine the size of a connected region bounded
// by "loop pipes".
let mut closed = HashSet::new();
Expand Down Expand Up @@ -164,7 +145,6 @@ enum Tile {
SouthWestPipe,
SouthEastPipe,
Ground,
StartingPosition,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
Expand Down Expand Up @@ -220,11 +200,6 @@ impl Field {
let mut next = ArrayVec::<[(Position, Position); 4]>::new();
use Tile::*;
match (self.get(pos), pos.direction_from(last_pos)) {
(Some(StartingPosition), _) => {
for dir in Direction::cardinal() {
next.push((pos.go(dir), pos));
}
}
(Some(HorizontalPipe), Direction::East) => next.push((pos.go(Direction::West), pos)),
(Some(HorizontalPipe), Direction::West) => next.push((pos.go(Direction::East), pos)),
(Some(VerticalPipe), Direction::North) => next.push((pos.go(Direction::South), pos)),
Expand All @@ -243,10 +218,13 @@ impl Field {
}

pub fn find_definite_loop_position(&self) -> Option<(Position, u32)> {
let mut distance = 0;
let mut distance = 1;
let mut cur = ArrayVec::<[(Position, Position); 4]>::new();
let mut definite_loop_position = None;
cur.push((self.starting_position, self.starting_position));
cur.extend(
self.pipe_neighbors(self.starting_position)
.map(|n| (n, self.starting_position)),
);
while definite_loop_position.is_none() && !cur.is_empty() {
let mut next = ArrayVec::<[(Position, Position); 4]>::new();
for (pos, from_pos) in cur
Expand Down Expand Up @@ -418,6 +396,9 @@ enum ParseFieldError {

#[error("multiple starting positions were found")]
MultipleStartingPositions,

#[error("no valid tile was found for starting position")]
NoValidStartingTile,
}

impl FromStr for Field {
Expand All @@ -440,8 +421,9 @@ impl FromStr for Field {
})
.enumerate()
.map(|(index, ch)| {
let tile: Tile = ch?.try_into()?;
if tile == Tile::StartingPosition {
let ch = ch?;
let tile: Tile = ch.try_into()?;
if ch == 'S' {
if starting_position.is_some() {
return Err(ParseFieldError::MultipleStartingPositions);
}
Expand All @@ -450,7 +432,7 @@ impl FromStr for Field {
Ok(tile)
})
.collect::<Result<_, _>>()?;
Ok(Self {
let mut field = Self {
tiles,
rows,
cols,
Expand All @@ -460,7 +442,18 @@ impl FromStr for Field {
row: (index / cols) as isize,
col: (index % cols) as isize,
})?,
})
};
let starting_position = field.starting_position;
let starting_tile = Tile::pipes()
.find(|&pipe| {
pipe.neighbors(starting_position)
.all(|n| field.pipe_neighbors(n).any(|n2| n2 == starting_position))
})
.ok_or(ParseFieldError::NoValidStartingTile)?;
if let Some(cell) = field.get_mut(starting_position) {
*cell = starting_tile;
};
Ok(field)
}
}

Expand All @@ -476,8 +469,8 @@ impl TryFrom<char> for Tile {
'J' => NorthWestPipe,
'7' => SouthWestPipe,
'F' => SouthEastPipe,
'.' => Ground,
'S' => StartingPosition,
// NOTE: we'll replace the starting tile later, so just return Ground as a placeholder
'.' | 'S' => Ground,
ch => return Err(ParseFieldError::InvalidTileCharacter(ch)),
})
}
Expand Down

0 comments on commit 086ae68

Please sign in to comment.