diff --git a/2022/Cargo.toml b/2022/Cargo.toml new file mode 100644 index 0000000..66b08b5 --- /dev/null +++ b/2022/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "aoc2022" +version = "0.1.0" +edition = "2021" + +[dependencies] +paste = "1.0" + +[profile.bench] +lto = true diff --git a/2022/inputs/day00 b/2022/inputs/day00 new file mode 100644 index 0000000..2643368 --- /dev/null +++ b/2022/inputs/day00 @@ -0,0 +1,200 @@ +1914 +1931 +1892 +1584 +1546 +1988 +1494 +1709 +1624 +1755 +1849 +1430 +1890 +1675 +1604 +1580 +1500 +1277 +1729 +1456 +2002 +1075 +1512 +895 +1843 +1921 +1904 +1989 +1407 +1552 +1714 +757 +1733 +1459 +1777 +1440 +1649 +1409 +1662 +1968 +1775 +1998 +1754 +1938 +1964 +1415 +1990 +1997 +1870 +1664 +1145 +1782 +1820 +1625 +1599 +1530 +1759 +1575 +1614 +1869 +1620 +1818 +1295 +1667 +1361 +1520 +1555 +1485 +1502 +1983 +1104 +1973 +1433 +1906 +1583 +1562 +1493 +1945 +1528 +1600 +1814 +1712 +1848 +1454 +1801 +1710 +1824 +1426 +1977 +1511 +1644 +1302 +1428 +1513 +1261 +1761 +1680 +1731 +1724 +1970 +907 +600 +1613 +1091 +1571 +1418 +1806 +1542 +1909 +1445 +1344 +1937 +1450 +1865 +1561 +1962 +1637 +1803 +1889 +365 +1810 +1791 +1591 +1532 +1863 +1658 +1808 +1816 +1837 +1764 +1443 +1805 +1616 +1403 +1656 +1661 +1734 +1930 +1120 +1920 +1227 +1618 +1640 +1586 +1982 +1534 +1278 +1269 +1572 +1654 +1472 +1974 +1748 +1425 +1553 +1708 +1394 +1417 +1746 +1745 +1834 +1787 +1298 +1786 +1966 +1768 +1932 +1523 +1356 +1547 +1634 +1951 +1922 +222 +1461 +1628 +1888 +1639 +473 +1568 +1783 +572 +1522 +1934 +1629 +1283 +1550 +1859 +2007 +1996 +1822 +996 +1911 +1689 +1537 +1793 +1762 +1677 +1266 +1715 diff --git a/2022/rustfmt.toml b/2022/rustfmt.toml new file mode 100644 index 0000000..36e1962 --- /dev/null +++ b/2022/rustfmt.toml @@ -0,0 +1,7 @@ +newline_style = "Unix" +max_width = 140 +imports_granularity = "Crate" +struct_field_align_threshold = 25 +where_single_line = true +edition = "2021" +use_small_heuristics = "Max" diff --git a/2022/setup_day.sh b/2022/setup_day.sh new file mode 100755 index 0000000..097c960 --- /dev/null +++ b/2022/setup_day.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +today=$(date +%d) +aocd > inputs/day$today + +echo '#![feature(test)] +extern crate test; +use aoc2022::{boilerplate, common::*}; + +fn parse_input(raw: &str) -> Parsed { + unimplemented!() +} + +fn part1(parsed: &Parsed) -> usize { + unimplemented!() +} + +fn part2(parsed: &Parsed) -> usize { + unimplemented!() +} + +boilerplate! { + DAY = '$today', + type = Vec, + TEST_INPUT == "", + tests: { + part1: { TEST_INPUT => 0 }, + part2: { TEST_INPUT => 0 }, + }, + bench1 == 0, + bench2 == 0, + parse: Vec::len => 0, +}' > src/bin/day$today.rs diff --git a/2022/src/bin/day0.rs b/2022/src/bin/day0.rs new file mode 100644 index 0000000..ec07ccf --- /dev/null +++ b/2022/src/bin/day0.rs @@ -0,0 +1,55 @@ +#![feature(test)] +extern crate test; +use aoc2022::{boilerplate, common::*}; + +/// Naive solution for a previous day 1, +/// just to test my test setup for this year. + +fn parse_input(raw: &str) -> Parsed { + parse_nums(raw) +} + +fn part1(parsed: &Parsed) -> usize { + for x in parsed { + for y in parsed { + if x + y == 2020 { + return x * y; + } + } + } + unreachable!() +} + +fn part2(parsed: &Parsed) -> usize { + for x in parsed { + for y in parsed { + for z in parsed { + if x + y + z == 2020 { + return x * y * z; + } + } + } + } + unreachable!() +} + +boilerplate! { + DAY = 0, + type = Vec, + TEST_INPUT == "1721 +979 +366 +299 +675 +1456", + tests: { + part1: { + TEST_INPUT => 514579, + "1234\n786" => 969924, + }, + part2: { TEST_INPUT => 241861950 }, + }, + bench1 == 731731, + bench2 == 116115990, + parse: Vec::len => 200, +} diff --git a/2022/src/common.rs b/2022/src/common.rs new file mode 100644 index 0000000..caa3385 --- /dev/null +++ b/2022/src/common.rs @@ -0,0 +1,17 @@ +use std::{env, fmt::Display, str::FromStr}; + +pub fn read_file(day: usize) -> String { + std::fs::read_to_string(env::var("AOC_INPUT").unwrap_or_else(|_| format!("inputs/day{:0>2}", day))).unwrap() +} + +pub fn parse_nums(l: &str) -> Vec { + l.lines().map(parse_num).collect() +} + +pub fn parse_nums_comma(l: &str) -> Vec { + l.trim().split(',').map(parse_num).collect() +} + +pub fn parse_num(s: &str) -> T { + s.parse().unwrap_or_else(|_| panic!("Invalid number {s}")) +} diff --git a/2022/src/lib.rs b/2022/src/lib.rs new file mode 100644 index 0000000..a9e8857 --- /dev/null +++ b/2022/src/lib.rs @@ -0,0 +1,3 @@ +#![feature(test)] +pub mod common; +pub mod teststuff; diff --git a/2022/src/teststuff.rs b/2022/src/teststuff.rs new file mode 100644 index 0000000..7dd3053 --- /dev/null +++ b/2022/src/teststuff.rs @@ -0,0 +1,62 @@ +#[macro_export] +macro_rules! boilerplate { + ( + DAY = $day: literal, + type = $type: ty, + TEST_INPUT == $ti: literal, + tests: { + $($part: ident: { $($tpi: expr => $to: literal$(,)?)+ }$(,)?)* + }, + bench1 == $b1: literal, + bench2 == $b2: literal, + parse: $input_fn: expr => $it: literal$(,)? + ) => { + const DAY: usize = $day; + type Parsed = $type; + + fn main() { + let input = parse_input(&read_file(DAY)); + println!("Part 1: {}", part1(&input)); + println!("Part 2: {}", part2(&input)); + } + + #[cfg(test)] + mod tests { + use super::*; + use aoc2022::*; + + const TEST_INPUT: &str = $ti; + + $($( + paste::paste! { + #[test] + fn [<$part _test_ $to>]() { + let input = parse_input($tpi); + assert_eq!($part(&input), $to); + } + } + )+)* + bench!(part1() == $b1); + bench!(part2() == $b2); + #[bench] + fn bench_input_parsing(b: &mut test::Bencher) { + let raw = &read_file(DAY); + b.iter(|| assert_eq!($input_fn(&parse_input(test::black_box(&raw))), $it)); + } + } + } +} + +#[macro_export] +macro_rules! bench { + ($part: ident() == $expected:expr) => { + paste::paste! { + #[bench] + fn [<$part _bench>](b: &mut test::Bencher) { + let raw = &read_file(DAY); + let input = parse_input(&raw); + b.iter(|| assert_eq!($part(test::black_box(&input)), $expected)); + } + } + }; +}