aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAria Shrimpton <me@aria.rip>2024-02-23 21:01:45 +0000
committerAria Shrimpton <me@aria.rip>2024-02-23 21:01:45 +0000
commit064e358559a99ddff6ee95cae737063357ecb61b (patch)
treea70491dba4f0489e8cf508ad4b1886c89302956f /src
parenteda6a357c5a9f0ea90b906e363d92b551972f819 (diff)
two aoc benchmarks!
Diffstat (limited to 'src')
-rw-r--r--src/tests/Cargo.lock11
-rw-r--r--src/tests/Cargo.toml2
-rw-r--r--src/tests/aoc-2022-08/Cargo.toml17
-rw-r--r--src/tests/aoc-2022-08/benches/main.rs31
-rw-r--r--src/tests/aoc-2022-08/src/lib.rs288
-rw-r--r--src/tests/aoc-2022-08/src/types.pr.rs3
-rw-r--r--src/tests/aoc-2022-09/Cargo.toml17
-rw-r--r--src/tests/aoc-2022-09/benches/main.rs31
-rw-r--r--src/tests/aoc-2022-09/src/lib.rs2126
-rw-r--r--src/tests/aoc-2022-09/src/types.pr.rs7
10 files changed, 2532 insertions, 1 deletions
diff --git a/src/tests/Cargo.lock b/src/tests/Cargo.lock
index 3b1b134..244aab4 100644
--- a/src/tests/Cargo.lock
+++ b/src/tests/Cargo.lock
@@ -21,7 +21,16 @@ dependencies = [
]
[[package]]
-name = "aoc-2022-05"
+name = "aoc-2022-08"
+version = "0.1.0"
+dependencies = [
+ "criterion",
+ "primrose-library",
+ "rand",
+]
+
+[[package]]
+name = "aoc-2022-09"
version = "0.1.0"
dependencies = [
"criterion",
diff --git a/src/tests/Cargo.toml b/src/tests/Cargo.toml
index d206105..c405635 100644
--- a/src/tests/Cargo.toml
+++ b/src/tests/Cargo.toml
@@ -2,6 +2,8 @@
resolver = "2"
members = [
"aoc-2021-09",
+ "aoc-2022-08",
+ "aoc-2022-09",
"example_sets",
"example_stack",
"prime_sieve"
diff --git a/src/tests/aoc-2022-08/Cargo.toml b/src/tests/aoc-2022-08/Cargo.toml
new file mode 100644
index 0000000..449bbdb
--- /dev/null
+++ b/src/tests/aoc-2022-08/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "aoc-2022-08"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+rand = { workspace = true }
+primrose-library = { path = "../../crates/library" }
+
+[dev-dependencies]
+criterion = { workspace = true }
+
+[[bench]]
+name = "main"
+harness = false
diff --git a/src/tests/aoc-2022-08/benches/main.rs b/src/tests/aoc-2022-08/benches/main.rs
new file mode 100644
index 0000000..ceab4a8
--- /dev/null
+++ b/src/tests/aoc-2022-08/benches/main.rs
@@ -0,0 +1,31 @@
+use aoc_2022_08::HeightMap;
+use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion};
+use rand::{rngs::StdRng, SeedableRng};
+
+fn run_benches(c: &mut Criterion) {
+ let mut rng = StdRng::seed_from_u64(42);
+ for size in [100, 500, 1000, 2000].iter() {
+ c.bench_with_input(BenchmarkId::new("part1", size), size, |b, &n| {
+ b.iter_batched_ref(
+ || HeightMap::gen(&mut rng, n),
+ |map| map.part1(),
+ BatchSize::SmallInput,
+ )
+ });
+
+ c.bench_with_input(BenchmarkId::new("part2", size), size, |b, &n| {
+ b.iter_batched_ref(
+ || HeightMap::gen(&mut rng, n),
+ |map| map.part2(),
+ BatchSize::SmallInput,
+ )
+ });
+ }
+}
+
+criterion_group!(
+ name = benches;
+ config = Criterion::default().sample_size(10);
+ targets = run_benches
+);
+criterion_main!(benches);
diff --git a/src/tests/aoc-2022-08/src/lib.rs b/src/tests/aoc-2022-08/src/lib.rs
new file mode 100644
index 0000000..9f60ac8
--- /dev/null
+++ b/src/tests/aoc-2022-08/src/lib.rs
@@ -0,0 +1,288 @@
+#![feature(type_alias_impl_trait)]
+
+use primrose_library::traits::*;
+use rand::{rngs::StdRng, Rng};
+
+mod types;
+use types::*;
+
+pub struct HeightMap {
+ map: Map<(usize, usize), usize>,
+ cols: usize,
+ rows: usize,
+}
+
+impl HeightMap {
+ pub fn new(map: Map<(usize, usize), usize>, cols: usize, rows: usize) -> Self {
+ Self { map, cols, rows }
+ }
+
+ pub fn gen(rng: &mut StdRng, n: usize) -> Self {
+ let mut map = Map::default();
+ for x in 0..n {
+ for y in 0..n {
+ map.insert((x, y), rng.gen_range(0..10));
+ }
+ }
+
+ Self {
+ map,
+ cols: n,
+ rows: n,
+ }
+ }
+
+ pub fn part1(&self) -> usize {
+ let mut grid = Map::default();
+
+ (0..self.rows).for_each(|grid_row| {
+ self.check_vis_along_run(
+ (0..self.cols).map(move |grid_col| (grid_row, grid_col)),
+ &mut grid,
+ );
+ self.check_vis_along_run(
+ (0..self.cols)
+ .rev()
+ .map(move |grid_col| (grid_row, grid_col)),
+ &mut grid,
+ )
+ });
+ (0..self.cols).for_each(|grid_col| {
+ self.check_vis_along_run(
+ (0..self.rows).map(move |grid_row| (grid_row, grid_col)),
+ &mut grid,
+ );
+ self.check_vis_along_run(
+ (0..self.rows)
+ .rev()
+ .map(move |grid_row| (grid_row, grid_col)),
+ &mut grid,
+ )
+ });
+
+ grid.iter().filter(|(_, v)| **v).count()
+ }
+
+ pub fn part2(&self) -> usize {
+ let mut grid = Map::default();
+
+ (0..self.rows).for_each(|grid_row| {
+ self.vis_score_along_run(
+ (0..self.cols).map(move |grid_col| (grid_row, grid_col)),
+ &mut grid,
+ );
+ self.vis_score_along_run(
+ (0..self.cols)
+ .rev()
+ .map(move |grid_col| (grid_row, grid_col)),
+ &mut grid,
+ )
+ });
+ (0..self.cols).for_each(|grid_col| {
+ self.vis_score_along_run(
+ (0..self.rows).map(move |grid_row| (grid_row, grid_col)),
+ &mut grid,
+ );
+ self.vis_score_along_run(
+ (0..self.rows)
+ .rev()
+ .map(move |grid_row| (grid_row, grid_col)),
+ &mut grid,
+ )
+ });
+
+ *grid.iter().map(|(_, score)| score).max().unwrap()
+ }
+
+ fn check_vis_along_run(
+ &self,
+ mut run: impl Iterator<Item = (usize, usize)>,
+ vis_grid: &mut Map<(usize, usize), bool>,
+ ) {
+ let mut curr_height = {
+ let (row_idx, col_idx) = run.next().unwrap();
+
+ vis_grid.insert((row_idx, col_idx), true);
+
+ self.map.get(&(row_idx, col_idx)).unwrap()
+ };
+ for (row_idx, col_idx) in run {
+ let height = self.map.get(&(row_idx, col_idx)).unwrap();
+ if height > curr_height {
+ curr_height = height;
+ vis_grid.insert((row_idx, col_idx), true);
+ }
+ }
+ }
+
+ fn vis_score_along_run(
+ &self,
+ run: impl Iterator<Item = (usize, usize)>,
+ vis_grid: &mut Map<(usize, usize), usize>,
+ ) {
+ let mut next_values = [0; 10];
+ for (row_idx, col_idx) in run {
+ let height = *self.map.get(&(row_idx, col_idx)).unwrap();
+ vis_grid.insert(
+ (row_idx, col_idx),
+ vis_grid.get(&(row_idx, col_idx)).unwrap_or(&1) * next_values[height as usize],
+ );
+
+ for (val, score) in next_values.iter_mut().enumerate() {
+ *score = if *score == 0 || val > height as usize {
+ *score + 1
+ } else {
+ 1
+ };
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ fn parse_input(input: &str) -> HeightMap {
+ let mut grid: Vec<Vec<_>> = input
+ .lines()
+ .map(|x| {
+ x.chars()
+ .map(|x| x.to_digit(10).unwrap() as usize)
+ .collect()
+ })
+ .collect();
+
+ let (cols, rows) = (grid.len(), grid[0].len());
+ HeightMap::new(
+ grid.into_iter()
+ .enumerate()
+ .flat_map(|(c, vs)| vs.into_iter().enumerate().map(move |(r, v)| ((r, c), v)))
+ .collect(),
+ cols,
+ rows,
+ )
+ }
+
+ #[test]
+ fn test_small() {
+ let map = parse_input(SMALL_INPUT);
+
+ assert_eq!(map.part1(), 21, "part 1");
+ assert_eq!(map.part2(), 8, "part 2");
+ }
+
+ #[test]
+ fn test_large() {
+ let map = parse_input(LARGE_INPUT);
+
+ assert_eq!(map.part1(), 1859, "part 1");
+ assert_eq!(map.part2(), 332640, "part 2");
+ }
+
+ const SMALL_INPUT: &str = "30373
+25512
+65332
+33549
+35390";
+
+ const LARGE_INPUT: &str = "100221200032023210231132410224121421011444302143121341425413411104320412140011030313333000220101112
+112202123021003133332142233323404332315445153153433313154424232233100410424422313323031220233011010
+011002203101130221201112041212404433424255343232213155531144333552214422033044404110303133013102011
+121111233130221221224141101130304514242212243115142242515311345141411232002244120020312220212230110
+202100121002031143312404331332151115114223331225243515233534114435141142242331404201300323113201222
+100021031220304112421404010433522123452131415552421124411431352333224213401342034313144213120020201
+021322001301122441210433214253425221315242313124453313231211152111255512555241432402123122313012220
+102112011033320244100140342511211253345112333255454336534252113251451114422242001024234213333302113
+132330330131203301420044434343145455152343343332352256556523331132212421445241301141320302112302033
+023322331300043142101542252542114115526343233433362336426522664522241145133152512411103311030301102
+322330231444114143321233414112534365353654433452553436246452265364531225351151151443033412041221031
+012321024142334102115451552132455663265336555636436352252325655253353135241221433212232340024232223
+221313322104114224452245113321425622464562645423543656226366436236366342211223552335030321004420030
+302122222422424154133544345544642565622466255242453626235542536222223332315231425444102032032122210
+231133324324321454452534322652236666662342666356747472523623223666552524234541221123331342040102130
+210020241002443524243413355654666622264244543546744763764772255422554656666314534534123124422233033
+131014422414243524255521645632356643223334677577673636537354355442655654452624241512525104443021123
+033403033322215332325412643445254652373556346633545346456537636346453566423552515332123444244330202
+113344141003242351252543634555644673346454333353676654553676643646433222324426451413334115040003434
+001230324131334423146345655352634367445777457543465476454557474433574665556354335235344443340423222
+023244011152423313324656433232434376576677545673553663364375673667467762442263336432523122511002314
+332301042252442131435255344627377653437674735733643774776343344336573375563254444441344341324221021
+334402434231342254423323453655434536773776677775884478878536663447374436723326532641314353455441013
+044342001441534222364463342375566346646375448766484784546577575636346474474644262426334344414332232
+244130421523351525564645423735465337565786567845848555466788768336334436366242664256515555351430211
+024000015535214533542634654746473565564746464865758448476545478886463346677543522243553255453421422
+314442345152523644625564463763377468476865877455764845786446587486747367443753366233446432411453102
+403000534214215322266566347455673478488876664657887477647485758778655633543776436463262445335553104
+214212342251136353523565555447738584887668745867475764748577568657667634663643424344644433342131210
+114243351433156335446363677757688866574765658676758768885858567668678654677476636444464535114243322
+042431434431524463423673765353776887875745588995877855658794867476588746757553543264362224534141501
+304145214121645333564636455447886886885877698565995687887577645687776748545456743542356254233125332
+311331441555242635254434657548756467747985795655656986779866797467565645743544356362633255252311252
+031543523352343526446775553558756644695895589667775569668758957957865578854634733662645643413532141
+132341313125236444736663666564678758797867656955877956887969998885558485468743564462266455525122534
+232352541122446346437676338577648848957677569986976865585987699675564746846753677543463556334143154
+131122222556542463647436455856664477857588875699877776998998877775547558467576475473336454313145311
+323351431635225653436555578777465655659599588676899686697589579979794858655753634546556432442445431
+112233531246445655746654878675766685587986697767667968689785797779856485864853546544452346664152533
+441132313625454663535377687586749896896879888977889996877688569867885777667647465574425232431545142
+111111115654356235746577756578775857666766677988789889966967668865796774447665533366756456656544233
+444252452345444655545775744655786859687696799777689978899776989678787767656644764567745346442533321
+243154434235433653434536454678865969596896986887966776669777699889978977488475776367633466352332221
+011224342565624633533747786446558897878876986776988967899998768656967776846856453564345652346143322
+255513254542435577753688664747776969589697768898799988986867978878755798466564874553774433546435555
+531145456554225737775485576687555769699797776897798787876797978897659996788865775465774226546153322
+442533162233465666667386864866899875679896679977778999979877877678659766555575467467575463636255152
+222435446522644555737767458468785999996898997999997899997696787896667589475664463563534454563214511
+114215466262527345675785857555678986776986688778978997878888897668987577564444436473675662336222114
+311512225352354555566787445776557865789678977797999877977997668696567599676867476737435246555451342
+421334156234643445446758455875576958787887988878779897788997898799755999778447566575637255446655255
+125142454452645575467547748465958777796899699889787977799988676968695967468678746455475566543545252
+541132356636257333356646477666678579897866699899788787979798698767778866447456666337455556433533121
+445221446426223553556485485665966685998799898899888979878767787768599876575858773334364454262234144
+525513243446634357764748776668756995869697898999998977878876699967659655845786665456752546565235543
+242413525434333433563775775447556666686688668777988879987769688978675587574767756766775543642424544
+412342456656355557547778657458878557979677769688789988888698966858589758586466663545734543236112142
+032124116534555566453646756448767766598786768796678968666697769566795585867844377364542222543543144
+441552534565633333336768485544889775969797879987999896968699678699996564658774473347764463533212333
+014334316443544233545737775568867776768987678899897898878766665677857876456548645543346266424252231
+325452232353463343766655746785669595566587987667687678677799977887575876564756446554733252464333125
+235313513563466536365543548586589569868987876898987896869998585688675666574767347633723365564532532
+131124335362654376773466855768859778665998766696796869779797998996756554465587764356742455564311133
+404343421445554355553366675767758576985659996766997797776657667759678485655666467335666422541134511
+312435242152464645537634574874657856986757676888867976856999658767747446588655574536622635614544141
+421213311564223563546534557645478659967967597665866686567866969995544678685456636652623544254232541
+132543425342352422657766376447447764765888966699888885566685795585666784565673355564333242524212311
+302331311115224263643775435787778644568655576569775967656567865844846487483657355742644444135343420
+041452122556655345467337433384557668665698956966665778595596897875676866777643767426226256541552542
+001153531411446425663655546568788568547498779978887586997587766584748746467645733632336523244335133
+123051345234564624353634333467884847454768797578698856589577675458586647637643536245652422355524202
+214113222524335633455447435736745665746584587959858876858874857758585653673436654525322545251233013
+021144513155424252656646455733574856574765868885444777566868748678578533774364735645364444331342200
+431211353221243564244634645643745486685475647654778847854578477454755346753436664555663251321120041
+102242514555444466436542457333634684684544446466456474474878867475656557554754542332232132452524043
+200242332413522436266226554463734737646765775855488765445547588777757737677755424453334532353422100
+241403131545213353553445445364457564356667686685588677677558646353463653546344554664534324351240301
+301440432323554425253552526545676357456386755454585758845784455753574633345364523362222213444203344
+400414313234154322364222535473637766337743638757685754757674654744437433364534662421344453452322134
+001422404442155511452332334335755446737463367654664454733735476754666354564255333335224221543430334
+013133011342545224454646324324367366635745635763574765656353733477656734233264226223311131330044444
+022111144023553523455232562425243646553465743577436756535447437664477626354554366335454123020240144
+230102421342115344242436455624362236434554736674746476337464537776466226562546332255133444243414211
+310212333434541233141416642226456363654747545733335637756546635676334542222542352332333111404102411
+030003333221133245434443565522626652624656376645357754463575744634634423652323553532531310030201001
+030023023423212441345154346256652364345653336653654434533772655254643423443531524513545021442402202
+010024230302312531312212123243243535655425464532567572556636535233466523565345454255552242044131211
+130202311443320415524153221422665546664426662533646433452623222644336564221342333223401212213001023
+211130021411240202155121122543663636242422664454425543522663356225322252323355231113031230011332201
+230111130130413041333532222115236464446226463566236266425464353655322253315233224353341443240012002
+001102313010120320313214115143353526263356666453526645336434636323231453123112522432413131410213301
+311322021312344404314245522512231315322442523625223426563542243513444315534543320140204003013302020
+223031222001210200323443112312552151222246552363556365653546423412555511231131443113420044113212123
+111320133131221133413343355424321432514225151443636656325513423253211421224222110014232232113301221
+010321023321033244303433322535144241341415221344311331433254245144245522341332333121010301003132230
+211110020103304321442134112151523315235121445254445414513445335245114524313310001304234213223211022
+111122023302320302411300133103134411221211352515252145115412111545311213404224233340430222022031002
+211120112212331032422141144010135514321521155344453422441443412441135423402430103212201303331211201
+010021021121120020020341010431334133122452331123312352352313123235203300324210330421332333020210112";
+}
diff --git a/src/tests/aoc-2022-08/src/types.pr.rs b/src/tests/aoc-2022-08/src/types.pr.rs
new file mode 100644
index 0000000..5e3950c
--- /dev/null
+++ b/src/tests/aoc-2022-08/src/types.pr.rs
@@ -0,0 +1,3 @@
+/*SPEC*
+type Map<K,V> = {c impl (Mapping) | true}
+ *ENDSPEC*/
diff --git a/src/tests/aoc-2022-09/Cargo.toml b/src/tests/aoc-2022-09/Cargo.toml
new file mode 100644
index 0000000..f806c9c
--- /dev/null
+++ b/src/tests/aoc-2022-09/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "aoc-2022-09"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+rand = { workspace = true }
+primrose-library = { path = "../../crates/library" }
+
+[dev-dependencies]
+criterion = { workspace = true }
+
+[[bench]]
+name = "main"
+harness = false
diff --git a/src/tests/aoc-2022-09/benches/main.rs b/src/tests/aoc-2022-09/benches/main.rs
new file mode 100644
index 0000000..bd5f92c
--- /dev/null
+++ b/src/tests/aoc-2022-09/benches/main.rs
@@ -0,0 +1,31 @@
+use aoc_2022_09::{gen_moves, part1, part2};
+use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion};
+use rand::{rngs::StdRng, SeedableRng};
+
+fn run_benches(c: &mut Criterion) {
+ let mut rng = StdRng::seed_from_u64(42);
+ for size in [100, 1000, 2000, 10_000, 50_000].iter() {
+ c.bench_with_input(BenchmarkId::new("part1", size), size, |b, &n| {
+ b.iter_batched_ref(
+ || gen_moves(&mut rng, n).collect::<Vec<_>>(),
+ |moves| part1(moves.iter()),
+ BatchSize::SmallInput,
+ )
+ });
+
+ c.bench_with_input(BenchmarkId::new("part2", size), size, |b, &n| {
+ b.iter_batched_ref(
+ || gen_moves(&mut rng, n).collect::<Vec<_>>(),
+ |moves| part2(moves.iter()),
+ BatchSize::SmallInput,
+ )
+ });
+ }
+}
+
+criterion_group!(
+ name = benches;
+ config = Criterion::default().sample_size(10);
+ targets = run_benches
+);
+criterion_main!(benches);
diff --git a/src/tests/aoc-2022-09/src/lib.rs b/src/tests/aoc-2022-09/src/lib.rs
new file mode 100644
index 0000000..9bb7364
--- /dev/null
+++ b/src/tests/aoc-2022-09/src/lib.rs
@@ -0,0 +1,2126 @@
+#![feature(type_alias_impl_trait)]
+
+use primrose_library::traits::*;
+use rand::Rng;
+use std::cmp::min;
+
+mod types;
+use types::*;
+
+pub fn part1<'a>(moves: impl Iterator<Item = &'a Move>) -> usize {
+ visited_from_moves::<2>(moves)
+}
+
+pub fn part2<'a>(moves: impl Iterator<Item = &'a Move>) -> usize {
+ visited_from_moves::<10>(moves)
+}
+
+fn visited_from_moves<'a, const N: usize>(moves: impl Iterator<Item = &'a Move>) -> usize {
+ let mut tail_visited = Set::default();
+ tail_visited.insert((0, 0));
+ let mut knots = [(0, 0); N];
+ for mv in moves {
+ make_move(mv, &mut knots, &mut tail_visited);
+ }
+
+ tail_visited.len()
+}
+
+fn make_move(mv: &Move, knots: &mut [Pos], tail_visited: &mut Set<Pos>) {
+ let (dir, count) = mv;
+
+ for _ in 0..*count {
+ // Move head of rope
+ match dir {
+ Direction::Up => knots[0].1 += 1,
+ Direction::Down => knots[0].1 -= 1,
+ Direction::Right => knots[0].0 += 1,
+ Direction::Left => knots[0].0 -= 1,
+ };
+
+ for front_idx in 0..knots.len() - 1 {
+ let (fx, fy) = knots[front_idx];
+ let (bx, by) = &mut knots[front_idx + 1];
+ let (dx, dy) = (fx - *bx, fy - *by);
+ if (dx.abs() == 2 && dy == 0) || (dy.abs() == 2 && dx == 0) || (dy.abs() + dx.abs() > 2)
+ {
+ *bx += (dx.signum()) * min(dx.abs(), 1);
+ *by += (dy.signum()) * min(dy.abs(), 1);
+ }
+ }
+ tail_visited.insert(knots[knots.len() - 1]);
+ }
+}
+
+pub type Pos = (i32, i32);
+pub type Move = (Direction, u8);
+
+#[derive(Debug, Clone, Copy)]
+pub enum Direction {
+ Up,
+ Down,
+ Left,
+ Right,
+}
+
+pub fn gen_moves<R: Rng>(rng: &mut R, n: usize) -> impl Iterator<Item = Move> + '_ {
+ (0..n).map(|_| {
+ let dir = match rng.gen_range(0..4) {
+ 0 => Direction::Up,
+ 1 => Direction::Down,
+ 2 => Direction::Left,
+ 3 => Direction::Right,
+ _ => unreachable!(),
+ };
+ let count = rng.gen();
+
+ (dir, count)
+ })
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::*;
+
+ fn parse_moves(input: &str) -> impl Iterator<Item = Move> + '_ {
+ input.lines().map(|x| {
+ let (dir, count) = x.split_once(' ').unwrap();
+ let count = count.parse().unwrap();
+
+ (
+ match dir {
+ "L" => Direction::Left,
+ "R" => Direction::Right,
+ "U" => Direction::Up,
+ "D" => Direction::Down,
+ _ => panic!("invalid direction, {}", dir),
+ },
+ count,
+ )
+ })
+ }
+
+ #[test]
+ fn test_small() {
+ let moves = parse_moves(SMALL_INPUT).collect::<Vec<_>>();
+ assert_eq!(part1(moves.iter()), 13, "part 1");
+ assert_eq!(part2(moves.iter()), 1, "part 2");
+ }
+
+ #[test]
+ fn test_large() {
+ let moves = parse_moves(LARGE_INPUT).collect::<Vec<_>>();
+ assert_eq!(part1(moves.iter()), 6236, "part 1");
+ assert_eq!(part2(moves.iter()), 2449, "part 2");
+ }
+
+ const SMALL_INPUT: &str = "R 4
+U 4
+L 3
+D 1
+R 4
+D 1
+L 5
+R 2";
+
+ const LARGE_INPUT: &str = "L 1
+R 1
+U 1
+R 1
+L 1
+U 2
+L 2
+R 1
+U 2
+D 2
+R 2
+D 2
+R 1
+U 1
+R 2
+L 1
+D 1
+L 2
+R 1
+D 1
+R 1
+U 1
+D 1
+R 1
+D 1
+R 1
+D 2
+L 2
+D 1
+R 2
+L 1
+R 2
+U 2
+R 1
+U 1
+D 2
+U 1
+R 1
+D 1
+R 2
+D 1
+L 2
+R 1
+U 1
+L 1
+U 1
+D 1
+U 1
+D 1
+L 1
+D 1
+R 1
+D 2
+L 1
+D 1
+L 1
+D 1
+R 1
+U 1
+D 2
+R 1
+D 1
+L 2
+D 2
+U 1
+L 1
+U 1
+L 1
+R 2
+U 1
+L 1
+D 1
+R 2
+L 2
+U 1
+D 2
+R 1
+U 1
+R 2
+L 2
+U 1
+L 2
+R 2
+D 1
+L 1
+R 1
+D 2
+L 2
+U 1
+L 2
+R 1
+U 2
+D 1
+U 2
+D 2
+L 2
+D 1
+R 1
+L 2
+R 2
+L 2
+R 2
+L 2
+R 2
+L 1
+U 1
+R 2
+U 1
+D 1
+R 2
+D 2
+R 2
+D 2
+L 2
+R 2
+U 3
+R 1
+U 3
+D 3
+U 1
+L 2
+D 2
+R 3
+D 1
+R 3
+U 1
+L 3
+R 3
+L 1
+U 3
+R 3
+U 3
+R 3
+U 2
+L 2
+D 2
+R 3
+U 2
+L 2
+U 3
+L 2
+R 1
+U 3
+R 2
+U 3
+L 2
+R 2
+U 1
+L 3
+R 3
+L 3
+R 2
+L 3
+D 3
+L 2
+D 1
+R 1
+D 3
+U 3
+R 3
+D 2
+L 2
+D 2
+R 1
+D 1
+U 3
+R 1
+U 2
+L 3
+U 3
+L 2
+D 1
+L 3
+R 2
+D 2
+L 2
+D 3
+L 3
+U 1
+D 3
+U 3
+L 3
+R 2
+D 2
+R 3
+D 2
+R 3
+U 2
+R 1
+L 2
+R 2
+L 1
+D 3
+U 2
+L 2
+U 3
+L 1
+D 1
+L 2
+R 3
+L 1
+D 2
+U 1
+D 3
+U 1
+D 3
+L 1
+U 1
+R 3
+L 2
+U 3
+L 3
+U 1
+L 2
+D 1
+R 2
+L 1
+R 2
+L 2
+D 3
+U 2
+D 2
+U 3
+L 4
+D 4
+R 3
+D 4
+R 1
+L 2
+U 2
+R 1
+U 4
+D 4
+U 4
+D 4
+R 4
+L 2
+U 3
+D 1
+R 4
+D 2
+L 2
+D 1
+L 4
+R 3
+U 2
+D 4
+U 3
+R 3
+L 1
+R 1
+L 2
+D 4
+U 2
+R 1
+L 3
+D 3
+R 4
+U 2
+L 1
+D 3
+R 4
+D 2
+U 3
+D 1
+L 2
+D 2
+R 2
+D 3
+R 2
+U 2
+R 1
+L 1
+U 2
+D 2
+U 3
+D 1
+U 3
+D 1
+R 4
+D 2
+U 1
+L 3
+D 4
+R 3
+D 4
+U 2
+D 1
+R 2
+U 3
+L 3
+D 1
+U 2
+L 3
+D 1
+L 3
+D 1
+U 1
+D 4
+R 1
+D 4
+L 2
+R 3
+D 4
+R 2
+L 3
+D 4
+U 3
+L 4
+U 1
+L 3
+R 1
+L 1
+D 2
+L 1
+U 2
+D 3
+L 1
+R 4
+L 1
+D 2
+U 2
+L 3
+U 3
+L 1
+R 4
+U 3
+D 3
+R 1
+L 2
+R 4
+U 2
+L 3
+U 4
+L 2
+R 4
+D 5
+U 1
+R 2
+D 5
+L 5
+R 1
+D 3
+U 3
+L 3
+U 5
+R 1
+D 1
+R 3
+U 3
+D 1
+R 1
+L 4
+R 1
+L 3
+U 4
+L 3
+R 5
+D 3
+R 2
+U 1
+R 2
+D 2
+L 4
+R 2
+U 1
+L 3
+D 4
+R 4
+L 1
+R 3
+U 3
+D 2
+R 3
+D 3
+U 1
+L 5
+U 1
+L 5
+R 5
+D 1
+U 1
+R 5
+D 4
+L 1
+R 4
+L 5
+D 5
+L 2
+D 1
+L 3
+D 5
+L 4
+R 4
+D 1
+U 1
+D 4
+U 1
+R 4
+L 2
+D 4
+U 1
+L 3
+R 3
+L 3
+R 3
+D 2
+R 3
+L 5
+R 1
+L 1
+R 3
+D 5
+U 5
+L 3
+U 3
+L 5
+D 3
+L 2
+U 5
+D 5
+U 5
+D 4
+U 4
+R 5
+U 3
+D 5
+R 1
+L 4
+U 1
+L 4
+R 2
+D 1
+U 4
+L 5
+D 2
+R 1
+U 1
+R 3
+U 1
+R 4
+U 4
+L 1
+R 2
+U 5
+D 2
+L 5
+U 4
+D 2
+R 1
+D 1
+U 6
+D 5
+L 4
+U 5
+R 1
+L 3
+D 2
+R 3
+U 6
+L 2
+R 6
+D 1
+R 5
+D 1
+L 1
+R 2
+L 4
+R 3
+L 4
+D 6
+R 5
+U 1
+L 4
+D 2
+L 2
+D 3
+L 2
+D 5
+R 4
+D 3
+L 2
+D 4
+R 1
+U 5
+L 5
+U 5
+D 2
+L 3
+D 4
+L 3
+U 4
+L 4
+U 6
+D 6
+U 4
+R 2
+D 3
+U 1
+R 4
+D 3
+R 1
+D 2
+R 3
+L 2
+D 2
+L 4
+D 5
+L 5
+R 2
+L 1
+R 2
+D 2
+R 4
+U 4
+R 5
+L 4
+D 1
+L 6
+R 4
+D 2
+R 6
+L 6
+D 3
+R 2
+D 2
+U 4
+R 2
+U 2
+L 2
+R 5
+D 5
+U 6
+D 6
+L 5
+R 1
+U 3
+L 1
+D 1
+U 2
+R 5
+L 2
+D 2
+U 4
+R 2
+D 2
+U 1
+D 2
+R 3
+L 6
+U 1
+D 6
+R 3
+D 6
+R 1
+D 7
+R 7
+L 4
+R 4
+D 5
+U 6
+R 2
+L 3
+R 5
+L 5
+U 6
+D 3
+U 5
+D 3
+U 5
+R 7
+L 5
+U 7
+L 6
+U 5
+D 1
+L 7
+U 6
+L 3
+D 1
+L 6
+U 4
+D 1
+U 1
+R 1
+L 3
+D 6
+L 6
+R 3
+D 3
+U 2
+R 1
+D 6
+U 7
+R 6
+L 4
+R 4
+D 7
+R 1
+D 5
+U 6
+D 4
+R 6
+L 2
+U 4
+D 7
+R 5
+D 6
+U 7
+R 6
+D 6
+U 1
+D 4
+L 2
+U 2
+R 7
+U 1
+L 1
+U 1
+L 7
+D 3
+U 5
+D 5
+L 1
+D 4
+L 3
+U 7
+L 6
+R 7
+U 6
+R 1
+L 3
+R 1
+D 3
+L 7
+R 4
+L 3
+D 2
+L 7
+D 2
+R 5
+L 7
+D 6
+L 6
+D 3
+L 3
+D 5
+U 3
+L 5
+R 6
+L 1
+U 5
+R 4
+U 2
+D 3
+R 5
+L 4
+U 5
+D 7
+R 1
+L 3
+U 5
+D 3
+L 6
+R 2
+L 2
+U 6
+R 3
+U 7
+R 3
+D 1
+L 2
+U 7
+L 6
+D 3
+L 8
+R 6
+D 3
+L 5
+R 5
+U 5
+R 8
+D 7
+R 7
+U 8
+L 5
+D 6
+R 6
+L 6
+D 8
+U 1
+R 4
+L 3
+R 6
+L 6
+D 5
+R 4
+D 8
+L 4
+R 4
+D 3
+L 2
+U 6
+L 8
+R 1
+U 5
+L 4
+D 8
+R 6
+D 5
+U 6
+L 5
+R 1
+L 8
+U 7
+R 6
+D 4
+U 2
+D 8
+U 3
+D 7
+R 6
+D 8
+R 8
+U 8
+D 7
+L 3
+D 4
+L 1
+U 4
+R 4
+U 2
+D 6
+R 1
+D 8
+R 2
+D 4
+R 5
+L 1
+R 7
+L 3
+D 1
+U 1
+R 7
+U 5
+D 1
+L 2
+R 8
+D 8
+L 5
+U 8
+D 4
+L 5
+D 3
+U 2
+L 7
+R 2
+L 5
+U 3
+R 3
+U 6
+R 6
+D 4
+R 3
+U 4
+D 5
+U 6
+R 3
+L 4
+R 5
+L 4
+R 8
+U 6
+L 6
+U 1
+L 5
+R 3
+U 1
+D 5
+U 8
+R 1
+L 2
+R 3
+L 8
+U 6
+L 4
+R 3
+L 3
+R 7
+L 9
+D 5
+R 8
+L 5
+U 7
+D 7
+R 6
+L 8
+U 4
+D 5
+R 8
+L 4
+R 8
+U 9
+R 9
+L 8
+D 9
+L 9
+D 6
+R 1
+L 8
+U 4
+L 6
+U 5
+R 9
+L 5
+D 6
+R 9
+D 9
+U 6
+L 1
+U 8
+L 7
+R 9
+U 4
+R 6
+U 1
+R 5
+U 5
+L 4
+R 4
+D 7
+L 6
+U 3
+R 9
+U 1
+L 6
+U 5
+L 5
+U 2
+L 3
+U 2
+D 6
+R 8
+L 5
+U 4
+D 4
+R 4
+D 6
+L 8
+U 9
+R 4
+L 3
+D 1
+U 2
+D 5
+U 3
+D 3
+L 2
+D 3
+L 4
+D 5
+L 9
+D 9
+U 2
+D 8
+R 4
+L 8
+R 9
+D 7
+L 3
+D 2
+R 2
+L 4
+D 7
+R 6
+D 8
+R 9
+L 3
+D 5
+U 1
+L 8
+D 6
+R 9
+U 6
+R 9
+D 6
+L 9
+U 5
+D 10
+L 4
+U 10
+R 3
+U 7
+D 4
+L 3
+R 8
+L 4
+U 10
+R 8
+L 10
+U 8
+R 5
+L 8
+U 6
+L 5
+D 7
+L 6
+U 6
+L 9
+R 8
+U 6
+D 7
+L 10
+R 2
+D 7
+L 8
+U 5
+L 2
+D 2
+U 7
+D 6
+R 7
+D 2
+U 3
+R 10
+D 2
+U 6
+D 6
+L 8
+D 2
+L 2
+D 10
+L 2
+D 1
+L 10
+D 6
+R 6
+L 7
+D 9
+R 2
+D 5
+U 2
+R 4
+L 4
+D 1
+L 3
+R 10
+U 9
+L 4
+D 10
+L 10
+D 4
+U 2
+R 1
+L 4
+D 6
+U 2
+L 6
+R 4
+U 1
+L 9
+R 7
+L 8
+U 5
+R 1
+D 6
+L 4
+U 9
+D 1
+L 5
+R 10
+D 4
+L 6
+U 8
+R 4
+L 5
+D 10
+R 8
+D 8
+R 4
+D 5
+R 7
+L 10
+D 3
+R 1
+L 4
+R 8
+L 10
+D 2
+L 3
+D 6
+L 8
+R 10
+L 2
+D 8
+R 5
+L 8
+D 1
+U 6
+D 11
+U 7
+L 1
+U 6
+R 9
+L 8
+R 5
+U 9
+D 5
+L 10
+U 6
+L 3
+D 4
+U 6
+D 10
+L 2
+D 9
+L 5
+R 8
+D 1
+R 1
+U 1
+D 4
+R 4
+U 6
+L 9
+U 7
+R 11
+L 8
+D 3
+R 9
+L 11
+U 9
+L 4
+D 10
+U 9
+L 7
+R 9
+U 1
+R 8
+U 4
+L 3
+U 2
+D 7
+R 6
+U 1
+D 10
+U 9
+R 6
+L 6
+D 4
+U 3
+L 10
+R 10
+U 6
+R 8
+L 9
+R 2
+D 7
+R 4
+U 6
+R 2
+L 4
+D 1
+L 10
+U 9
+R 11
+U 11
+R 1
+D 5
+L 8
+U 3
+R 1
+U 4
+D 10
+U 6
+L 8
+R 4
+L 7
+R 8
+D 3
+L 9
+U 4
+L 6
+R 2
+D 2
+U 9
+D 6
+R 8
+L 2
+U 7
+L 2
+R 8
+L 7
+D 5
+R 10
+U 5
+L 10
+U 6
+R 8
+U 9
+L 7
+D 11
+U 10
+L 4
+D 5
+R 4
+L 7
+U 5
+D 8
+R 6
+D 9
+L 4
+U 9
+R 6
+D 1
+U 6
+R 8
+U 10
+D 6
+U 10
+L 3
+D 1
+L 1
+R 9
+D 10
+L 10
+U 12
+D 3
+L 2
+U 6
+L 9
+U 2
+R 6
+D 8
+R 11
+L 1
+U 3
+R 1
+U 9
+R 12
+U 3
+D 11
+U 3
+D 10
+U 12
+L 11
+R 9
+U 9
+D 11
+L 8
+D 4
+R 4
+U 4
+D 1
+L 7
+R 10
+L 4
+R 4
+U 11
+D 3
+L 6
+R 10
+L 9
+R 11
+U 6
+D 2
+U 2
+L 3
+D 11
+U 6
+D 12
+L 5
+R 5
+D 6
+R 5
+U 2
+R 8
+L 7
+D 7
+R 3
+D 8
+U 6
+D 1
+U 1
+D 4
+L 3
+D 12
+L 8
+D 8
+U 7
+R 1
+D 10
+L 5
+D 7
+L 1
+U 4
+R 12
+L 8
+U 2
+L 2
+U 1
+L 8
+U 3
+L 12
+R 3
+D 11
+R 1
+U 4
+D 12
+L 3
+U 2
+R 5
+U 2
+R 7
+U 8
+L 5
+R 1
+D 5
+R 12
+D 8
+R 9
+D 7
+L 2
+R 2
+U 9
+D 6
+U 6
+R 2
+D 2
+R 9
+D 4
+R 12
+D 13
+R 9
+L 3
+D 8
+L 13
+U 2
+R 10
+U 12
+D 12
+U 3
+L 6
+D 8
+U 1
+L 12
+D 9
+L 7
+R 2
+D 4
+R 5
+L 7
+R 12
+U 4
+L 7
+D 4
+U 10
+L 2
+D 1
+U 5
+R 5
+U 2
+L 9
+D 10
+L 1
+R 7
+L 6
+D 1
+L 12
+R 6
+U 10
+R 2
+D 10
+R 5
+L 3
+R 8
+D 1
+R 12
+L 7
+U 5
+L 11
+D 4
+U 11
+D 1
+U 11
+L 1
+D 11
+U 11
+D 4
+U 8
+R 5
+D 6
+L 12
+R 5
+D 10
+L 2
+D 5
+R 10
+U 6
+D 6
+R 4
+D 7
+L 2
+D 5
+U 2
+R 9
+L 11
+U 13
+D 9
+L 11
+D 8
+L 2
+D 4
+R 13
+L 5
+U 12
+R 11
+U 5
+L 8
+U 5
+D 7
+U 1
+R 9
+D 4
+U 3
+R 9
+L 3
+D 7
+R 8
+D 7
+L 2
+U 4
+L 12
+U 13
+L 12
+R 8
+L 3
+R 12
+L 4
+U 12
+R 13
+D 10
+L 8
+U 12
+R 5
+L 1
+U 2
+L 3
+U 2
+D 12
+L 12
+U 11
+L 2
+R 6
+U 3
+L 2
+R 7
+U 7
+L 3
+R 8
+L 11
+D 2
+U 1
+R 12
+D 1
+R 4
+L 13
+U 14
+R 14
+D 12
+R 12
+D 11
+L 11
+U 2
+L 6
+D 8
+L 5
+D 7
+R 2
+L 14
+U 12
+R 13
+L 7
+D 2
+U 4
+D 5
+R 5
+L 7
+R 7
+U 1
+R 10
+D 11
+L 7
+U 2
+R 5
+L 11
+U 11
+R 9
+U 9
+R 12
+D 14
+R 5
+L 9
+U 2
+D 12
+L 6
+U 7
+R 5
+L 10
+D 10
+U 4
+D 13
+L 13
+D 3
+R 8
+D 10
+U 12
+L 14
+U 7
+D 6
+R 4
+U 11
+R 2
+L 5
+D 12
+R 4
+L 4
+D 5
+L 12
+U 3
+L 3
+U 7
+R 4
+L 2
+R 7
+L 5
+D 5
+R 9
+L 5
+D 12
+R 3
+U 1
+D 6
+U 2
+R 10
+L 4
+U 12
+R 15
+L 2
+R 3
+D 8
+L 13
+D 3
+R 5
+D 5
+L 5
+U 7
+L 4
+R 10
+D 11
+L 3
+R 1
+U 4
+D 15
+L 8
+U 10
+L 5
+D 1
+R 5
+D 15
+R 3
+U 9
+R 4
+D 3
+L 15
+U 6
+D 10
+U 2
+R 6
+U 10
+L 12
+R 8
+D 12
+R 14
+U 10
+D 1
+L 1
+D 8
+U 3
+R 11
+D 7
+L 5
+D 14
+R 1
+D 8
+R 6
+U 6
+D 1
+U 14
+R 12
+L 5
+U 5
+L 14
+U 1
+D 3
+R 6
+U 4
+R 9
+L 13
+R 2
+U 10
+R 11
+U 7
+D 8
+U 14
+L 4
+R 3
+U 6
+R 2
+D 14
+U 10
+D 13
+U 8
+R 12
+L 12
+U 6
+L 4
+U 5
+D 6
+U 8
+L 12
+D 1
+L 3
+R 4
+L 11
+R 5
+D 3
+U 6
+D 15
+R 14
+U 8
+R 10
+U 15
+R 13
+L 13
+U 4
+D 3
+U 4
+D 1
+U 5
+R 5
+D 4
+R 2
+D 13
+R 7
+D 10
+U 3
+R 15
+D 3
+U 13
+R 16
+U 2
+D 6
+L 13
+R 8
+L 5
+R 1
+U 7
+R 6
+U 6
+R 10
+U 5
+L 14
+R 12
+U 8
+R 13
+U 4
+L 10
+R 16
+L 15
+D 7
+R 14
+D 8
+U 8
+L 15
+R 2
+U 11
+L 6
+R 6
+D 2
+U 9
+D 12
+L 10
+U 7
+R 8
+L 4
+D 5
+R 13
+L 9
+U 15
+D 11
+R 11
+D 8
+L 10
+R 14
+D 3
+R 10
+U 1
+R 11
+L 16
+R 12
+D 15
+L 13
+U 2
+L 11
+U 15
+D 9
+R 1
+D 13
+L 16
+U 9
+D 2
+R 5
+U 9
+R 11
+L 16
+U 5
+R 11
+U 8
+L 15
+U 1
+L 11
+U 3
+L 4
+U 9
+L 5
+U 11
+D 9
+U 4
+L 14
+U 8
+L 16
+D 9
+U 5
+L 14
+R 13
+U 8
+L 4
+R 9
+L 4
+R 7
+D 15
+U 14
+D 8
+U 6
+R 11
+L 15
+D 10
+R 2
+L 12
+R 11
+D 7
+R 11
+L 4
+R 4
+D 4
+R 3
+U 15
+L 6
+R 8
+L 5
+U 13
+D 6
+R 1
+D 15
+L 9
+U 2
+L 13
+R 10
+U 8
+R 15
+D 16
+L 13
+U 13
+L 12
+R 10
+U 16
+L 10
+R 14
+D 17
+R 4
+D 16
+U 17
+R 8
+D 10
+R 11
+L 10
+U 17
+L 11
+U 3
+L 4
+U 2
+D 10
+R 15
+U 1
+R 5
+L 12
+D 4
+R 1
+U 15
+R 13
+L 17
+R 15
+D 4
+L 14
+R 3
+D 1
+U 14
+R 11
+D 12
+L 7
+D 11
+R 12
+U 1
+R 5
+L 11
+D 9
+U 8
+R 1
+U 4
+L 15
+R 12
+U 17
+R 4
+U 14
+L 4
+D 16
+R 9
+U 9
+D 11
+L 7
+D 16
+R 10
+L 10
+R 15
+U 10
+R 6
+L 4
+R 6
+L 12
+U 9
+R 15
+D 12
+L 14
+U 14
+D 6
+U 4
+R 17
+U 2
+L 5
+R 13
+D 15
+U 13
+L 5
+D 3
+L 7
+U 12
+R 13
+D 15
+U 15
+L 17
+U 17
+L 6
+R 2
+U 17
+R 7
+L 15
+U 17
+R 11
+L 2
+U 1
+D 4
+U 2
+R 10
+L 9
+D 18
+U 5
+D 7
+R 18
+L 11
+D 2
+U 13
+D 12
+R 10
+D 2
+R 9
+L 3
+D 9
+R 9
+L 17
+R 4
+L 7
+D 16
+L 5
+R 3
+L 8
+U 7
+R 8
+L 1
+D 12
+U 13
+R 8
+D 18
+U 7
+R 6
+D 7
+L 7
+D 8
+R 16
+L 13
+R 6
+U 1
+L 9
+U 9
+L 12
+D 13
+R 18
+L 7
+D 18
+U 17
+R 18
+D 11
+R 1
+D 4
+U 3
+L 7
+D 17
+R 8
+U 11
+D 7
+L 4
+R 12
+U 10
+L 15
+R 14
+U 16
+D 4
+L 10
+U 6
+D 18
+R 7
+U 13
+R 11
+D 14
+L 5
+U 5
+L 7
+R 15
+L 16
+U 6
+D 9
+L 17
+R 4
+L 16
+D 10
+U 16
+D 17
+R 7
+L 16
+U 6
+L 15
+R 13
+U 8
+L 14
+R 12
+U 5
+D 17
+R 13
+D 12
+U 12
+L 16
+R 8
+U 4
+D 6
+U 10
+D 14
+R 18
+L 17
+U 15
+L 5
+U 7
+D 15
+U 10
+R 18
+L 11
+D 10
+R 12
+U 15
+D 11
+U 7
+D 3
+R 2
+U 5
+R 12
+U 15
+R 12
+U 19
+L 6
+U 18
+D 8
+L 7
+D 2
+R 1
+L 16
+D 5
+L 9
+U 11
+L 6
+U 7
+L 2
+D 18
+L 1
+U 19
+D 15
+U 8
+R 5
+U 13
+L 7
+R 14
+U 2
+D 10
+U 16
+D 3
+R 8
+L 10
+D 17
+U 16
+D 6
+R 18
+D 5
+L 5
+D 4
+L 6
+U 17
+D 7
+R 15
+D 5
+R 18
+L 6
+U 15
+L 3
+U 13
+L 15
+R 5
+D 9
+R 11
+U 15
+L 19
+D 11
+L 8
+D 14
+R 7
+L 16
+D 5
+R 13
+D 5
+L 9
+D 3
+L 3
+R 12
+U 17
+R 8
+L 11
+U 2
+R 9
+L 3
+D 6
+L 9
+U 11
+R 6
+U 19
+R 6
+L 12
+U 5
+R 4
+U 4
+L 16
+R 17
+D 12
+U 11
+R 4
+D 11
+U 4
+R 8
+U 9
+R 12
+U 13
+L 2
+D 9
+L 2";
+}
diff --git a/src/tests/aoc-2022-09/src/types.pr.rs b/src/tests/aoc-2022-09/src/types.pr.rs
new file mode 100644
index 0000000..d4225a9
--- /dev/null
+++ b/src/tests/aoc-2022-09/src/types.pr.rs
@@ -0,0 +1,7 @@
+/*SPEC*
+property unique<T> {
+ \c <: (Container) -> ((for-all-elems c) \a -> ((unique-count? a) c))
+}
+
+type Set<T> = {c impl (Container) | (unique c)}
+ *ENDSPEC*/