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