Skip to content

Commit 8e51d9d

Browse files
committed
2017 day 19
1 parent 7a8885e commit 8e51d9d

File tree

6 files changed

+165
-19
lines changed

6 files changed

+165
-19
lines changed

crates/utils/src/number.rs

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
//! Traits for using numbers as generic data types.
2-
//!
3-
//! Machine-dependent integer types aren't unsupported.
42
53
use std::fmt::Debug;
64
use std::iter::{Product, Sum};
@@ -80,13 +78,23 @@ pub trait Integer:
8078
}
8179

8280
/// Trait implemented by the primitive unsigned integer types.
83-
pub trait UnsignedInteger: Integer + From<u8> {}
81+
pub trait UnsignedInteger: Integer + From<u8> {
82+
type Signed: SignedInteger;
83+
84+
#[must_use]
85+
fn wrapping_add_signed(self, rhs: Self::Signed) -> Self;
86+
}
8487

8588
/// Trait implemented by the primitive signed integer types.
86-
pub trait SignedInteger: Integer + Signed {}
89+
pub trait SignedInteger: Integer + Signed {
90+
type Unsigned: UnsignedInteger;
91+
92+
#[must_use]
93+
fn unsigned_abs(self) -> Self::Unsigned;
94+
}
8795

8896
macro_rules! number_impl {
89-
(uint => $($t:ty),+) => {
97+
(uint => $($t:ty: $signed:ty),+) => {
9098
$(impl Number for $t {
9199
const ZERO: Self = 0;
92100
const ONE: Self = 1;
@@ -106,9 +114,16 @@ macro_rules! number_impl {
106114

107115
number_impl! {@common integer => $($t),+}
108116

109-
$(impl UnsignedInteger for $t {})+
117+
$(impl UnsignedInteger for $t {
118+
type Signed = $signed;
119+
120+
#[inline]
121+
fn wrapping_add_signed(self, rhs: Self::Signed) -> Self {
122+
self.wrapping_add_signed(rhs)
123+
}
124+
})+
110125
};
111-
(int => $($t:ty),+) => {
126+
(int => $($t:ty: $unsigned:ty ),+) => {
112127
$(impl Number for $t {
113128
const ZERO: Self = 0;
114129
const ONE: Self = 1;
@@ -129,7 +144,14 @@ macro_rules! number_impl {
129144
number_impl! {@common integer => $($t),+}
130145
number_impl! {@common signed => $($t),+}
131146

132-
$(impl SignedInteger for $t {})+
147+
$(impl SignedInteger for $t {
148+
type Unsigned = $unsigned;
149+
150+
#[inline]
151+
fn unsigned_abs(self) -> Self::Unsigned {
152+
self.unsigned_abs()
153+
}
154+
})+
133155
};
134156
(float => $($t:ty),+) => {
135157
$(impl Number for $t {
@@ -181,8 +203,8 @@ macro_rules! number_impl {
181203
})+
182204
};
183205
}
184-
number_impl! {uint => u8, u16, u32, u64, u128}
185-
number_impl! {int => i8, i16, i32, i64, i128}
206+
number_impl! {uint => u8: i8, u16: i16, u32: i32, u64: i64, u128: i128, usize: isize}
207+
number_impl! {int => i8: u8, i16: u16, i32: u32, i64: u64, i128: u128, isize: usize}
186208
number_impl! {float => f32, f64}
187209

188210
/// Checks if the provided unsigned integer `n` is a prime number.

crates/utils/src/point.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
//! 2D point implementation.
22
3-
use crate::number::{Number, Signed};
3+
use crate::number::{Number, Signed, SignedInteger, UnsignedInteger};
44
use std::fmt::Debug;
55
use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
66

77
macro_rules! point_impl {
8-
($v:vis struct $s:ident{$($f:ident),+}) => {
8+
($(#[$m:meta])* $v:vis struct $s:ident{$($f:ident),+}) => {
99
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
10-
$v struct $s<T: Number> {
10+
$(#[$m])* $v struct $s<T: Number> {
1111
$(pub $f: T,)+
1212
}
1313

@@ -26,6 +26,30 @@ macro_rules! point_impl {
2626
pub fn manhattan_distance(self) -> T {
2727
T::ZERO $(+ self.$f.abs())+
2828
}
29+
30+
/// Returns the manhattan distance from the origin.
31+
#[inline]
32+
#[must_use]
33+
pub fn manhattan_distance_unsigned(self) -> T::Unsigned
34+
where
35+
T: SignedInteger
36+
{
37+
T::Unsigned::ZERO $(+ self.$f.unsigned_abs())+
38+
}
39+
40+
/// Add the provided signed point, wrapping on overflow.
41+
///
42+
/// Useful for adding a signed direction onto an unsigned position.
43+
#[inline]
44+
#[must_use]
45+
pub fn wrapping_add_signed(self, rhs: $s<T::Signed>) -> Self
46+
where
47+
T: UnsignedInteger,
48+
{
49+
Self{
50+
$($f: self.$f.wrapping_add_signed(rhs.$f),)+
51+
}
52+
}
2953
}
3054

3155
impl<T: Number> Add for $s<T> {
@@ -87,7 +111,10 @@ macro_rules! point_impl {
87111
};
88112
}
89113

90-
point_impl! {pub struct Point2D{x, y}}
114+
point_impl! {
115+
/// Struct representing a 2D point or vector.
116+
pub struct Point2D{x, y}
117+
}
91118

92119
impl<T: Signed> Point2D<T> {
93120
pub const UP: Self = Self {

crates/year2016/src/day01.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl Day01 {
2525
}
2626

2727
#[must_use]
28-
pub fn part1(&self) -> i32 {
28+
pub fn part1(&self) -> u32 {
2929
let mut pos = Point2D::ORIGIN;
3030
let mut dir = Point2D::UP;
3131

@@ -37,11 +37,11 @@ impl Day01 {
3737
pos += dir * i32::from(steps);
3838
}
3939

40-
pos.manhattan_distance()
40+
pos.manhattan_distance_unsigned()
4141
}
4242

4343
#[must_use]
44-
pub fn part2(&self) -> i32 {
44+
pub fn part2(&self) -> u32 {
4545
let mut pos: Point2D<i32> = Point2D::ORIGIN;
4646
let mut dir = Point2D::UP;
4747
let mut visited = HashSet::new();
@@ -54,7 +54,7 @@ impl Day01 {
5454
for _ in 0..steps {
5555
pos += dir;
5656
if !visited.insert(pos) {
57-
return pos.manhattan_distance();
57+
return pos.manhattan_distance_unsigned();
5858
}
5959
}
6060
}
@@ -63,7 +63,7 @@ impl Day01 {
6363
}
6464
}
6565

66-
examples!(Day01 -> (i32, i32) [
66+
examples!(Day01 -> (u32, u32) [
6767
{input: "R2, L3", part1: 5},
6868
{input: "R2, R2, R2", part1: 2},
6969
{input: "R5, L5, R5, R3", part1: 12},
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
|
2+
| +--+
3+
A | C
4+
F---|--|-E---+
5+
| | | D
6+
+B-+ +--+

crates/year2017/src/day19.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
use utils::point::Point2D;
2+
use utils::prelude::*;
3+
4+
/// Following a path.
5+
#[derive(Clone, Debug)]
6+
pub struct Day19 {
7+
part1: String,
8+
part2: u32,
9+
}
10+
11+
impl Day19 {
12+
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
13+
let lines = input.lines().collect::<Vec<_>>();
14+
let lookup = |p: Point2D<usize>| {
15+
if p.y < lines.len() && p.x < lines[p.y].len() {
16+
Some(lines[p.y].as_bytes()[p.x])
17+
} else {
18+
None
19+
}
20+
};
21+
22+
let Some(start_col) = lines.first().and_then(|l| l.find('|')) else {
23+
return Err(InputError::new(input, 0, "expected '|' on the first line"));
24+
};
25+
let mut pos = Point2D::new(start_col, 0);
26+
let mut dir = Point2D::new(0, 1);
27+
28+
let mut letters = String::new();
29+
let mut steps = 1;
30+
loop {
31+
match lookup(pos)
32+
.ok_or_else(|| InputError::new(input, 0, "path leads outside the input"))?
33+
{
34+
b'|' | b'-' => {}
35+
b'+' => {
36+
let left = lookup(pos.wrapping_add_signed(dir.turn_left())).unwrap_or(b' ');
37+
let right = lookup(pos.wrapping_add_signed(dir.turn_right())).unwrap_or(b' ');
38+
if matches!(left, b'|' | b'-' | b'A'..=b'Z') && right == b' ' {
39+
dir = dir.turn_left();
40+
} else if matches!(right, b'|' | b'-' | b'A'..=b'Z') && left == b' ' {
41+
dir = dir.turn_right();
42+
} else {
43+
return Err(InputError::new(
44+
input,
45+
&lines[pos.y][pos.x..],
46+
"invalid turn",
47+
));
48+
}
49+
}
50+
letter @ b'A'..=b'Z' => {
51+
letters.push(letter as char);
52+
53+
// The path is allowed to end after letters
54+
if lookup(pos.wrapping_add_signed(dir)).unwrap_or(b' ') == b' ' {
55+
break;
56+
}
57+
}
58+
_ => {
59+
return Err(InputError::new(
60+
input,
61+
&lines[pos.y][pos.x..],
62+
"expected '|', '-', '+' or 'A'-'Z'",
63+
));
64+
}
65+
}
66+
67+
pos = pos.wrapping_add_signed(dir);
68+
steps += 1;
69+
}
70+
71+
Ok(Self {
72+
part1: letters,
73+
part2: steps,
74+
})
75+
}
76+
77+
#[must_use]
78+
pub fn part1(&self) -> &str {
79+
&self.part1
80+
}
81+
82+
#[must_use]
83+
pub fn part2(&self) -> u32 {
84+
self.part2
85+
}
86+
}
87+
88+
examples!(Day19 -> (&'static str, u32) [
89+
{file: "day19_example0.txt", part1: "ABCDEF", part2: 38},
90+
]);

crates/year2017/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ utils::year!(2017 => year2017, ${
2222
16 => day16::Day16,
2323
17 => day17::Day17,
2424
18 => day18::Day18,
25+
19 => day19::Day19,
2526
});

0 commit comments

Comments
 (0)