better rust
This commit is contained in:
parent
41b013b5e9
commit
d5b6cb72cb
21 changed files with 61 additions and 112 deletions
|
|
@ -6,10 +6,10 @@ fn format_path(day_num: usize, file: &str) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_string(day_num: usize, file: &str) -> io::Result<String> {
|
pub fn read_string(day_num: usize, file: &str) -> io::Result<String> {
|
||||||
Ok(fs::read_to_string(format_path(day_num, file))?)
|
fs::read_to_string(format_path(day_num, file))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn split_lines<'a>(lines: &'a str) -> impl Iterator<Item = &'a str> + 'a {
|
pub fn split_lines(lines: &str) -> impl Iterator<Item = &'_ str> + '_ {
|
||||||
lines
|
lines
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.with_position()
|
.with_position()
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ pub const NEG_Z: UnitVector = UnitVector(Pos3::new(0, 0, -1));
|
||||||
|
|
||||||
impl UnitVector {
|
impl UnitVector {
|
||||||
pub fn new(vector: Pos3<i8>) -> Option<Self> {
|
pub fn new(vector: Pos3<i8>) -> Option<Self> {
|
||||||
vector.is_unit().then(|| UnitVector(vector))
|
vector.is_unit().then_some(UnitVector(vector))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn x(self) -> i8 {
|
pub fn x(self) -> i8 {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ impl DayTrait for Day {
|
||||||
|
|
||||||
fn part1(&self, lines: &str) -> anyhow::Result<ResultType> {
|
fn part1(&self, lines: &str) -> anyhow::Result<ResultType> {
|
||||||
let sum = split_lines(lines)
|
let sum = split_lines(lines)
|
||||||
.map(|line| Rps::parse_line(line))
|
.map(Rps::parse_line)
|
||||||
.collect::<Result<Vec<_>, _>>()?
|
.collect::<Result<Vec<_>, _>>()?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(first, second)| second.asses_pair(&first))
|
.map(|(first, second)| second.asses_pair(&first))
|
||||||
|
|
@ -25,7 +25,7 @@ impl DayTrait for Day {
|
||||||
|
|
||||||
fn part2(&self, lines: &str) -> anyhow::Result<ResultType> {
|
fn part2(&self, lines: &str) -> anyhow::Result<ResultType> {
|
||||||
let sum = split_lines(lines)
|
let sum = split_lines(lines)
|
||||||
.map(|line| Strategy::parse_line(line))
|
.map(Strategy::parse_line)
|
||||||
.collect::<Result<Vec<_>, _>>()?
|
.collect::<Result<Vec<_>, _>>()?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(first, second)| second.fullfill(&first).asses_pair(&first))
|
.map(|(first, second)| second.fullfill(&first).asses_pair(&first))
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ impl DayTrait for Day {
|
||||||
|
|
||||||
fn part1(&self, lines: &str) -> anyhow::Result<ResultType> {
|
fn part1(&self, lines: &str) -> anyhow::Result<ResultType> {
|
||||||
let sum = split_lines(lines)
|
let sum = split_lines(lines)
|
||||||
.map(|line| find_double(line))
|
.map(find_double)
|
||||||
.map_ok(priority)
|
.map_ok(priority)
|
||||||
.flatten_ok()
|
.flatten_ok()
|
||||||
.fold_ok(0, |a, b| a + b)?;
|
.fold_ok(0, |a, b| a + b)?;
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ impl DayTrait for Day {
|
||||||
|
|
||||||
fn part1(&self, lines: &str) -> anyhow::Result<ResultType> {
|
fn part1(&self, lines: &str) -> anyhow::Result<ResultType> {
|
||||||
let sum = split_lines(lines)
|
let sum = split_lines(lines)
|
||||||
.map(|line| parse(line))
|
.map(parse)
|
||||||
.filter_ok(fully_contained)
|
.filter_ok(fully_contained)
|
||||||
.fold_ok(0i64, |a, _| a + 1)?;
|
.fold_ok(0i64, |a, _| a + 1)?;
|
||||||
Ok(ResultType::Integer(sum))
|
Ok(ResultType::Integer(sum))
|
||||||
|
|
@ -23,7 +23,7 @@ impl DayTrait for Day {
|
||||||
|
|
||||||
fn part2(&self, lines: &str) -> anyhow::Result<ResultType> {
|
fn part2(&self, lines: &str) -> anyhow::Result<ResultType> {
|
||||||
let sum = split_lines(lines)
|
let sum = split_lines(lines)
|
||||||
.map(|line| parse(line))
|
.map(parse)
|
||||||
.filter_ok(overlaps)
|
.filter_ok(overlaps)
|
||||||
.fold_ok(0i64, |a, _| a + 1)?;
|
.fold_ok(0i64, |a, _| a + 1)?;
|
||||||
Ok(ResultType::Integer(sum))
|
Ok(ResultType::Integer(sum))
|
||||||
|
|
|
||||||
|
|
@ -59,12 +59,10 @@ fn parse_crate(line: &str) -> Vec<Option<char>> {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_all_crates<'a>(
|
fn parse_all_crates(line_it: &mut dyn Iterator<Item = &str>) -> Result<Vec<String>, CrateError> {
|
||||||
line_it: &mut dyn Iterator<Item = &'a str>,
|
|
||||||
) -> Result<Vec<String>, CrateError> {
|
|
||||||
let rows = line_it
|
let rows = line_it
|
||||||
.take_while(|line| !line.is_empty())
|
.take_while(|line| !line.is_empty())
|
||||||
.map(|row| parse_crate(row))
|
.map(parse_crate)
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
let Some(stacks_count) = rows.iter().map(|row| row.len()).max() else {
|
let Some(stacks_count) = rows.iter().map(|row| row.len()).max() else {
|
||||||
return Err(CrateError::NoCargoStacksGiven);
|
return Err(CrateError::NoCargoStacksGiven);
|
||||||
|
|
@ -83,12 +81,10 @@ fn parse_all_crates<'a>(
|
||||||
Ok(stacks)
|
Ok(stacks)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse<'a>(lines: &'a str) -> Result<(Vec<String>, Vec<Move>), CrateError> {
|
fn parse(lines: &str) -> Result<(Vec<String>, Vec<Move>), CrateError> {
|
||||||
let mut iter = split_lines(lines);
|
let mut iter = split_lines(lines);
|
||||||
let stacks = parse_all_crates(&mut iter)?;
|
let stacks = parse_all_crates(&mut iter)?;
|
||||||
let moves: Vec<_> = iter
|
let moves: Vec<_> = iter.map(Move::try_from).collect::<Result<_, _>>()?;
|
||||||
.map(|command| Move::try_from(command))
|
|
||||||
.collect::<Result<_, _>>()?;
|
|
||||||
Ok((stacks, moves))
|
Ok((stacks, moves))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -194,7 +190,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_all_crates() -> Result<()> {
|
fn test_parse_all_crates() -> Result<()> {
|
||||||
let lines = vec![
|
let lines = [
|
||||||
" [D] ",
|
" [D] ",
|
||||||
"[N] [C] ",
|
"[N] [C] ",
|
||||||
"[Z] [M] [P]",
|
"[Z] [M] [P]",
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ fn find_marker(word: &str, marker_length: usize) -> Result<usize, MarkerError> {
|
||||||
if word.len() < marker_length {
|
if word.len() < marker_length {
|
||||||
return Err(MarkerError::StringTooShort(word.to_owned(), marker_length));
|
return Err(MarkerError::StringTooShort(word.to_owned(), marker_length));
|
||||||
}
|
}
|
||||||
let mut letter_count = vec![0; 26];
|
let mut letter_count = [0; 26];
|
||||||
let mut doubles = 0;
|
let mut doubles = 0;
|
||||||
for new in word.chars().take(marker_length) {
|
for new in word.chars().take(marker_length) {
|
||||||
let new = char_pos(new);
|
let new = char_pos(new);
|
||||||
|
|
|
||||||
|
|
@ -92,13 +92,13 @@ impl Rope {
|
||||||
* returns true if the whole rope moved, otherwise false
|
* returns true if the whole rope moved, otherwise false
|
||||||
*/
|
*/
|
||||||
pub fn move_rope(&mut self, head_direction: Direction) -> bool {
|
pub fn move_rope(&mut self, head_direction: Direction) -> bool {
|
||||||
self.head = self.head + head_direction;
|
self.head += head_direction;
|
||||||
let mut prev = self.head;
|
let mut prev = self.head;
|
||||||
let mut knots_unmoved = self.knots.len();
|
let mut knots_unmoved = self.knots.len();
|
||||||
|
|
||||||
for knot in self.knots.iter_mut() {
|
for knot in self.knots.iter_mut() {
|
||||||
if let Some(diff) = get_closer(*knot, prev) {
|
if let Some(diff) = get_closer(*knot, prev) {
|
||||||
*knot = *knot + diff;
|
*knot += diff;
|
||||||
prev = *knot;
|
prev = *knot;
|
||||||
knots_unmoved -= 1;
|
knots_unmoved -= 1;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,8 @@ impl Operation {
|
||||||
let (input, _) = tag("new = old ")(input)?;
|
let (input, _) = tag("new = old ")(input)?;
|
||||||
alt((
|
alt((
|
||||||
value(Operation::Squared, tag("* old")),
|
value(Operation::Squared, tag("* old")),
|
||||||
preceded(char('*'), trim0(i64.map(|a| Operation::Times(a)))),
|
preceded(char('*'), trim0(i64.map(Operation::Times))),
|
||||||
preceded(char('+'), trim0(i64.map(|a| Operation::Plus(a)))),
|
preceded(char('+'), trim0(i64.map(Operation::Plus))),
|
||||||
))(input)
|
))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,19 +48,7 @@ struct Path {
|
||||||
|
|
||||||
impl PartialOrd for Path {
|
impl PartialOrd for Path {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
match other.length.partial_cmp(&self.length) {
|
Some(self.cmp(other))
|
||||||
Some(core::cmp::Ordering::Equal) => {}
|
|
||||||
ord => return ord,
|
|
||||||
}
|
|
||||||
match other.height.partial_cmp(&self.height) {
|
|
||||||
Some(core::cmp::Ordering::Equal) => {}
|
|
||||||
ord => return ord,
|
|
||||||
}
|
|
||||||
match self.pos.x().partial_cmp(&other.pos.x()) {
|
|
||||||
Some(core::cmp::Ordering::Equal) => {}
|
|
||||||
ord => return ord,
|
|
||||||
}
|
|
||||||
self.pos.y().partial_cmp(&other.pos.y())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,7 @@ impl Packets {
|
||||||
pub fn parse_all(lines: &str) -> Result<Vec<Packets>, PacketError> {
|
pub fn parse_all(lines: &str) -> Result<Vec<Packets>, PacketError> {
|
||||||
split_lines(lines)
|
split_lines(lines)
|
||||||
.filter(|line| !line.is_empty())
|
.filter(|line| !line.is_empty())
|
||||||
.map(|line| Packets::parse(line))
|
.map(Packets::parse)
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -874,7 +874,7 @@ impl<AG: ActorGroup> Ord for WeightedState<AG> {
|
||||||
impl<AG: ActorGroup> Deref for WeightedState<AG> {
|
impl<AG: ActorGroup> Deref for WeightedState<AG> {
|
||||||
type Target = ValveState<AG>;
|
type Target = ValveState<AG>;
|
||||||
|
|
||||||
fn deref<'b>(&'b self) -> &'b Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1029,7 +1029,7 @@ mod test {
|
||||||
result.closed,
|
result.closed,
|
||||||
vec![Index(1), Index(2), Index(3), Index(7), Index(9)]
|
vec![Index(1), Index(2), Index(3), Index(7), Index(9)]
|
||||||
);
|
);
|
||||||
assert_eq!(result.potential, Flow(20 * 1));
|
assert_eq!(result.potential, Flow(20));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -1091,8 +1091,8 @@ mod test {
|
||||||
assert_eq!(next.len(), 15);
|
assert_eq!(next.len(), 15);
|
||||||
let result = &next[4];
|
let result = &next[4];
|
||||||
assert_eq!(result.flow, Flow(13 * 3));
|
assert_eq!(result.flow, Flow(13 * 3));
|
||||||
assert_eq!(result.potential, Flow(21 * 2 + 2 * 1));
|
assert_eq!(result.potential, Flow(21 * 2 + 2));
|
||||||
assert_eq!(result.flow_potential(), Flow(13 * 3 + 21 * 2 + 2 * 1));
|
assert_eq!(result.flow_potential(), Flow(13 * 3 + 21 * 2 + 2));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.closed,
|
result.closed,
|
||||||
vec![Index(2), Index(3), Index(4), Index(7), Index(9)]
|
vec![Index(2), Index(3), Index(4), Index(7), Index(9)]
|
||||||
|
|
|
||||||
|
|
@ -15,31 +15,19 @@ impl DayTrait for Day {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part1(&self, lines: &str) -> anyhow::Result<ResultType> {
|
fn part1(&self, lines: &str) -> anyhow::Result<ResultType> {
|
||||||
let pushes = Dispenser::new(
|
let pushes = Dispenser::new(lines.trim_end().chars().map(Push::parse).try_collect()?)?;
|
||||||
lines
|
|
||||||
.trim_end()
|
|
||||||
.chars()
|
|
||||||
.map(|c| Push::parse(c))
|
|
||||||
.try_collect()?,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let result = Day::run(pushes, 2022)?;
|
let result = Day::run(pushes, 2022)?;
|
||||||
|
|
||||||
Ok(ResultType::Integer(result as i64))
|
Ok(ResultType::Integer(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part2(&self, lines: &str) -> anyhow::Result<ResultType> {
|
fn part2(&self, lines: &str) -> anyhow::Result<ResultType> {
|
||||||
let pushes = Dispenser::new(
|
let pushes = Dispenser::new(lines.trim_end().chars().map(Push::parse).try_collect()?)?;
|
||||||
lines
|
|
||||||
.trim_end()
|
|
||||||
.chars()
|
|
||||||
.map(|c| Push::parse(c))
|
|
||||||
.try_collect()?,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let result = Day::run(pushes, 1000000000000)?;
|
let result = Day::run(pushes, 1000000000000)?;
|
||||||
|
|
||||||
Ok(ResultType::Integer(result as i64))
|
Ok(ResultType::Integer(result))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,12 +144,11 @@ impl Rock {
|
||||||
let positions = blocks
|
let positions = blocks
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(y, line)| {
|
.flat_map(|(y, line)| {
|
||||||
line.iter()
|
line.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter_map(move |(x, block)| block.then_some((x, height - 1 - y)))
|
.filter_map(move |(x, block)| block.then_some((x, height - 1 - y)))
|
||||||
})
|
})
|
||||||
.flatten()
|
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|
||||||
Ok(Rock {
|
Ok(Rock {
|
||||||
|
|
@ -299,8 +286,8 @@ impl Stack {
|
||||||
let mut rock = FallingRock::new(rock, self.height());
|
let mut rock = FallingRock::new(rock, self.height());
|
||||||
loop {
|
loop {
|
||||||
let push = push_cycle.next();
|
let push = push_cycle.next();
|
||||||
rock = rock.try_push(push, &self);
|
rock = rock.try_push(push, self);
|
||||||
match rock.try_drop(&self) {
|
match rock.try_drop(self) {
|
||||||
Ok(next_rock) => rock = next_rock,
|
Ok(next_rock) => rock = next_rock,
|
||||||
Err(rock) => {
|
Err(rock) => {
|
||||||
let bottom = rock.bottom;
|
let bottom = rock.bottom;
|
||||||
|
|
@ -413,13 +400,7 @@ mod test {
|
||||||
fn drop_one() -> Result<()> {
|
fn drop_one() -> Result<()> {
|
||||||
let day = Day {};
|
let day = Day {};
|
||||||
let lines = read_string(day.get_day_number(), "example01.txt")?;
|
let lines = read_string(day.get_day_number(), "example01.txt")?;
|
||||||
let pushes = Dispenser::new(
|
let pushes = Dispenser::new(lines.trim_end().chars().map(Push::parse).try_collect()?)?;
|
||||||
lines
|
|
||||||
.trim_end()
|
|
||||||
.chars()
|
|
||||||
.map(|c| Push::parse(c))
|
|
||||||
.try_collect()?,
|
|
||||||
)?;
|
|
||||||
let raw = read_string(day.get_day_number(), "blocks.txt")?;
|
let raw = read_string(day.get_day_number(), "blocks.txt")?;
|
||||||
let rocks = Dispenser::new(Rock::parse(&raw)?)?;
|
let rocks = Dispenser::new(Rock::parse(&raw)?)?;
|
||||||
|
|
||||||
|
|
@ -435,13 +416,7 @@ mod test {
|
||||||
fn drop_some() -> Result<()> {
|
fn drop_some() -> Result<()> {
|
||||||
let day = Day {};
|
let day = Day {};
|
||||||
let lines = read_string(day.get_day_number(), "example01.txt")?;
|
let lines = read_string(day.get_day_number(), "example01.txt")?;
|
||||||
let pushes = Dispenser::new(
|
let pushes = Dispenser::new(lines.trim_end().chars().map(Push::parse).try_collect()?)?;
|
||||||
lines
|
|
||||||
.trim_end()
|
|
||||||
.chars()
|
|
||||||
.map(|c| Push::parse(c))
|
|
||||||
.try_collect()?,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let result = Day::run(pushes, 10)?;
|
let result = Day::run(pushes, 10)?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ struct Droplet(i64, i64, i64);
|
||||||
|
|
||||||
impl Droplet {
|
impl Droplet {
|
||||||
fn parse(line: &str) -> Result<Droplet, DropletError> {
|
fn parse(line: &str) -> Result<Droplet, DropletError> {
|
||||||
let split = line.split(",").collect_vec();
|
let split = line.split(',').collect_vec();
|
||||||
if split.len() != 3 {
|
if split.len() != 3 {
|
||||||
return Err(DropletError::IllegalDroplet(line.to_owned()));
|
return Err(DropletError::IllegalDroplet(line.to_owned()));
|
||||||
}
|
}
|
||||||
|
|
@ -135,9 +135,7 @@ impl TryFrom<&str> for Blob {
|
||||||
type Error = DropletError;
|
type Error = DropletError;
|
||||||
|
|
||||||
fn try_from(lines: &str) -> Result<Self, Self::Error> {
|
fn try_from(lines: &str) -> Result<Self, Self::Error> {
|
||||||
let droplets = split_lines(lines)
|
let droplets = split_lines(lines).map(Droplet::parse).try_collect()?;
|
||||||
.map(|line| Droplet::parse(line))
|
|
||||||
.try_collect()?;
|
|
||||||
Ok(Blob { droplets })
|
Ok(Blob { droplets })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -148,7 +146,7 @@ impl Blob {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut range = Ranges::new(&self.droplets.iter().next().unwrap());
|
let mut range = Ranges::new(self.droplets.iter().next().unwrap());
|
||||||
for droplet in self.droplets.iter().skip(1) {
|
for droplet in self.droplets.iter().skip(1) {
|
||||||
range.extend(droplet);
|
range.extend(droplet);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ impl Ingredients {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inc(&self, mat: Material) -> Ingredients {
|
fn inc(&self, mat: Material) -> Ingredients {
|
||||||
let mut next = self.0.clone();
|
let mut next = self.0;
|
||||||
next[mat as usize] += 1;
|
next[mat as usize] += 1;
|
||||||
Ingredients(next)
|
Ingredients(next)
|
||||||
}
|
}
|
||||||
|
|
@ -351,7 +351,7 @@ impl Cabinet {
|
||||||
let _ = sender.send(result);
|
let _ = sender.send(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
done = done + 1;
|
done += 1;
|
||||||
if done >= count {
|
if done >= count {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -404,7 +404,7 @@ impl Simulation {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn no_production(mut self) -> Self {
|
pub fn no_production(mut self) -> Self {
|
||||||
self.time = self.time - 1;
|
self.time -= 1;
|
||||||
self.material = self.material + &self.robots;
|
self.material = self.material + &self.robots;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ impl Ring {
|
||||||
self.items
|
self.items
|
||||||
.iter()
|
.iter()
|
||||||
.position(|v| *v == value)
|
.position(|v| *v == value)
|
||||||
.ok_or_else(|| RingError::ItemNotFound(value))
|
.ok_or(RingError::ItemNotFound(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_pos(&self, pos: usize) -> usize {
|
fn next_pos(&self, pos: usize) -> usize {
|
||||||
|
|
@ -145,9 +145,7 @@ impl Ring {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn multiply(&mut self, arg: i64) {
|
fn multiply(&mut self, arg: i64) {
|
||||||
self.items
|
self.items.iter_mut().for_each(|value| *value *= arg);
|
||||||
.iter_mut()
|
|
||||||
.for_each(|value| *value = *value * arg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ use thiserror::Error;
|
||||||
|
|
||||||
const DAY_NUMBER: usize = 21;
|
const DAY_NUMBER: usize = 21;
|
||||||
|
|
||||||
const ROOT: &'static str = "root";
|
const ROOT: &str = "root";
|
||||||
const HUMAN: &'static str = "humn";
|
const HUMAN: &str = "humn";
|
||||||
pub struct Day;
|
pub struct Day;
|
||||||
|
|
||||||
impl DayTrait for Day {
|
impl DayTrait for Day {
|
||||||
|
|
@ -91,11 +91,7 @@ impl MonkeyJob {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(input: &str) -> IResult<&str, MonkeyJob> {
|
fn parse(input: &str) -> IResult<&str, MonkeyJob> {
|
||||||
trim0(alt((
|
trim0(alt((i64.map(MonkeyJob::Yell), MonkeyJob::parse_operation))).parse(input)
|
||||||
i64.map(|val| MonkeyJob::Yell(val)),
|
|
||||||
MonkeyJob::parse_operation,
|
|
||||||
)))
|
|
||||||
.parse(input)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform(&self, troop: &Troop) -> Result<i64, MonkeyError> {
|
fn perform(&self, troop: &Troop) -> Result<i64, MonkeyError> {
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ impl WorldMap {
|
||||||
value(None, char(' ')),
|
value(None, char(' ')),
|
||||||
));
|
));
|
||||||
let line = eol_terminated(many1(tile));
|
let line = eol_terminated(many1(tile));
|
||||||
let mut lines = many1(line).map(|tiles| WorldMap::new(tiles));
|
let mut lines = many1(line).map(WorldMap::new);
|
||||||
lines.parse(input)
|
lines.parse(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -147,7 +147,7 @@ enum Instruction {
|
||||||
impl Instruction {
|
impl Instruction {
|
||||||
fn parse(input: &str) -> IResult<&str, Vec<Instruction>> {
|
fn parse(input: &str) -> IResult<&str, Vec<Instruction>> {
|
||||||
many1(alt((
|
many1(alt((
|
||||||
usize.map(|v| Instruction::Walk(v)),
|
usize.map(Instruction::Walk),
|
||||||
value(Instruction::Right, char('R')),
|
value(Instruction::Right, char('R')),
|
||||||
value(Instruction::Left, char('L')),
|
value(Instruction::Left, char('L')),
|
||||||
)))
|
)))
|
||||||
|
|
@ -342,7 +342,7 @@ struct CubeWalker {
|
||||||
|
|
||||||
impl CubeWalker {
|
impl CubeWalker {
|
||||||
fn get_side_length(world: &WorldMap) -> Result<usize, WorldError> {
|
fn get_side_length(world: &WorldMap) -> Result<usize, WorldError> {
|
||||||
let width = world.width().ok_or_else(|| WorldError::NotAValidCube)?;
|
let width = world.width().ok_or(WorldError::NotAValidCube)?;
|
||||||
let height = world.height();
|
let height = world.height();
|
||||||
if width % 3 == 0 && height % 4 == 0 && width / 3 == height / 4 {
|
if width % 3 == 0 && height % 4 == 0 && width / 3 == height / 4 {
|
||||||
Ok(height / 4)
|
Ok(height / 4)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
use super::template::{DayTrait, ResultType};
|
use super::template::{DayTrait, ResultType};
|
||||||
use crate::common::{area::Area, direction::Direction, pos2::Pos2};
|
use crate::common::{area::Area, direction::Direction, pos2::Pos2};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::{collections::HashMap, str::FromStr};
|
use std::{
|
||||||
|
collections::{hash_map::Entry, HashMap},
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
const DAY_NUMBER: usize = 23;
|
const DAY_NUMBER: usize = 23;
|
||||||
|
|
@ -143,14 +146,13 @@ impl FromStr for Field {
|
||||||
let elves: HashMap<Pos2<i32>, bool> = lines
|
let elves: HashMap<Pos2<i32>, bool> = lines
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(y, row)| {
|
.flat_map(|(y, row)| {
|
||||||
row.chars().enumerate().filter_map(move |(x, c)| match c {
|
row.chars().enumerate().filter_map(move |(x, c)| match c {
|
||||||
'.' => None,
|
'.' => None,
|
||||||
'#' => Some(Ok((Pos2::new(x as i32, y as i32), true))),
|
'#' => Some(Ok((Pos2::new(x as i32, y as i32), true))),
|
||||||
_ => Some(Err(FieldError::UnknownChar(c))),
|
_ => Some(Err(FieldError::UnknownChar(c))),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.flatten()
|
|
||||||
.try_collect()?;
|
.try_collect()?;
|
||||||
|
|
||||||
Ok(Field {
|
Ok(Field {
|
||||||
|
|
@ -198,10 +200,10 @@ impl Field {
|
||||||
{
|
{
|
||||||
match self.check(elf, self.direction.iter()) {
|
match self.check(elf, self.direction.iter()) {
|
||||||
MoveCheck::MoveTo(proposal, direction) => {
|
MoveCheck::MoveTo(proposal, direction) => {
|
||||||
if proposals.contains_key(&proposal) {
|
if let Entry::Vacant(e) = proposals.entry(proposal) {
|
||||||
proposals.remove(&proposal);
|
e.insert((elf, direction));
|
||||||
} else {
|
} else {
|
||||||
proposals.insert(proposal, (elf, direction));
|
proposals.remove(&proposal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MoveCheck::NoNeighbors => {
|
MoveCheck::NoNeighbors => {
|
||||||
|
|
@ -214,7 +216,7 @@ impl Field {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.elves.extend(deactivate.into_iter());
|
self.elves.extend(deactivate);
|
||||||
|
|
||||||
for (to, (from, direction)) in proposals {
|
for (to, (from, direction)) in proposals {
|
||||||
self.elves.remove(&from);
|
self.elves.remove(&from);
|
||||||
|
|
@ -328,7 +330,7 @@ mod test {
|
||||||
Pos2::new(2, 5)
|
Pos2::new(2, 5)
|
||||||
);
|
);
|
||||||
let field: Field = lines.parse()?;
|
let field: Field = lines.parse()?;
|
||||||
let elves = HashSet::from_iter(field.rounds(2).into_iter());
|
let elves = HashSet::from_iter(field.rounds(2));
|
||||||
assert_eq!(elves, expected);
|
assert_eq!(elves, expected);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@ impl Valley {
|
||||||
let raw = input
|
let raw = input
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(y, row)| {
|
.flat_map(|(y, row)| {
|
||||||
row.char_indices().filter_map(move |(x, c)| match c {
|
row.char_indices().filter_map(move |(x, c)| match c {
|
||||||
'#' => {
|
'#' => {
|
||||||
if x != 0 && x != row.len() - 1 {
|
if x != 0 && x != row.len() - 1 {
|
||||||
|
|
@ -195,7 +195,6 @@ impl Valley {
|
||||||
_ => Some(Err(BlizzardError::IllegalChar(c))),
|
_ => Some(Err(BlizzardError::IllegalChar(c))),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.flatten()
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
Ok(Blizzards::new(raw, width - 2, height))
|
Ok(Blizzards::new(raw, width - 2, height))
|
||||||
|
|
@ -208,7 +207,7 @@ impl Valley {
|
||||||
let mut queue = vec![start];
|
let mut queue = vec![start];
|
||||||
let mut next_queue = vec![];
|
let mut next_queue = vec![];
|
||||||
while let Some(current) = queue.pop() {
|
while let Some(current) = queue.pop() {
|
||||||
for next_state in current.next_states(&self) {
|
for next_state in current.next_states(self) {
|
||||||
if next_state.trip == trips {
|
if next_state.trip == trips {
|
||||||
return Ok(next_state.time.get());
|
return Ok(next_state.time.get());
|
||||||
}
|
}
|
||||||
|
|
@ -420,10 +419,7 @@ mod test {
|
||||||
assert_eq!(valley.storm.len(), 5);
|
assert_eq!(valley.storm.len(), 5);
|
||||||
assert_eq!(valley.get_entry(), Pos2::new(0, 0));
|
assert_eq!(valley.get_entry(), Pos2::new(0, 0));
|
||||||
assert_eq!(valley.get_exit(), Pos2::new(4, 6));
|
assert_eq!(valley.get_exit(), Pos2::new(4, 6));
|
||||||
assert_eq!(
|
assert!(!valley.storm.get(Time(3)).is_accessible(&Pos2::new(3, 2)));
|
||||||
valley.storm.get(Time(3)).is_accessible(&Pos2::new(3, 2)),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ impl FromStr for Snafu {
|
||||||
"=-012"
|
"=-012"
|
||||||
.chars()
|
.chars()
|
||||||
.position(|d| d == c)
|
.position(|d| d == c)
|
||||||
.ok_or_else(|| SnafuError::IllegalChar(c))
|
.ok_or(SnafuError::IllegalChar(c))
|
||||||
})
|
})
|
||||||
.fold_ok(0, |acc, next| acc * 5 + (next as i64 - 2))?,
|
.fold_ok(0, |acc, next| acc * 5 + (next as i64 - 2))?,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue