Initial
This commit is contained in:
commit
284f099d3e
22 changed files with 1717 additions and 0 deletions
22
.gitignore
vendored
Normal file
22
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/rust,vscode
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=rust,vscode
|
||||
|
||||
### Rust ###
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
### vscode ###
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/rust,vscode
|
||||
61
.vscode/launch.json
vendored
Normal file
61
.vscode/launch.json
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug executable 'advent2019'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--bin=advent2019",
|
||||
"--package=advent2019"
|
||||
],
|
||||
"filter": {
|
||||
"name": "advent2019",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [
|
||||
"${input:program}"
|
||||
],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"sourceLanguages": [
|
||||
"rust"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug unit tests in executable 'advent2019'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"test",
|
||||
"--no-run",
|
||||
"--bin=advent2019",
|
||||
"--package=advent2019"
|
||||
],
|
||||
"filter": {
|
||||
"name": "advent2019",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"sourceLanguages": [
|
||||
"rust"
|
||||
]
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"id": "program",
|
||||
"type": "promptString",
|
||||
"default": "day",
|
||||
"description": "Which day shall I run?"
|
||||
}
|
||||
]
|
||||
}
|
||||
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "advent2022"
|
||||
version = "1.0.0"
|
||||
authors = ["Ruediger Ludwig <github@savinien.de>"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.68"
|
||||
thiserror = "1.0.38"
|
||||
13
README.md
Normal file
13
README.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# Advent of Code 2019
|
||||
|
||||
These are my solutions for [Advent of Code 2019](https://adventofcode.com/). Thanks to [Eric Wastl](http://was.tl) for the great puzzles and a great time I had solving them.
|
||||
|
||||
These are my attempts for the year 2019. I wanted to learn Rust (started at version 1.48 finished at 1.49) and I would say I succeeded to get the hange of this strange language for just a bit.
|
||||
|
||||
My goal was to finish at least one puzzle on a given day. And to try to use a few additional crates as possible. I did not quite succeed in the former, but at least I solved every single puzzle alone. I am quite pround of a few of them. I learned a lot. Not only about rust, but also on how to approach certain riddles.
|
||||
|
||||
If you look at the code and see ways I could improve it, please do not hesitate to contact me. I am always grateful for everything that makes me a better programmer.
|
||||
|
||||
Also, if you ever look for a programmer and think my code is any good, please also contact me at once.
|
||||
|
||||
All code is published under the [Unlicense](https://unlicense.org/)
|
||||
24
UNLICENSE
Normal file
24
UNLICENSE
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <https://unlicense.org>
|
||||
100
data/day01/input.txt
Normal file
100
data/day01/input.txt
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
128270
|
||||
147113
|
||||
61335
|
||||
78766
|
||||
119452
|
||||
116991
|
||||
70640
|
||||
145446
|
||||
117606
|
||||
135046
|
||||
70489
|
||||
131072
|
||||
67955
|
||||
66424
|
||||
126450
|
||||
101418
|
||||
90225
|
||||
66004
|
||||
136510
|
||||
61695
|
||||
143880
|
||||
53648
|
||||
58699
|
||||
119214
|
||||
83838
|
||||
95895
|
||||
66388
|
||||
66755
|
||||
120223
|
||||
79310
|
||||
93828
|
||||
136686
|
||||
108958
|
||||
140752
|
||||
85343
|
||||
103800
|
||||
126602
|
||||
147726
|
||||
88228
|
||||
83380
|
||||
77877
|
||||
61922
|
||||
75448
|
||||
67095
|
||||
60888
|
||||
136692
|
||||
63271
|
||||
113742
|
||||
68854
|
||||
86904
|
||||
110243
|
||||
104642
|
||||
141854
|
||||
71205
|
||||
76729
|
||||
138540
|
||||
134142
|
||||
62517
|
||||
63306
|
||||
71363
|
||||
126146
|
||||
74749
|
||||
76716
|
||||
59135
|
||||
62449
|
||||
110575
|
||||
134030
|
||||
84072
|
||||
122698
|
||||
96891
|
||||
69976
|
||||
94501
|
||||
149180
|
||||
57944
|
||||
64873
|
||||
68192
|
||||
138238
|
||||
119185
|
||||
137570
|
||||
79274
|
||||
111040
|
||||
142586
|
||||
120872
|
||||
63586
|
||||
78628
|
||||
122704
|
||||
147951
|
||||
102593
|
||||
105562
|
||||
55180
|
||||
64450
|
||||
87466
|
||||
112522
|
||||
60000
|
||||
149885
|
||||
52154
|
||||
80633
|
||||
61867
|
||||
86380
|
||||
136024
|
||||
312
src/common/area.rs
Normal file
312
src/common/area.rs
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
#![allow(dead_code)]
|
||||
use std::fmt::Display;
|
||||
|
||||
use super::{number::Number, pos::Pos};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct Area<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
lower_left: Pos<T>,
|
||||
upper_right: Pos<T>,
|
||||
}
|
||||
|
||||
impl<T> Area<T>
|
||||
where
|
||||
T: Number + Ord,
|
||||
{
|
||||
pub fn new(p1: Pos<T>, p2: Pos<T>) -> Area<T> {
|
||||
Area {
|
||||
lower_left: p1.min_components(&p2),
|
||||
upper_right: p1.max_components(&p2),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extend(&self, pos: Pos<T>) -> Area<T> {
|
||||
if self.contains(pos) {
|
||||
return *self;
|
||||
}
|
||||
|
||||
Area {
|
||||
lower_left: self.lower_left.min_components(&pos),
|
||||
upper_right: self.upper_right.max_components(&pos),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_lower_left(&self) -> Pos<T> {
|
||||
self.lower_left
|
||||
}
|
||||
|
||||
pub fn get_upper_right(&self) -> Pos<T> {
|
||||
self.upper_right
|
||||
}
|
||||
|
||||
pub fn contains(&self, pos: Pos<T>) -> bool {
|
||||
self.lower_left.x() >= pos.x()
|
||||
&& pos.x() >= self.upper_right.x()
|
||||
&& self.lower_left.y() >= pos.y()
|
||||
&& pos.y() >= self.upper_right.y()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Area<T>
|
||||
where
|
||||
T: Number + Ord + 'a,
|
||||
{
|
||||
pub fn from_iterator<I>(mut iter: I) -> Option<Self>
|
||||
where
|
||||
I: Iterator<Item = &'a Pos<T>>,
|
||||
{
|
||||
let first = *iter.next()?;
|
||||
let (upper, lower) = iter.fold((first, first), |(mx, mn), p| {
|
||||
(mx.max_components(&p), mn.min_components(&p))
|
||||
});
|
||||
|
||||
Some(Area::new(lower, upper))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Area<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
pub fn width(&self) -> T {
|
||||
self.upper_right.x() - self.lower_left.x() + T::ONE
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn height(&self) -> T {
|
||||
self.upper_right.y() - self.lower_left.y() + T::ONE
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Area<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
#[allow(dead_code)]
|
||||
pub fn area(&self) -> T {
|
||||
self.width() * self.height()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Display for Area<T>
|
||||
where
|
||||
T: Number + Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "[{}-{}]", self.lower_left, self.upper_right)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Area<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
pub fn cells(&self, ascending: bool) -> CellIterator<'_, T> {
|
||||
CellIterator::new(self, ascending)
|
||||
}
|
||||
|
||||
pub fn rows(&self, ascending: bool) -> RowIterator<'_, T> {
|
||||
RowIterator::new(self, ascending)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RowIterator<'a, T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
area: &'a Area<T>,
|
||||
row: T,
|
||||
ascending: bool,
|
||||
}
|
||||
|
||||
impl<'a, T> RowIterator<'a, T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
fn new(area: &'a Area<T>, ascending: bool) -> RowIterator<'a, T> {
|
||||
RowIterator {
|
||||
area,
|
||||
row: if ascending {
|
||||
area.lower_left.y()
|
||||
} else {
|
||||
area.upper_right.y()
|
||||
},
|
||||
ascending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for RowIterator<'a, T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
type Item = Row<'a, T>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if (self.ascending && self.row <= self.area.upper_right.y())
|
||||
|| (!self.ascending && self.row >= self.area.lower_left.y())
|
||||
{
|
||||
let row = Row {
|
||||
area: self.area,
|
||||
row: self.row,
|
||||
};
|
||||
if self.ascending {
|
||||
self.row += T::ONE;
|
||||
} else {
|
||||
self.row -= T::ONE;
|
||||
}
|
||||
Some(row)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Row<'a, T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
area: &'a Area<T>,
|
||||
row: T,
|
||||
}
|
||||
|
||||
impl<'a, T> Row<'a, T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
pub fn cols(&self, ascending: bool) -> ColIterator<'_, T> {
|
||||
ColIterator {
|
||||
area: self.area,
|
||||
row: self.row,
|
||||
col: if ascending {
|
||||
self.area.lower_left.x()
|
||||
} else {
|
||||
self.area.upper_right.x()
|
||||
},
|
||||
ascending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ColIterator<'a, T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
area: &'a Area<T>,
|
||||
row: T,
|
||||
col: T,
|
||||
ascending: bool,
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for ColIterator<'a, T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
type Item = Pos<T>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if (self.ascending && self.col <= self.area.upper_right.x())
|
||||
|| (!self.ascending && self.col >= self.area.lower_left.x())
|
||||
{
|
||||
let pos = Pos::new(self.col, self.row);
|
||||
if self.ascending {
|
||||
self.col += T::ONE
|
||||
} else {
|
||||
self.col -= T::ONE
|
||||
};
|
||||
Some(pos)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CellIterator<'a, T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
area: &'a Area<T>,
|
||||
row: T,
|
||||
col: T,
|
||||
ascending: bool,
|
||||
}
|
||||
|
||||
impl<'a, T> CellIterator<'a, T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
pub fn new(area: &'a Area<T>, ascending: bool) -> CellIterator<'a, T> {
|
||||
let (col, row) = if ascending {
|
||||
(area.lower_left.x(), area.lower_left.y())
|
||||
} else {
|
||||
(area.upper_right.x(), area.upper_right.y())
|
||||
};
|
||||
CellIterator {
|
||||
area,
|
||||
row,
|
||||
col,
|
||||
ascending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for CellIterator<'a, T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
type Item = Pos<T>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if (self.ascending && self.row <= self.area.upper_right.y())
|
||||
|| (!self.ascending && self.row >= self.area.lower_left.y())
|
||||
{
|
||||
let pos = Pos::new(self.col, self.row);
|
||||
if self.ascending {
|
||||
self.col += T::ONE;
|
||||
if self.col > self.area.upper_right.x() {
|
||||
self.row += T::ONE;
|
||||
self.col = self.area.lower_left.x();
|
||||
}
|
||||
} else {
|
||||
self.col -= T::ONE;
|
||||
if self.col < self.area.lower_left.x() {
|
||||
self.row -= T::ONE;
|
||||
self.col = self.area.upper_right.x();
|
||||
}
|
||||
}
|
||||
|
||||
Some(pos)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_cell_iterator() {
|
||||
let area = Area::new(Pos::new(-1, -1), Pos::new(1, 1));
|
||||
let result = area.cells(true).collect::<Vec<_>>();
|
||||
let expected = vec![
|
||||
Pos::new(-1, -1),
|
||||
Pos::new(0, -1),
|
||||
Pos::new(1, -1),
|
||||
Pos::new(-1, 0),
|
||||
Pos::new(0, 0),
|
||||
Pos::new(1, 0),
|
||||
Pos::new(-1, 1),
|
||||
Pos::new(0, 1),
|
||||
Pos::new(1, 1),
|
||||
];
|
||||
assert_eq!(result, expected);
|
||||
}
|
||||
}
|
||||
156
src/common/direction.rs
Normal file
156
src/common/direction.rs
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
use super::{pos::Pos, turn::Turn};
|
||||
use std::{fmt::Display, ops::Add};
|
||||
|
||||
use Direction::*;
|
||||
use Turn::*;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Direction {
|
||||
East,
|
||||
North,
|
||||
West,
|
||||
South,
|
||||
}
|
||||
|
||||
impl Direction {
|
||||
pub fn as_pos(&self) -> Pos<i32> {
|
||||
match *self {
|
||||
East => Pos::new(1, 0),
|
||||
North => Pos::new(0, 1),
|
||||
West => Pos::new(-1, 0),
|
||||
South => Pos::new(0, -1),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_perpendicular(&self, other: &Direction) -> bool {
|
||||
match *self {
|
||||
East => *other != East && *other != West,
|
||||
North => *other != North && *other != South,
|
||||
West => *other != East && *other != West,
|
||||
South => *other != North && *other != South,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_turn(&self, toward: Direction) -> Turn {
|
||||
if *self == toward {
|
||||
Forward
|
||||
} else if toward == self.turn_left() {
|
||||
Left
|
||||
} else if toward == self.turn_right() {
|
||||
Right
|
||||
} else {
|
||||
Back
|
||||
}
|
||||
}
|
||||
|
||||
pub fn turn(&self, turn: Turn) -> Direction {
|
||||
match turn {
|
||||
Left => self.turn_left(),
|
||||
Right => self.turn_right(),
|
||||
Back => self.turn_back(),
|
||||
Forward => *self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn turn_right(&self) -> Direction {
|
||||
match *self {
|
||||
East => South,
|
||||
North => East,
|
||||
West => North,
|
||||
South => West,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn turn_left(&self) -> Direction {
|
||||
match *self {
|
||||
East => North,
|
||||
North => West,
|
||||
West => South,
|
||||
South => East,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn turn_back(&self) -> Direction {
|
||||
match *self {
|
||||
East => West,
|
||||
North => South,
|
||||
West => East,
|
||||
South => North,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Direction {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match *self {
|
||||
Direction::East => write!(f, "East"),
|
||||
Direction::North => write!(f, "North"),
|
||||
Direction::West => write!(f, "West"),
|
||||
Direction::South => write!(f, "South"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Pos<i32>> for Direction {
|
||||
type Output = Pos<i32>;
|
||||
|
||||
fn add(self, rhs: Pos<i32>) -> Self::Output {
|
||||
Pos::add(rhs, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Pos<i32>> for &Direction {
|
||||
type Output = Pos<i32>;
|
||||
|
||||
fn add(self, rhs: Pos<i32>) -> Self::Output {
|
||||
Pos::add(rhs, *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<&Pos<i32>> for Direction {
|
||||
type Output = Pos<i32>;
|
||||
|
||||
fn add(self, rhs: &Pos<i32>) -> Self::Output {
|
||||
Pos::add(*rhs, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<&Pos<i32>> for &Direction {
|
||||
type Output = Pos<i32>;
|
||||
|
||||
fn add(self, rhs: &Pos<i32>) -> Self::Output {
|
||||
Pos::add(*rhs, *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Turn> for Direction {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Turn) -> Self {
|
||||
self.turn(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<&Turn> for Direction {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: &Turn) -> Direction {
|
||||
Direction::add(self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Turn> for &Direction {
|
||||
type Output = Direction;
|
||||
|
||||
fn add(self, rhs: Turn) -> Direction {
|
||||
Direction::add(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<&Turn> for &Direction {
|
||||
type Output = Direction;
|
||||
|
||||
fn add(self, rhs: &Turn) -> Direction {
|
||||
Direction::add(*self, *rhs)
|
||||
}
|
||||
}
|
||||
5
src/common/file.rs
Normal file
5
src/common/file.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
use std::{fs, io};
|
||||
|
||||
pub fn read_data(day_num: usize, file: &str) -> io::Result<String> {
|
||||
fs::read_to_string(format!("data/day{:02}/{}", day_num, file))
|
||||
}
|
||||
94
src/common/helper.rs
Normal file
94
src/common/helper.rs
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
#![allow(dead_code)]
|
||||
use std::fmt::Display;
|
||||
|
||||
pub fn join<T: Display>(lst: &[T], sep: &str) -> String {
|
||||
lst.iter()
|
||||
.map(|item| item.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(sep)
|
||||
}
|
||||
|
||||
pub fn zip2<A, B>(o1: Option<A>, o2: Option<B>) -> Option<(A, B)> {
|
||||
o1.zip(o2)
|
||||
}
|
||||
|
||||
pub fn zip3<A, B, C>(o1: Option<A>, o2: Option<B>, o3: Option<C>) -> Option<(A, B, C)> {
|
||||
match (o1, o2, o3) {
|
||||
(Some(a), Some(b), Some(c)) => Some((a, b, c)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zip4<A, B, C, D>(
|
||||
o1: Option<A>,
|
||||
o2: Option<B>,
|
||||
o3: Option<C>,
|
||||
o4: Option<D>,
|
||||
) -> Option<(A, B, C, D)> {
|
||||
match (o1, o2, o3, o4) {
|
||||
(Some(a), Some(b), Some(c), Some(d)) => Some((a, b, c, d)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zip5<A, B, C, D, E>(
|
||||
o1: Option<A>,
|
||||
o2: Option<B>,
|
||||
o3: Option<C>,
|
||||
o4: Option<D>,
|
||||
o5: Option<E>,
|
||||
) -> Option<(A, B, C, D, E)> {
|
||||
match (o1, o2, o3, o4, o5) {
|
||||
(Some(a), Some(b), Some(c), Some(d), Some(e)) => Some((a, b, c, d, e)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zip6<A, B, C, D, E, F>(
|
||||
o1: Option<A>,
|
||||
o2: Option<B>,
|
||||
o3: Option<C>,
|
||||
o4: Option<D>,
|
||||
o5: Option<E>,
|
||||
o6: Option<F>,
|
||||
) -> Option<(A, B, C, D, E, F)> {
|
||||
match (o1, o2, o3, o4, o5, o6) {
|
||||
(Some(a), Some(b), Some(c), Some(d), Some(e), Some(f)) => Some((a, b, c, d, e, f)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zip7<A, B, C, D, E, F, G>(
|
||||
o1: Option<A>,
|
||||
o2: Option<B>,
|
||||
o3: Option<C>,
|
||||
o4: Option<D>,
|
||||
o5: Option<E>,
|
||||
o6: Option<F>,
|
||||
o7: Option<G>,
|
||||
) -> Option<(A, B, C, D, E, F, G)> {
|
||||
match (o1, o2, o3, o4, o5, o6, o7) {
|
||||
(Some(a), Some(b), Some(c), Some(d), Some(e), Some(f), Some(g)) => {
|
||||
Some((a, b, c, d, e, f, g))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zip8<A, B, C, D, E, F, G, H>(
|
||||
o1: Option<A>,
|
||||
o2: Option<B>,
|
||||
o3: Option<C>,
|
||||
o4: Option<D>,
|
||||
o5: Option<E>,
|
||||
o6: Option<F>,
|
||||
o7: Option<G>,
|
||||
o8: Option<H>,
|
||||
) -> Option<(A, B, C, D, E, F, G, H)> {
|
||||
match (o1, o2, o3, o4, o5, o6, o7, o8) {
|
||||
(Some(a), Some(b), Some(c), Some(d), Some(e), Some(f), Some(g), Some(h)) => {
|
||||
Some((a, b, c, d, e, f, g, h))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
165
src/common/math.rs
Normal file
165
src/common/math.rs
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
#![allow(dead_code)]
|
||||
use thiserror::Error;
|
||||
|
||||
use super::number::Number;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum MathError {
|
||||
#[error("We can not calculate so close to the ceiling")]
|
||||
TooHigh,
|
||||
|
||||
#[error("Need positive modulo")]
|
||||
NeedPositiveModulo,
|
||||
|
||||
#[error("Need non negative exponent")]
|
||||
NeedNonNegativeExponent,
|
||||
}
|
||||
|
||||
fn non_zero_gcd<T>(mut a: T, mut b: T) -> T
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
while b != T::ZERO {
|
||||
let t = a % b;
|
||||
a = b;
|
||||
b = t;
|
||||
}
|
||||
a.abs()
|
||||
}
|
||||
|
||||
pub fn gcd<T>(a: T, b: T) -> T
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
if a == T::ZERO {
|
||||
b.abs()
|
||||
} else if b == T::ZERO {
|
||||
a.abs()
|
||||
} else {
|
||||
non_zero_gcd(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lcm<T>(a: T, b: T) -> T
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
if a == T::ZERO || b == T::ZERO {
|
||||
T::ZERO
|
||||
} else {
|
||||
a * b / non_zero_gcd(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modulus_inv<T>(num: T, modulo: T) -> Option<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
let num = num.rem_euclid(modulo);
|
||||
let mut s = (T::ZERO, T::ONE);
|
||||
let mut r = (modulo, num);
|
||||
while r.0 != T::ZERO {
|
||||
let q = r.1 / r.0;
|
||||
r = (r.1 - q * r.0, r.0);
|
||||
s = (s.1 - q * s.0, s.0);
|
||||
}
|
||||
if r.1 != T::ONE {
|
||||
None
|
||||
} else {
|
||||
Some(s.1.rem_euclid(modulo))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modulus_mul<T>(a: T, b: T, modulo: T) -> Result<T, MathError>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
let mul = if let Some(mul) = a.checked_mul(b) {
|
||||
mul
|
||||
} else if T::MAX >> T::ONE >= a {
|
||||
let start = if b.is_odd() { a } else { T::ZERO };
|
||||
start + modulus_mul((a << T::ONE).rem_euclid(modulo), b >> T::ONE, modulo)?
|
||||
} else {
|
||||
return Err(MathError::TooHigh);
|
||||
};
|
||||
|
||||
Ok(mul.rem_euclid(modulo))
|
||||
}
|
||||
|
||||
pub fn modulus_exp<T>(base: T, exponent: T, modulo: T) -> Result<T, MathError>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
if modulo < T::ONE {
|
||||
return Err(MathError::NeedPositiveModulo);
|
||||
}
|
||||
if exponent < T::ZERO {
|
||||
return Err(MathError::NeedNonNegativeExponent);
|
||||
}
|
||||
|
||||
if modulo == T::ONE {
|
||||
Ok(T::ZERO)
|
||||
} else {
|
||||
let mut result = T::ONE;
|
||||
let mut base = base.rem_euclid(modulo);
|
||||
let mut exponent = exponent;
|
||||
while exponent > T::ZERO {
|
||||
if exponent.is_odd() {
|
||||
result = modulus_mul(result, base, modulo)?;
|
||||
}
|
||||
exponent = exponent >> T::ONE;
|
||||
base = modulus_mul(base, base, modulo)?;
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn some_simple_gcd() {
|
||||
assert_eq!(5, gcd(10, 15));
|
||||
assert_eq!(7, gcd(21, 49));
|
||||
assert_eq!(1, gcd(13, 17));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn some_simple_lcm() {
|
||||
assert_eq!(18, lcm(6, 9));
|
||||
assert_eq!(20, lcm(5, 4));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_modulo_mul() -> Result<(), MathError> {
|
||||
let a = 1_234_567_890_123_456i64;
|
||||
let b = 98_765;
|
||||
let result = modulus_mul(a, b, 3_333_333_333_333_333)?;
|
||||
|
||||
assert_eq!(result, 2_097_668_043_144_033);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_modulo_exp() -> Result<(), MathError> {
|
||||
let base = 4;
|
||||
let exponent = 13;
|
||||
let modulo = 497;
|
||||
let result = modulus_exp(base, exponent, modulo)?;
|
||||
|
||||
assert_eq!(result, 445);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inverse_modulo() {
|
||||
let num = 3;
|
||||
let modulo = 10;
|
||||
let inv = modulus_inv(num, modulo);
|
||||
|
||||
assert_eq!(inv, Some(7));
|
||||
}
|
||||
}
|
||||
9
src/common/mod.rs
Normal file
9
src/common/mod.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
pub mod area;
|
||||
pub mod direction;
|
||||
pub mod file;
|
||||
pub mod helper;
|
||||
pub mod math;
|
||||
pub mod number;
|
||||
pub mod permutations;
|
||||
pub mod pos;
|
||||
pub mod turn;
|
||||
102
src/common/number.rs
Normal file
102
src/common/number.rs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
use std::ops::{Add, AddAssign, BitAnd, Div, Mul, Rem, Shl, Shr, Sub, SubAssign};
|
||||
|
||||
pub trait Number:
|
||||
Copy
|
||||
+ Add<Output = Self>
|
||||
+ Sub<Output = Self>
|
||||
+ Mul<Output = Self>
|
||||
+ Div<Output = Self>
|
||||
+ Rem<Output = Self>
|
||||
+ Shr<Output = Self>
|
||||
+ Shl<Output = Self>
|
||||
+ AddAssign
|
||||
+ SubAssign
|
||||
+ BitAnd<Output = Self>
|
||||
+ PartialEq
|
||||
+ PartialOrd
|
||||
+ Ord
|
||||
{
|
||||
const ZERO: Self;
|
||||
const ONE: Self;
|
||||
const MAX: Self;
|
||||
|
||||
fn abs(self) -> Self;
|
||||
fn checked_mul(self, rhs: Self) -> Option<Self>;
|
||||
fn rem_euclid(self, rhs: Self) -> Self;
|
||||
|
||||
fn is_odd(&self) -> bool {
|
||||
*self & Self::ONE == Self::ONE
|
||||
}
|
||||
|
||||
fn is_even(&self) -> bool {
|
||||
!self.is_odd()
|
||||
}
|
||||
|
||||
fn as_f64(self) -> f64;
|
||||
}
|
||||
|
||||
impl Number for i32 {
|
||||
const ZERO: i32 = 0i32;
|
||||
const ONE: i32 = 1i32;
|
||||
const MAX: i32 = i32::MAX;
|
||||
|
||||
fn abs(self) -> Self {
|
||||
(self as i32).abs()
|
||||
}
|
||||
|
||||
fn rem_euclid(self, rhs: Self) -> Self {
|
||||
(self as i32).rem_euclid(rhs)
|
||||
}
|
||||
|
||||
fn checked_mul(self, rhs: Self) -> Option<Self> {
|
||||
(self as i32).checked_mul(rhs)
|
||||
}
|
||||
|
||||
fn as_f64(self) -> f64 {
|
||||
self as f64
|
||||
}
|
||||
}
|
||||
|
||||
impl Number for i64 {
|
||||
const ZERO: i64 = 0i64;
|
||||
const ONE: i64 = 1i64;
|
||||
const MAX: i64 = i64::MAX;
|
||||
|
||||
fn abs(self) -> Self {
|
||||
(self as i64).abs()
|
||||
}
|
||||
|
||||
fn rem_euclid(self, rhs: Self) -> Self {
|
||||
(self as i64).rem_euclid(rhs)
|
||||
}
|
||||
|
||||
fn checked_mul(self, rhs: Self) -> Option<Self> {
|
||||
(self as i64).checked_mul(rhs)
|
||||
}
|
||||
|
||||
fn as_f64(self) -> f64 {
|
||||
self as f64
|
||||
}
|
||||
}
|
||||
|
||||
impl Number for i128 {
|
||||
const ZERO: i128 = 0i128;
|
||||
const ONE: i128 = 1i128;
|
||||
const MAX: i128 = i128::MAX;
|
||||
|
||||
fn abs(self) -> Self {
|
||||
(self as i128).abs()
|
||||
}
|
||||
|
||||
fn rem_euclid(self, rhs: Self) -> Self {
|
||||
(self as i128).rem_euclid(rhs)
|
||||
}
|
||||
|
||||
fn checked_mul(self, rhs: Self) -> Option<Self> {
|
||||
(self as i128).checked_mul(rhs)
|
||||
}
|
||||
|
||||
fn as_f64(self) -> f64 {
|
||||
self as f64
|
||||
}
|
||||
}
|
||||
152
src/common/permutations.rs
Normal file
152
src/common/permutations.rs
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
pub trait PermutateExt<T>: IntoIterator<Item = T> {
|
||||
fn permutate(&self) -> Permutations<'_, T>;
|
||||
}
|
||||
|
||||
impl<T> PermutateExt<T> for Vec<T> {
|
||||
fn permutate(&self) -> Permutations<'_, T> {
|
||||
let list = self.into_iter().collect::<Vec<_>>();
|
||||
Permutations {
|
||||
list: Rc::new(RefCell::new(list)),
|
||||
|
||||
start: 0,
|
||||
current: 0,
|
||||
len: self.len(),
|
||||
maybe_tail: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Permutations<'a, T> {
|
||||
list: Rc<RefCell<Vec<&'a T>>>,
|
||||
start: usize,
|
||||
current: usize,
|
||||
len: usize,
|
||||
maybe_tail: Option<Box<Permutations<'a, T>>>,
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for Permutations<'a, T> {
|
||||
type Item = Vec<&'a T>;
|
||||
|
||||
fn next(&mut self) -> Option<Vec<&'a T>> {
|
||||
if self.current >= self.len {
|
||||
None
|
||||
} else if self.start + 1 == self.len {
|
||||
self.current += 1;
|
||||
Some(self.list.borrow().clone())
|
||||
} else {
|
||||
if let Some(mut tail) = self.maybe_tail.take() {
|
||||
if let Some(result) = tail.next() {
|
||||
self.maybe_tail = Some(tail);
|
||||
return Some(result);
|
||||
} else {
|
||||
let mut borrow = (*self.list).borrow_mut();
|
||||
// Swapping prev first item back to its original osition
|
||||
for p in self.start..self.current {
|
||||
borrow.swap(p, p + 1);
|
||||
}
|
||||
|
||||
self.current += 1;
|
||||
if self.current >= self.len {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Getting next first item for next iteration
|
||||
for p in (self.start..self.current).rev() {
|
||||
borrow.swap(p, p + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut rest = Box::new(Permutations {
|
||||
len: self.len,
|
||||
list: self.list.clone(),
|
||||
current: self.start + 1,
|
||||
start: self.start + 1,
|
||||
maybe_tail: None,
|
||||
});
|
||||
let result = rest.next();
|
||||
self.maybe_tail = Some(rest);
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_zero() {
|
||||
let input: Vec<i32> = vec![];
|
||||
let result = input.permutate().collect::<Vec<_>>();
|
||||
let expected: Vec<Vec<&i32>> = vec![];
|
||||
assert_eq!(result, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_one() {
|
||||
let input = vec![1];
|
||||
let result = input.permutate().collect::<Vec<_>>();
|
||||
let expected = vec![[&1]];
|
||||
assert_eq!(result, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_two() {
|
||||
let input = vec![1, 2];
|
||||
let result = input.permutate().collect::<Vec<_>>();
|
||||
let expected = vec![[&1, &2], [&2, &1]];
|
||||
assert_eq!(result, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_three() {
|
||||
let input = vec![1, 2, 3];
|
||||
let result = input.permutate().collect::<Vec<_>>();
|
||||
let expected = vec![
|
||||
[&1, &2, &3],
|
||||
[&1, &3, &2],
|
||||
[&2, &1, &3],
|
||||
[&2, &3, &1],
|
||||
[&3, &1, &2],
|
||||
[&3, &2, &1],
|
||||
];
|
||||
assert_eq!(result, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_four() {
|
||||
let input = vec![1, 2, 3, 4];
|
||||
let result = input.permutate().collect::<Vec<_>>();
|
||||
let expected = vec![
|
||||
[&1, &2, &3, &4],
|
||||
[&1, &2, &4, &3],
|
||||
[&1, &3, &2, &4],
|
||||
[&1, &3, &4, &2],
|
||||
[&1, &4, &2, &3],
|
||||
[&1, &4, &3, &2],
|
||||
[&2, &1, &3, &4],
|
||||
[&2, &1, &4, &3],
|
||||
[&2, &3, &1, &4],
|
||||
[&2, &3, &4, &1],
|
||||
[&2, &4, &1, &3],
|
||||
[&2, &4, &3, &1],
|
||||
[&3, &1, &2, &4],
|
||||
[&3, &1, &4, &2],
|
||||
[&3, &2, &1, &4],
|
||||
[&3, &2, &4, &1],
|
||||
[&3, &4, &1, &2],
|
||||
[&3, &4, &2, &1],
|
||||
[&4, &1, &2, &3],
|
||||
[&4, &1, &3, &2],
|
||||
[&4, &2, &1, &3],
|
||||
[&4, &2, &3, &1],
|
||||
[&4, &3, &1, &2],
|
||||
[&4, &3, &2, &1],
|
||||
];
|
||||
assert_eq!(result, expected);
|
||||
}
|
||||
}
|
||||
227
src/common/pos.rs
Normal file
227
src/common/pos.rs
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
use super::{direction::Direction, math::gcd, number::Number};
|
||||
use std::fmt;
|
||||
use std::ops::{Add, Mul, Sub};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
|
||||
pub struct Pos<T>(T, T)
|
||||
where
|
||||
T: Number;
|
||||
|
||||
impl<T> Pos<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
pub fn new(x: T, y: T) -> Pos<T> {
|
||||
Pos(x, y)
|
||||
}
|
||||
|
||||
pub fn x(&self) -> T {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn y(&self) -> T {
|
||||
self.1
|
||||
}
|
||||
|
||||
pub fn max_components(&self, other: &Pos<T>) -> Self {
|
||||
Self(self.0.max(other.0), self.1.max(other.1))
|
||||
}
|
||||
|
||||
pub fn min_components(&self, other: &Pos<T>) -> Self {
|
||||
Self(self.0.min(other.0), self.1.min(other.1))
|
||||
}
|
||||
|
||||
pub fn abs(&self) -> T {
|
||||
self.0.abs() + self.1.abs()
|
||||
}
|
||||
|
||||
pub fn normalize(&self) -> (Pos<T>, T) {
|
||||
if self.0 == T::ZERO && self.1 == T::ZERO {
|
||||
(*self, T::ONE)
|
||||
} else {
|
||||
let ggt = gcd(self.0, self.1);
|
||||
(Pos::new(self.0 / ggt, self.1 / ggt), ggt)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn angle(&self) -> f64 {
|
||||
self.1.as_f64().atan2(self.0.as_f64())
|
||||
}
|
||||
|
||||
pub fn angle2(&self) -> f64 {
|
||||
(-self.0.as_f64().atan2(-self.1.as_f64()) + std::f64::consts::PI)
|
||||
.rem_euclid(2.0 * std::f64::consts::PI)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Display for Pos<T>
|
||||
where
|
||||
T: Number + fmt::Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "({}, {})", self.0, self.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add for Pos<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
type Output = Self;
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Pos(self.0 + rhs.0, self.1 + rhs.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add for &Pos<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
type Output = <Pos<T> as Add<Pos<T>>>::Output;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Pos::add(*self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add<&Pos<T>> for Pos<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
type Output = <Pos<T> as Add<Pos<T>>>::Output;
|
||||
fn add(self, rhs: &Self) -> Self::Output {
|
||||
Pos::add(self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add<Pos<T>> for &Pos<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
type Output = <Pos<T> as Add<Pos<T>>>::Output;
|
||||
fn add(self, rhs: Pos<T>) -> Self::Output {
|
||||
Pos::add(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add<(T, T)> for Pos<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
type Output = Self;
|
||||
fn add(self, rhs: (T, T)) -> Self::Output {
|
||||
Pos(self.0 + rhs.0, self.1 + rhs.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Direction> for Pos<i32> {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Direction) -> Self::Output {
|
||||
Pos::add(self, rhs.as_pos())
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<&Direction> for Pos<i32> {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: &Direction) -> Self::Output {
|
||||
Pos::add(self, rhs.as_pos())
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<&Direction> for &Pos<i32> {
|
||||
type Output = Pos<i32>;
|
||||
|
||||
fn add(self, rhs: &Direction) -> Self::Output {
|
||||
Pos::add(*self, rhs.as_pos())
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Direction> for &Pos<i32> {
|
||||
type Output = Pos<i32>;
|
||||
|
||||
fn add(self, rhs: Direction) -> Self::Output {
|
||||
Pos::add(*self, rhs.as_pos())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Sub for Pos<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
type Output = Pos<T>;
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Pos(self.0 - rhs.0, self.1 - rhs.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Sub<&Self> for Pos<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
type Output = Pos<T>;
|
||||
fn sub(self, rhs: &Self) -> Self::Output {
|
||||
Pos::sub(self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Sub for &Pos<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
type Output = Pos<T>;
|
||||
fn sub(self, rhs: &Pos<T>) -> Self::Output {
|
||||
Pos::sub(*self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Sub<Pos<T>> for &Pos<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
type Output = Pos<T>;
|
||||
fn sub(self, rhs: Pos<T>) -> Self::Output {
|
||||
Pos::sub(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Mul<T> for Pos<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
type Output = Self;
|
||||
fn mul(self, rhs: T) -> Self::Output {
|
||||
Pos(self.0 * rhs, self.1 * rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Mul<T> for &Pos<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
type Output = Pos<T>;
|
||||
fn mul(self, rhs: T) -> Self::Output {
|
||||
Pos::mul(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Mul<&T> for Pos<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
type Output = Pos<T>;
|
||||
fn mul(self, rhs: &T) -> Self::Output {
|
||||
Pos::mul(self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Mul<&T> for &Pos<T>
|
||||
where
|
||||
T: Number,
|
||||
{
|
||||
type Output = Pos<T>;
|
||||
fn mul(self, rhs: &T) -> Self::Output {
|
||||
Pos::mul(*self, *rhs)
|
||||
}
|
||||
}
|
||||
121
src/common/turn.rs
Normal file
121
src/common/turn.rs
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
use super::direction::Direction;
|
||||
use std::{fmt::Display, ops::Add};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Turn {
|
||||
Left,
|
||||
Right,
|
||||
Back,
|
||||
Forward,
|
||||
}
|
||||
|
||||
use Turn::*;
|
||||
|
||||
impl Turn {
|
||||
pub fn to_left(&self) -> Turn {
|
||||
match *self {
|
||||
Left => Back,
|
||||
Back => Right,
|
||||
Right => Forward,
|
||||
Forward => Left,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_right(&self) -> Turn {
|
||||
match *self {
|
||||
Left => Forward,
|
||||
Back => Left,
|
||||
Right => Back,
|
||||
Forward => Right,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_back(&self) -> Turn {
|
||||
match *self {
|
||||
Left => Right,
|
||||
Back => Forward,
|
||||
Right => Left,
|
||||
Forward => Back,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Turn {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match *self {
|
||||
Turn::Left => write!(f, "Left"),
|
||||
Turn::Right => write!(f, "Right"),
|
||||
Turn::Forward => write!(f, "Forward"),
|
||||
Turn::Back => write!(f, "Back"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Turn {
|
||||
type Output = Turn;
|
||||
|
||||
fn add(self, rhs: Turn) -> Self::Output {
|
||||
match rhs {
|
||||
Left => self.to_left(),
|
||||
Back => self.to_back(),
|
||||
Right => self.to_right(),
|
||||
Forward => self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for &Turn {
|
||||
type Output = Turn;
|
||||
|
||||
fn add(self, rhs: &Turn) -> Self::Output {
|
||||
Turn::add(*self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<&Turn> for Turn {
|
||||
type Output = Turn;
|
||||
|
||||
fn add(self, rhs: &Turn) -> Self::Output {
|
||||
Turn::add(self, *rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Turn> for &Turn {
|
||||
type Output = Turn;
|
||||
|
||||
fn add(self, rhs: Turn) -> Self::Output {
|
||||
Turn::add(*self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Direction> for Turn {
|
||||
type Output = Direction;
|
||||
|
||||
fn add(self, rhs: Direction) -> Self::Output {
|
||||
rhs.turn(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Direction> for &Turn {
|
||||
type Output = Direction;
|
||||
|
||||
fn add(self, rhs: Direction) -> Self::Output {
|
||||
rhs.turn(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<&Direction> for Turn {
|
||||
type Output = Direction;
|
||||
|
||||
fn add(self, rhs: &Direction) -> Self::Output {
|
||||
rhs.turn(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<&Direction> for &Turn {
|
||||
type Output = Direction;
|
||||
|
||||
fn add(self, rhs: &Direction) -> Self::Output {
|
||||
rhs.turn(*self)
|
||||
}
|
||||
}
|
||||
20
src/days/day01/mod.rs
Normal file
20
src/days/day01/mod.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
use anyhow::Result;
|
||||
|
||||
use super::template::{DayTrait, ResultType};
|
||||
|
||||
pub struct Day;
|
||||
const DAY_NUMBER: usize = 1;
|
||||
|
||||
impl DayTrait for Day {
|
||||
fn get_day_number(&self) -> usize {
|
||||
DAY_NUMBER
|
||||
}
|
||||
|
||||
fn part1(&self, lines: String) -> Result<ResultType> {
|
||||
Ok(ResultType::NoResult)
|
||||
}
|
||||
|
||||
fn part2(&self, lines: String) -> Result<ResultType> {
|
||||
Ok(ResultType::NoResult)
|
||||
}
|
||||
}
|
||||
20
src/days/day__/mod.rs
Normal file
20
src/days/day__/mod.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
use anyhow::Result;
|
||||
|
||||
use super::template::{Day, ResultType};
|
||||
|
||||
pub struct Day;
|
||||
const DAY_NUMBER: usize = 0;
|
||||
|
||||
impl DayTemplate for Day {
|
||||
fn get_day_number(&self) -> usize {
|
||||
DAY_NUMBER
|
||||
}
|
||||
|
||||
fn part1(&self, lines: String) -> Result<ResultType> {
|
||||
Ok(ResultType::NoResult)
|
||||
}
|
||||
|
||||
fn part2(&self, lines: String) -> Result<ResultType> {
|
||||
Ok(ResultType::NoResult)
|
||||
}
|
||||
}
|
||||
38
src/days/mod.rs
Normal file
38
src/days/mod.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
use anyhow::Result;
|
||||
|
||||
use self::{day01::Day, template::DayTrait};
|
||||
use thiserror::Error;
|
||||
|
||||
pub use template::ResultType;
|
||||
|
||||
mod day01;
|
||||
mod template;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum TemplateError {
|
||||
#[error("Not a valid day number: {0}")]
|
||||
InvalidNumber(usize),
|
||||
}
|
||||
|
||||
pub struct DayProvider {
|
||||
days: Vec<Box<dyn DayTrait>>,
|
||||
}
|
||||
|
||||
impl DayProvider {
|
||||
pub fn create() -> DayProvider {
|
||||
DayProvider {
|
||||
days: vec![Box::new(Day)],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_day(&self, day_num: usize) -> Result<&Box<dyn DayTrait>> {
|
||||
Ok(self
|
||||
.days
|
||||
.get(day_num - 1)
|
||||
.ok_or(TemplateError::InvalidNumber(day_num))?)
|
||||
}
|
||||
|
||||
pub fn get_all_days(&self) -> &[Box<dyn DayTrait>] {
|
||||
&self.days
|
||||
}
|
||||
}
|
||||
14
src/days/template.rs
Normal file
14
src/days/template.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
use anyhow::Result;
|
||||
|
||||
pub enum ResultType {
|
||||
IntResult(i64),
|
||||
StringResult(String),
|
||||
LinesResult(String),
|
||||
NoResult,
|
||||
}
|
||||
|
||||
pub trait DayTrait {
|
||||
fn get_day_number(&self) -> usize;
|
||||
fn part1(&self, lines: String) -> Result<ResultType>;
|
||||
fn part2(&self, lines: String) -> Result<ResultType>;
|
||||
}
|
||||
26
src/macros.rs
Normal file
26
src/macros.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// https://stackoverflow.com/a/28392068
|
||||
#[macro_export]
|
||||
macro_rules! hashmap {
|
||||
() => {
|
||||
::std::collections::HashMap::new()
|
||||
};
|
||||
|
||||
($( $key: expr => $val: expr ),+ $(,)?) => {{
|
||||
let mut map = ::std::collections::HashMap::new();
|
||||
$( map.insert($key, $val); )+
|
||||
map
|
||||
}}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! hashset {
|
||||
() => {
|
||||
::std::collections::HashSet::new()
|
||||
};
|
||||
|
||||
($( $key: expr ),+ $(,)?) => {{
|
||||
let mut set = ::std::collections::HashSet::new();
|
||||
$( set.insert($key); )+
|
||||
set
|
||||
}}
|
||||
}
|
||||
27
src/main.rs
Normal file
27
src/main.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
mod common;
|
||||
mod days;
|
||||
mod macros;
|
||||
use std::error::Error;
|
||||
|
||||
use common::file::read_data;
|
||||
use days::{DayProvider, ResultType};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let day_provider = DayProvider::create();
|
||||
|
||||
//let params = env::args().skip(1).collect::<Vec<_>>();
|
||||
|
||||
let day = day_provider.get_day(1)?;
|
||||
let lines = read_data(day.get_day_number(), "input.txt")?;
|
||||
|
||||
match day.part1(lines)? {
|
||||
ResultType::IntResult(value) => {
|
||||
println!("Day {:02} part {}: {}", day.get_day_number(), 1, value);
|
||||
}
|
||||
ResultType::StringResult(_) => todo!(),
|
||||
ResultType::LinesResult(_) => todo!(),
|
||||
ResultType::NoResult => todo!(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue