diff --git a/fetch.sh b/fetch.sh index bb9bd06..710eaaf 100755 --- a/fetch.sh +++ b/fetch.sh @@ -6,7 +6,6 @@ if [ ! -e cookies.txt ]; then fi list=$(find -name "Day*.cpp" | awk -F '/' '{print $3 "/" $4}' | awk -F '.' '{print $1}' | sed 's/Day//g' | sort) -echo $list for item in $list; do echo $item @@ -23,5 +22,4 @@ for item in $list; do touch "res/$year/day$day/test_input.txt" curl -s --cookie cookies.txt https://adventofcode.com/$year/day/$webitem/input >$dir fi - exit done diff --git a/res/2022/day01/test_input.txt b/res/2022/day01/test_input.txt new file mode 100644 index 0000000..2094f91 --- /dev/null +++ b/res/2022/day01/test_input.txt @@ -0,0 +1,14 @@ +1000 +2000 +3000 + +4000 + +5000 +6000 + +7000 +8000 +9000 + +10000 diff --git a/res/2022/day02/test_input.txt b/res/2022/day02/test_input.txt new file mode 100644 index 0000000..25097e8 --- /dev/null +++ b/res/2022/day02/test_input.txt @@ -0,0 +1,3 @@ +A Y +B X +C Z \ No newline at end of file diff --git a/res/2022/day03/test_input.txt b/res/2022/day03/test_input.txt new file mode 100644 index 0000000..9919ffa --- /dev/null +++ b/res/2022/day03/test_input.txt @@ -0,0 +1,6 @@ +vJrwpWtwJgWrhcsFMMfFFhFp +jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL +PmmdzqPrVvPwwTWBwg +wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn +ttgJtRGJQctTZtZT +CrZsJsPPZsGzwwsLwLmpwMDw \ No newline at end of file diff --git a/res/2022/day04/test_input.txt b/res/2022/day04/test_input.txt new file mode 100644 index 0000000..99a66c5 --- /dev/null +++ b/res/2022/day04/test_input.txt @@ -0,0 +1,6 @@ +2-4,6-8 +2-3,4-5 +5-7,7-9 +2-8,3-7 +6-6,4-6 +2-6,4-8 \ No newline at end of file diff --git a/res/2022/day05/test_input.txt b/res/2022/day05/test_input.txt new file mode 100644 index 0000000..e98aba4 --- /dev/null +++ b/res/2022/day05/test_input.txt @@ -0,0 +1,9 @@ + [D] +[N] [C] +[Z] [M] [P] + 1 2 3 + +move 1 from 2 to 1 +move 3 from 1 to 3 +move 2 from 2 to 1 +move 1 from 1 to 2 \ No newline at end of file diff --git a/res/2022/day06/test_input.txt b/res/2022/day06/test_input.txt new file mode 100644 index 0000000..5a2b0a7 --- /dev/null +++ b/res/2022/day06/test_input.txt @@ -0,0 +1 @@ +mjqjpqmgbljsphdztnvjfqwrcgsmlb \ No newline at end of file diff --git a/res/2022/day07/test_input.txt b/res/2022/day07/test_input.txt new file mode 100644 index 0000000..bcbb513 --- /dev/null +++ b/res/2022/day07/test_input.txt @@ -0,0 +1,23 @@ +$ cd / +$ ls +dir a +14848514 b.txt +8504156 c.dat +dir d +$ cd a +$ ls +dir e +29116 f +2557 g +62596 h.lst +$ cd e +$ ls +584 i +$ cd .. +$ cd .. +$ cd d +$ ls +4060174 j +8033020 d.log +5626152 d.ext +7214296 k \ No newline at end of file diff --git a/res/2022/day08/test_input.txt b/res/2022/day08/test_input.txt new file mode 100644 index 0000000..6557024 --- /dev/null +++ b/res/2022/day08/test_input.txt @@ -0,0 +1,5 @@ +30373 +25512 +65332 +33549 +35390 \ No newline at end of file diff --git a/res/2022/day09/test_input.txt b/res/2022/day09/test_input.txt new file mode 100644 index 0000000..60bd43b --- /dev/null +++ b/res/2022/day09/test_input.txt @@ -0,0 +1,8 @@ +R 5 +U 8 +L 8 +D 3 +R 17 +D 10 +L 25 +U 20 diff --git a/res/2022/day10/test_input.txt b/res/2022/day10/test_input.txt new file mode 100644 index 0000000..94cd0a8 --- /dev/null +++ b/res/2022/day10/test_input.txt @@ -0,0 +1,146 @@ +addx 15 +addx -11 +addx 6 +addx -3 +addx 5 +addx -1 +addx -8 +addx 13 +addx 4 +noop +addx -1 +addx 5 +addx -1 +addx 5 +addx -1 +addx 5 +addx -1 +addx 5 +addx -1 +addx -35 +addx 1 +addx 24 +addx -19 +addx 1 +addx 16 +addx -11 +noop +noop +addx 21 +addx -15 +noop +noop +addx -3 +addx 9 +addx 1 +addx -3 +addx 8 +addx 1 +addx 5 +noop +noop +noop +noop +noop +addx -36 +noop +addx 1 +addx 7 +noop +noop +noop +addx 2 +addx 6 +noop +noop +noop +noop +noop +addx 1 +noop +noop +addx 7 +addx 1 +noop +addx -13 +addx 13 +addx 7 +noop +addx 1 +addx -33 +noop +noop +noop +addx 2 +noop +noop +noop +addx 8 +noop +addx -1 +addx 2 +addx 1 +noop +addx 17 +addx -9 +addx 1 +addx 1 +addx -3 +addx 11 +noop +noop +addx 1 +noop +addx 1 +noop +noop +addx -13 +addx -19 +addx 1 +addx 3 +addx 26 +addx -30 +addx 12 +addx -1 +addx 3 +addx 1 +noop +noop +noop +addx -9 +addx 18 +addx 1 +addx 2 +noop +noop +addx 9 +noop +noop +noop +addx -1 +addx 2 +addx -37 +addx 1 +addx 3 +noop +addx 15 +addx -21 +addx 22 +addx -6 +addx 1 +noop +addx 2 +addx 1 +noop +addx -10 +noop +noop +addx 20 +addx 1 +addx 2 +addx 2 +addx -6 +addx -11 +noop +noop +noop \ No newline at end of file diff --git a/res/2022/day11/test_input.txt b/res/2022/day11/test_input.txt new file mode 100644 index 0000000..c04eddb --- /dev/null +++ b/res/2022/day11/test_input.txt @@ -0,0 +1,27 @@ +Monkey 0: + Starting items: 79, 98 + Operation: new = old * 19 + Test: divisible by 23 + If true: throw to monkey 2 + If false: throw to monkey 3 + +Monkey 1: + Starting items: 54, 65, 75, 74 + Operation: new = old + 6 + Test: divisible by 19 + If true: throw to monkey 2 + If false: throw to monkey 0 + +Monkey 2: + Starting items: 79, 60, 97 + Operation: new = old * old + Test: divisible by 13 + If true: throw to monkey 1 + If false: throw to monkey 3 + +Monkey 3: + Starting items: 74 + Operation: new = old + 3 + Test: divisible by 17 + If true: throw to monkey 0 + If false: throw to monkey 1 \ No newline at end of file diff --git a/res/2022/day12/test_input.txt b/res/2022/day12/test_input.txt new file mode 100644 index 0000000..433e0d2 --- /dev/null +++ b/res/2022/day12/test_input.txt @@ -0,0 +1,5 @@ +Sabqponm +abcryxxl +accszExk +acctuvwj +abdefghi \ No newline at end of file diff --git a/res/2022/day13/test_input.txt b/res/2022/day13/test_input.txt new file mode 100644 index 0000000..4008a65 --- /dev/null +++ b/res/2022/day13/test_input.txt @@ -0,0 +1,24 @@ +[1,1,3,1,1] +[1,1,5,1,1] + +[[1],[2,3,4]] +[[1],4] + +[9] +[[8,7,6]] + +[[4,4],4,4] +[[4,4],4,4,4] + +[7,7,7,7] +[7,7,7] + +[] +[3] + +[[[]]] +[[]] + + +[1,[2,[3,[4,[5,6,7]]]],8,9] +[1,[2,[3,[4,[5,6,0]]]],8,9] \ No newline at end of file diff --git a/res/2022/day14/test_input.txt b/res/2022/day14/test_input.txt new file mode 100644 index 0000000..1926028 --- /dev/null +++ b/res/2022/day14/test_input.txt @@ -0,0 +1,2 @@ +498,4 -> 498,6 -> 496,6 +503,4 -> 502,4 -> 502,9 -> 494,9 \ No newline at end of file diff --git a/res/2022/day15/test_input.txt b/res/2022/day15/test_input.txt new file mode 100644 index 0000000..652e631 --- /dev/null +++ b/res/2022/day15/test_input.txt @@ -0,0 +1,14 @@ +Sensor at x=2, y=18: closest beacon is at x=-2, y=15 +Sensor at x=9, y=16: closest beacon is at x=10, y=16 +Sensor at x=13, y=2: closest beacon is at x=15, y=3 +Sensor at x=12, y=14: closest beacon is at x=10, y=16 +Sensor at x=10, y=20: closest beacon is at x=10, y=16 +Sensor at x=14, y=17: closest beacon is at x=10, y=16 +Sensor at x=8, y=7: closest beacon is at x=2, y=10 +Sensor at x=2, y=0: closest beacon is at x=2, y=10 +Sensor at x=0, y=11: closest beacon is at x=2, y=10 +Sensor at x=20, y=14: closest beacon is at x=25, y=17 +Sensor at x=17, y=20: closest beacon is at x=21, y=22 +Sensor at x=16, y=7: closest beacon is at x=15, y=3 +Sensor at x=14, y=3: closest beacon is at x=15, y=3 +Sensor at x=20, y=1: closest beacon is at x=15, y=3 \ No newline at end of file diff --git a/res/2022/day16/test_input.txt b/res/2022/day16/test_input.txt new file mode 100644 index 0000000..85fa5b0 --- /dev/null +++ b/res/2022/day16/test_input.txt @@ -0,0 +1,10 @@ +Valve AA has flow rate=0; tunnels lead to valves DD, II, BB +Valve BB has flow rate=13; tunnels lead to valves CC, AA +Valve CC has flow rate=2; tunnels lead to valves DD, BB +Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE +Valve EE has flow rate=3; tunnels lead to valves FF, DD +Valve FF has flow rate=0; tunnels lead to valves EE, GG +Valve GG has flow rate=0; tunnels lead to valves FF, HH +Valve HH has flow rate=22; tunnel leads to valve GG +Valve II has flow rate=0; tunnels lead to valves AA, JJ +Valve JJ has flow rate=21; tunnel leads to valve II \ No newline at end of file diff --git a/res/2022/day17/test_input.txt b/res/2022/day17/test_input.txt new file mode 100644 index 0000000..fb5d89e --- /dev/null +++ b/res/2022/day17/test_input.txt @@ -0,0 +1 @@ +>>><<><>><<<>><>>><<<>>><<<><<<>><>><<>> \ No newline at end of file diff --git a/res/2022/day18/test_input.txt b/res/2022/day18/test_input.txt new file mode 100644 index 0000000..d18bf98 --- /dev/null +++ b/res/2022/day18/test_input.txt @@ -0,0 +1,13 @@ +2,2,2 +1,2,2 +3,2,2 +2,1,2 +2,3,2 +2,2,1 +2,2,3 +2,2,4 +2,2,6 +1,2,5 +3,2,5 +2,1,5 +2,3,5 \ No newline at end of file diff --git a/res/2022/day19/test_input.txt b/res/2022/day19/test_input.txt new file mode 100644 index 0000000..5212cde --- /dev/null +++ b/res/2022/day19/test_input.txt @@ -0,0 +1,2 @@ +Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 2 ore and 7 obsidian. +Blueprint 2: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 8 clay. Each geode robot costs 3 ore and 12 obsidian. \ No newline at end of file diff --git a/res/2022/day20/test_input.txt b/res/2022/day20/test_input.txt new file mode 100644 index 0000000..5cbf3d9 --- /dev/null +++ b/res/2022/day20/test_input.txt @@ -0,0 +1,7 @@ +1 +2 +-3 +3 +-2 +0 +4 \ No newline at end of file diff --git a/res/2022/day21/test_input.txt b/res/2022/day21/test_input.txt new file mode 100644 index 0000000..e14be60 --- /dev/null +++ b/res/2022/day21/test_input.txt @@ -0,0 +1,15 @@ +root: pppw + sjmn +dbpl: 5 +cczh: sllz + lgvd +zczc: 2 +ptdq: humn - dvpt +dvpt: 3 +lfqf: 4 +humn: 5 +ljgn: 2 +sjmn: drzm * dbpl +sllz: 4 +pppw: cczh / lfqf +lgvd: ljgn * ptdq +drzm: hmdt - zczc +hmdt: 32 diff --git a/res/2022/day22/test_input.txt b/res/2022/day22/test_input.txt new file mode 100644 index 0000000..8bc2e1e --- /dev/null +++ b/res/2022/day22/test_input.txt @@ -0,0 +1,14 @@ + ...# + .#.. + #... + .... +...#.......# +........#... +..#....#.... +..........#. + ...#.... + .....#.. + .#...... + ......#. + +10R5L5R10L4R5L5 diff --git a/res/2022/day23/test_input.txt b/res/2022/day23/test_input.txt new file mode 100644 index 0000000..7ac3ba9 --- /dev/null +++ b/res/2022/day23/test_input.txt @@ -0,0 +1,7 @@ +....#.. +..###.# +#...#.# +.#...## +#.###.. +##.#.## +.#..#.. \ No newline at end of file diff --git a/res/2022/day24/test_input.txt b/res/2022/day24/test_input.txt new file mode 100644 index 0000000..6b9b892 --- /dev/null +++ b/res/2022/day24/test_input.txt @@ -0,0 +1,6 @@ +#.###### +#>>.<^<# +#.<..<<# +#>v.><># +#<^v^^># +######.# \ No newline at end of file diff --git a/res/2022/day25/test_input.txt b/res/2022/day25/test_input.txt new file mode 100644 index 0000000..237ef0c --- /dev/null +++ b/res/2022/day25/test_input.txt @@ -0,0 +1,13 @@ +1=-0-2 +12111 +2=0= +21 +2=01 +111 +20012 +112 +1=-1= +1-12 +12 +1= +122 \ No newline at end of file diff --git a/src/2022/Day01.cpp b/src/2022/Day01.cpp new file mode 100644 index 0000000..67f4408 --- /dev/null +++ b/src/2022/Day01.cpp @@ -0,0 +1,51 @@ +#include "common/aoc.h" + +namespace y$1::day01 +{ + REGISTER_DAY(2022, Day01, std::set, int); + + REGISTER_TEST_EXAMPLE(2022, Day01, ExampleInput, 1, 24000); + REGISTER_TEST(2022, Day01, Input, 1, 68292); + REGISTER_TEST_EXAMPLE(2022, Day01, ExampleInput, 2, 45000); + REGISTER_TEST(2022, Day01, Input, 2, 203203); + + READ_INPUT(input) + { + std::string str; + std::set elfs; + int sum = 0; + while (std::getline(input, str)) + { + if (str.empty()) + { + elfs.emplace(sum); + sum = 0; + continue; + } + sum += std::stoll(str); + } + if (sum != 0) + elfs.emplace(sum); + return elfs; + } + + OUTPUT1(input) + { + return Helper::Max(input); + } + + OUTPUT2(input) + { + int sum = 0; + int i = 0; + for (auto it = input.rbegin(); it != input.rend(); it++) + { + sum += *it; + i++; + if (i == 3) + break; + } + + return sum; + } +} diff --git a/src/2022/Day02.cpp b/src/2022/Day02.cpp new file mode 100644 index 0000000..5638443 --- /dev/null +++ b/src/2022/Day02.cpp @@ -0,0 +1,46 @@ +#include "common/aoc.h" + +namespace y$1::day02 +{ + REGISTER_DAY(2022, Day02, std::vector, int); + + REGISTER_TEST_EXAMPLE(2022, Day02, ExampleInput, 1, 15); + REGISTER_TEST(2022, Day02, Input, 1, 13221); + REGISTER_TEST_EXAMPLE(2022, Day02, ExampleInput, 2, 12); + REGISTER_TEST(2022, Day02, Input, 2, 13131); + + READ_INPUT(input) + { + std::string str; + std::vector hands; + while (std::getline(input, str)) + { + hands.emplace_back(str); + } + return hands; + } + + OUTPUT1(input) + { + int sum = 0; + for (auto hand : input) + { + int handPoints = hand[2] - 'X' + 1; + int outcomePoints = (((hand[2] - 'X') - (hand[0] - 'A') + 4) % 3) * 3; + sum += handPoints + outcomePoints; + } + return sum; + } + + OUTPUT2(input) + { + int sum = 0; + for (auto& hand : input) + { + int handPoints = ((hand[2] - 'A') + (hand[0] - 'X' - 1) + 3) % 3 + 1; + int outcomePoints = (hand[2] - 'X') * 3; + sum += handPoints + outcomePoints; + } + return sum; + } +} diff --git a/src/2022/Day03.cpp b/src/2022/Day03.cpp new file mode 100644 index 0000000..e3a7b9b --- /dev/null +++ b/src/2022/Day03.cpp @@ -0,0 +1,84 @@ +#include "common/aoc.h" + +namespace y$1::day03 +{ + REGISTER_DAY(2022, Day03, std::vector, int); + + REGISTER_TEST_EXAMPLE(2022, Day03, ExampleInput, 1, 157); + REGISTER_TEST(2022, Day03, Input, 1, 7811); + REGISTER_TEST_EXAMPLE(2022, Day03, ExampleInput, 2, 70); + REGISTER_TEST(2022, Day03, Input, 2, 2639); + + READ_INPUT(input) + { + std::string str; + std::vector backpacks; + while (std::getline(input, str)) + { + backpacks.emplace_back(str); + } + return backpacks; + } + + OUTPUT1(input) + { + int sum = 0; + for (auto& backpack : input) + { + std::set s1; + std::set s2; + for (int i = 0; i < backpack.size(); i++) + { + if (i < backpack.size() / 2) + { + s1.emplace(backpack[i]); + } + else + { + s2.emplace(backpack[i]); + } + } + std::set intersection = Helper::GetIntersection(s1, s2); + for (auto c : intersection) + { + if (c >= 'A' && c <= 'Z') + sum += c - 'A' + 27; + else + sum += c - 'a' + 1; + } + } + return sum; + } + + OUTPUT2(input) + { + int sum = 0; + for (int i = 0; i < input.size() - 2; i += 3) + { + std::set s1; + std::set s2; + std::set s3; + for (int j = 0; j < input[i].size(); j++) + { + s1.emplace(input[i][j]); + } + for (int j = 0; j < input[i + 1].size(); j++) + { + s2.emplace(input[i + 1][j]); + } + for (int j = 0; j < input[i + 2].size(); j++) + { + s3.emplace(input[i + 2][j]); + } + std::set intersection = Helper::GetIntersection(std::vector>{s1, s2, s3}); + for (auto c : intersection) + { + if (c >= 'A' && c <= 'Z') + sum += c - 'A' + 27; + else + sum += c - 'a' + 1; + } + } + return sum; + } +} diff --git a/src/2022/Day04.cpp b/src/2022/Day04.cpp new file mode 100644 index 0000000..aecf622 --- /dev/null +++ b/src/2022/Day04.cpp @@ -0,0 +1,65 @@ +#include "common/aoc.h" + +namespace y$1::day04 +{ + struct Range + { + int left = 0; + int right = 0; + }; + + struct Pair + { + Range r1; + Range r2; + }; + + REGISTER_DAY(2022, Day04, std::vector, int); + + REGISTER_TEST_EXAMPLE(2022, Day04, ExampleInput, 1, 2); + REGISTER_TEST(2022, Day04, Input, 1, 477); + REGISTER_TEST_EXAMPLE(2022, Day04, ExampleInput, 2, 4); + REGISTER_TEST(2022, Day04, Input, 2, 830); + + READ_INPUT(input) + { + std::string str; + std::vector pairs; + while (std::getline(input, str)) + { + std::stringstream ss{str}; + Pair pair; + ss >> pair.r1.left >> "-" >> pair.r1.right >> ","; + ss >> pair.r2.left >> "-" >> pair.r2.right; + pairs.emplace_back(pair); + } + return pairs; + } + + OUTPUT1(input) + { + int sum = 0; + for (auto& pair : input) + { + if ((pair.r1.left >= pair.r2.left && pair.r1.right <= pair.r2.right) || + (pair.r2.left >= pair.r1.left && pair.r2.right <= pair.r1.right)) + { + sum++; + } + } + return sum; + } + + OUTPUT2(input) + { + int sum = 0; + for (auto& pair : input) + { + if (pair.r1.left <= pair.r2.right && pair.r1.right >= pair.r2.left) + { + sum++; + } + } + return sum; + } +} diff --git a/src/2022/Day05.cpp b/src/2022/Day05.cpp new file mode 100644 index 0000000..2c3ce9b --- /dev/null +++ b/src/2022/Day05.cpp @@ -0,0 +1,95 @@ +#include "common/aoc.h" + +namespace y$1::day05 +{ + struct Move + { + int from; + int count; + int to; + }; + + struct Instructions + { + std::vector> stacks; + std::vector moves; + }; + + REGISTER_DAY(2022, Day05, Instructions, std::string); + + REGISTER_TEST_EXAMPLE(2022, Day05, ExampleInput, 1, "CMZ"); + REGISTER_TEST(2022, Day05, Input, 1, "JCMHLVGMG"); + REGISTER_TEST_EXAMPLE(2022, Day05, ExampleInput, 2, "MCD"); + REGISTER_TEST(2022, Day05, Input, 2, "LVMRWSSPZ"); + + READ_INPUT(input) + { + std::string str; + Instructions instructions; + while (std::getline(input, str)) + { + if (Helper::StartsWith(str, "move")) + { + std::stringstream ss{str}; + Move move; + ss >> "move" >> move.count >> "from" >> move.from >> "to" >> move.to; + instructions.moves.emplace_back(move); + } + else if (!str.empty()) + { + for (int i = 1; i < str.size(); i += 4) + { + int index = (i - 1) / 4; + if (instructions.stacks.size() <= index) + instructions.stacks.emplace_back(std::deque{}); + if (str[i] >= 'A' && str[i] <= 'Z') + instructions.stacks[index].emplace_front(str[i]); + } + } + } + return instructions; + } + + OUTPUT1(input) + { + Instructions instructions = input; + for (auto& move : instructions.moves) + { + for (int i = 0; i < move.count; i++) + { + instructions.stacks[move.to - 1].emplace_back(instructions.stacks[move.from - 1].back()); + instructions.stacks[move.from - 1].pop_back(); + } + } + std::stringstream ss; + for (auto& stack : instructions.stacks) + { + ss << stack.back(); + } + return ss.str(); + } + + OUTPUT2(input) + { + Instructions instructions = input; + for (auto& move : instructions.moves) + { + std::vector chars; + for (int i = 0; i < move.count; i++) + { + chars.emplace_back(instructions.stacks[move.from - 1].back()); + instructions.stacks[move.from - 1].pop_back(); + } + for (auto it = chars.rbegin(); it != chars.rend(); it++) + { + instructions.stacks[move.to - 1].emplace_back(*it); + } + } + std::stringstream ss; + for (auto& stack : instructions.stacks) + { + ss << stack.back(); + } + return ss.str(); + } +} diff --git a/src/2022/Day06.cpp b/src/2022/Day06.cpp new file mode 100644 index 0000000..bd36283 --- /dev/null +++ b/src/2022/Day06.cpp @@ -0,0 +1,43 @@ +#include "common/aoc.h" + +namespace y$1::day06 +{ + REGISTER_DAY(2022, Day06, std::string, int); + + REGISTER_TEST_EXAMPLE(2022, Day06, ExampleInput, 1, 7); + REGISTER_TEST(2022, Day06, Input, 1, 1658); + REGISTER_TEST_EXAMPLE(2022, Day06, ExampleInput, 2, 19); + REGISTER_TEST(2022, Day06, Input, 2, 2260); + + int GetPosition(const std::string& str, int length) + { + for (int i = length - 1; i < str.size(); i++) + { + std::set s; + for (int j = i - length + 1; j <= i; j++) + { + s.emplace(str[j]); + } + if (s.size() == length) + return i + 1; + } + return 0; + } + + READ_INPUT(input) + { + std::string str; + std::getline(input, str); + return str; + } + + OUTPUT1(input) + { + return GetPosition(input, 4); + } + + OUTPUT2(input) + { + return GetPosition(input, 14); + } +} diff --git a/src/2022/Day07.cpp b/src/2022/Day07.cpp new file mode 100644 index 0000000..9bccf4f --- /dev/null +++ b/src/2022/Day07.cpp @@ -0,0 +1,138 @@ +#include "common/aoc.h" + +namespace y$1::day07 +{ + struct Directory + { + Directory* parent; + std::string name; + int size = 0; + std::map directories; + std::map files; + + bool operator<(const Directory& rhs) + { + return name < rhs.name; + } + }; + + REGISTER_DAY(2022, Day07, Directory, int); + + REGISTER_TEST_EXAMPLE(2022, Day07, ExampleInput, 1, 95437); + REGISTER_TEST(2022, Day07, Input, 1, 1084134); + REGISTER_TEST_EXAMPLE(2022, Day07, ExampleInput, 2, 24933642); + REGISTER_TEST(2022, Day07, Input, 2, 6183184); + + void CalculateSize(Directory& directory) + { + if (directory.size != 0) + return; + int size = 0; + for (auto& file : directory.files) + { + size += file.second; + } + for (auto& directory2 : directory.directories) + { + CalculateSize(directory2.second); + size += directory2.second.size; + } + directory.size = size; + } + + int SumOfDirectories(Directory& directory, int maxSize) + { + int sum = 0; + if (directory.size <= maxSize) + sum += directory.size; + + for (auto& directory2 : directory.directories) + { + sum += SumOfDirectories(directory2.second, maxSize); + } + + return sum; + } + + int FindSmallest(Directory& directory, int minimum) + { + int smallest = 70000000; + if (directory.size >= minimum) + smallest = directory.size; + + for (auto& dir : directory.directories) + { + int min = FindSmallest(dir.second, minimum); + if (smallest != 70000000) + smallest = std::min(min, smallest); + } + return smallest; + } + + READ_INPUT(input) + { + std::string str; + std::set elfs; + int sum = 0; + Directory* currentDirectory; + + Directory rootDirectory; + rootDirectory.name = "/"; + currentDirectory = &rootDirectory; + std::getline(input, str); // $ cd / + while (std::getline(input, str)) + { + if (str[0] == '$') + { + std::stringstream ss{str}; + std::string command; + ss >> "$" >> command; + if (command == "cd") + { + std::string directory; + ss >> directory; + if (directory == "..") + currentDirectory = currentDirectory->parent; + else + currentDirectory = ¤tDirectory->directories[directory]; + } + } + else + { + std::stringstream ss{str}; + if (str[0] == 'd') + { + Directory directory; + ss >> "dir" >> directory.name; + directory.parent = currentDirectory; + currentDirectory->directories.emplace(directory.name, directory); + } + else + { + int size; + std::string name; + ss >> size >> name; + currentDirectory->files.emplace(name, size); + } + } + } + return rootDirectory; + } + + OUTPUT1(input) + { + Directory directory = input; + CalculateSize(directory); + + return SumOfDirectories(directory, 100000); + } + + OUTPUT2(input) + { + Directory directory = input; + CalculateSize(directory); + int space = 70000000; + int neededSpace = 30000000 - (space - directory.size); + return FindSmallest(directory, neededSpace); + } +} diff --git a/src/2022/Day08.cpp b/src/2022/Day08.cpp new file mode 100644 index 0000000..4515a0b --- /dev/null +++ b/src/2022/Day08.cpp @@ -0,0 +1,143 @@ +#include "common/aoc.h" + +namespace y$1::day08 +{ + REGISTER_DAY(2022, Day08, Array2D, int); + + REGISTER_TEST_EXAMPLE(2022, Day08, ExampleInput, 1, 21); + REGISTER_TEST(2022, Day08, Input, 1, 1820); + REGISTER_TEST_EXAMPLE(2022, Day08, ExampleInput, 2, 8); + REGISTER_TEST(2022, Day08, Input, 2, 385112); + + READ_INPUT(input) + { + return Input::ReadDigitsAsArray2D(input); + } + + OUTPUT1(input) + { + // input.Each([&](const Array2D& arr, const Index2D& index) { + std::set found; + for (auto it = input.begin(); it != input.end(); it++) + { + if (found.count(it.index) > 0) + continue; + bool visible = true; + for (int x = it.index.x - 1; x >= 0; x--) + { + if (input.Get(x, it.index.y) >= *it) + { + visible = false; + break; + } + } + if (visible) + { + found.emplace(it.index); + continue; + } + visible = true; + for (int x = it.index.x + 1; x < input.width; x++) + { + if (input.Get(x, it.index.y) >= *it) + { + visible = false; + break; + } + } + if (visible) + { + found.emplace(it.index); + continue; + } + visible = true; + for (int y = it.index.y - 1; y >= 0; y--) + { + if (input.Get(it.index.x, y) >= *it) + { + visible = false; + break; + } + } + if (visible) + { + found.emplace(it.index); + continue; + } + visible = true; + for (int y = it.index.y + 1; y < input.height; y++) + { + if (input.Get(it.index.x, y) >= *it) + { + visible = false; + break; + } + } + if (visible) + { + found.emplace(it.index); + continue; + } + }; + return found.size(); + } + + OUTPUT2(input) + { + int max = 0; + for (auto it = input.begin(); it != input.end(); ++it) + { + int scenic = 1; + bool found = false; + for (int x = it.index.x - 1; x >= 0; x--) + { + if (*it <= input.Get(x, it.index.y)) + { + scenic *= it.index.x - x; + found = true; + break; + } + } + if (!found) + scenic *= it.index.x; + found = false; + for (int x = it.index.x + 1; x < input.width; x++) + { + if (*it <= input.Get(x, it.index.y)) + { + scenic *= x - it.index.x; + found = true; + break; + } + } + if (!found) + scenic *= input.width - it.index.x - 1; + found = false; + for (int y = it.index.y - 1; y >= 0; y--) + { + if (*it <= input.Get(it.index.x, y)) + { + scenic *= it.index.y - y; + found = true; + break; + } + } + if (!found) + scenic *= it.index.y; + found = false; + for (int y = it.index.y + 1; y < input.height; y++) + { + if (*it <= input.Get(it.index.x, y)) + { + scenic *= y - it.index.y; + found = true; + break; + } + } + if (!found) + scenic *= input.height - it.index.y - 1; + max = std::max(max, scenic); + }; + return max; + } +} diff --git a/src/2022/Day09.cpp b/src/2022/Day09.cpp new file mode 100644 index 0000000..34e8071 --- /dev/null +++ b/src/2022/Day09.cpp @@ -0,0 +1,122 @@ +#include "common/aoc.h" + +namespace y$1::day09 +{ + struct Instruction + { + char dir; + int amount; + }; + + REGISTER_DAY(2022, Day09, std::vector, int); + + REGISTER_TEST_EXAMPLE(2022, Day09, ExampleInput, 1, 88); + REGISTER_TEST(2022, Day09, Input, 1, 6011); + REGISTER_TEST_EXAMPLE(2022, Day09, ExampleInput, 2, 36); + REGISTER_TEST(2022, Day09, Input, 2, 2419); + + READ_INPUT(input) + { + std::string str; + std::vector instructions; + while (std::getline(input, str)) + { + std::stringstream ss{str}; + Instruction ins; + ss >> ins.dir >> ins.amount; + instructions.emplace_back(ins); + } + return instructions; + } + + OUTPUT1(input) + { + std::set visited; + Index2D headPos{0, 0}; + Index2D tailPos{0, 0}; + visited.emplace(tailPos); + for (auto& ins : input) + { + for (int i = 0; i < ins.amount; i++) + { + switch (ins.dir) + { + case 'R': + headPos.x++; + break; + case 'U': + headPos.y++; + break; + case 'L': + headPos.x--; + break; + case 'D': + headPos.y--; + break; + } + Index2D diff = headPos - tailPos; + if (std::abs(diff.x) > 1) + { + tailPos.x = headPos.x + (diff.x < 0 ? 1 : -1); + tailPos.y = headPos.y; + visited.emplace(tailPos); + } + else if (std::abs(diff.y) > 1) + { + tailPos.x = headPos.x; + tailPos.y = headPos.y + (diff.y < 0 ? 1 : -1); + visited.emplace(tailPos); + } + } + } + return visited.size(); + } + + OUTPUT2(input) + { + std::set visited; + std::vector bodyPos; + bodyPos.resize(10); + std::fill(bodyPos.begin(), bodyPos.end(), Index2D{0, 0}); + visited.emplace(Index2D{0, 0}); + for (auto& ins : input) + { + for (int i = 0; i < ins.amount; i++) + { + switch (ins.dir) + { + case 'R': + bodyPos[0].x++; + break; + case 'U': + bodyPos[0].y++; + break; + case 'L': + bodyPos[0].x--; + break; + case 'D': + bodyPos[0].y--; + break; + } + for (int i = 1; i < bodyPos.size(); i++) + { + Index2D diff = bodyPos[i - 1] - bodyPos[i]; + if (std::abs(diff.x) > 1) + { + bodyPos[i].x += diff.x < 0 ? -1 : 1; + if (std::abs(diff.y) >= 1) + bodyPos[i].y += diff.y < 0 ? -1 : 1; + } + else if (std::abs(diff.y) > 1) + { + if (std::abs(diff.x) >= 1) + bodyPos[i].x += diff.x < 0 ? -1 : 1; + bodyPos[i].y += diff.y < 0 ? -1 : 1; + } + } + visited.emplace(bodyPos.back()); + } + } + return visited.size(); + } +} diff --git a/src/2022/Day10.cpp b/src/2022/Day10.cpp new file mode 100644 index 0000000..aaa9e9b --- /dev/null +++ b/src/2022/Day10.cpp @@ -0,0 +1,116 @@ +#include "common/aoc.h" + +namespace y$1::day10 +{ + enum class Op + { + Addx, + Noop + }; + + struct Instruction + { + Op op; + int val; + }; + + REGISTER_DAY(2022, Day10, std::vector, int); + + REGISTER_TEST_EXAMPLE(2022, Day10, ExampleInput, 1, 13140); + REGISTER_TEST(2022, Day10, Input, 1, 10760); + REGISTER_TEST_EXAMPLE(2022, Day10, ExampleInput, 2, 124); + REGISTER_TEST(2022, Day10, Input, 2, 100); + + void Draw(int cycle, int value, Array2D& grid) + { + int xPos = cycle % 40; + int yPos = cycle / 40; + if (value - 1 <= xPos && xPos <= value + 1) + grid.Set(xPos, yPos, '#'); + } + + READ_INPUT(input) + { + std::string str; + std::vector instructions; + while (std::getline(input, str)) + { + Instruction instruction; + if (str == "noop") + { + instruction.op = Op::Noop; + instructions.emplace_back(instruction); + } + else + { + std::stringstream ss{str}; + instruction.op = Op::Addx; + ss >> "addx" >> instruction.val; + instructions.emplace_back(instruction); + } + } + return instructions; + } + + OUTPUT1(input) + { + int sum = 0; + int cycle = 1; + int currentCycle = 20; + int value = 1; + for (auto& instruction : input) + { + if (instruction.op == Op::Addx) + { + cycle += 2; + if (cycle > currentCycle) + { + sum += currentCycle * value; + + currentCycle += 40; + } + value += instruction.val; + } + else if (instruction.op == Op::Noop) + { + cycle += 1; + if (cycle > currentCycle) + { + sum += currentCycle * value; + + currentCycle += 40; + } + } + } + return sum; + } + + OUTPUT2(input) + { + Array2D grid{40, 6}; + grid.Fill('.'); + + int cycle = 0; + int value = 1; + + for (auto& instruction : input) + { + Draw(cycle, value, grid); + if (instruction.op == Op::Addx) + { + cycle++; + Draw(cycle, value, grid); + cycle++; + value += instruction.val; + } + else if (instruction.op == Op::Noop) + { + cycle++; + } + } + std::cout << grid << std::endl; + + // Output is text in a grid so do some basic verification on the amount of filled in pixels + return grid.Count('#'); + } +} diff --git a/src/2022/Day11.cpp b/src/2022/Day11.cpp new file mode 100644 index 0000000..31aeb23 --- /dev/null +++ b/src/2022/Day11.cpp @@ -0,0 +1,145 @@ +#include "common/aoc.h" + +namespace y$1::day11 +{ + + enum Op + { + Add, + Mul + }; + + struct Old + { + }; + + struct Monkey + { + std::vector items; + std::variant bin1; + std::variant bin2; + int divisible; + Op op; + int monkeyTrue; + int monkeyFalse; + }; + + REGISTER_DAY(2022, Day11, std::vector, int64_t); + + REGISTER_TEST_EXAMPLE(2022, Day11, ExampleInput, 1, 10605); + REGISTER_TEST(2022, Day11, Input, 1, 120756); + REGISTER_TEST_EXAMPLE(2022, Day11, ExampleInput, 2, 2713310158); + REGISTER_TEST(2022, Day11, Input, 2, 39109444654); + + template + void Round(std::vector& monkeys, std::vector& inspections, Func worryManagement) + { + for (int j = 0; j < monkeys.size(); j++) + { + for (auto item : monkeys[j].items) + { + inspections[j]++; + int64_t i1 = std::holds_alternative(monkeys[j].bin1) ? item : std::get(monkeys[j].bin1); + int64_t i2 = std::holds_alternative(monkeys[j].bin2) ? item : std::get(monkeys[j].bin2); + int64_t val; + + if (monkeys[j].op == Op::Add) + val = i1 + i2; + else if (monkeys[j].op == Op::Mul) + val = i1 * i2; + val = worryManagement(val); + if (val % monkeys[j].divisible == 0) + monkeys[monkeys[j].monkeyTrue].items.emplace_back(val); + else + monkeys[monkeys[j].monkeyFalse].items.emplace_back(val); + } + monkeys[j].items.clear(); + } + } + + READ_INPUT(input) + { + std::string str; + std::vector monkeys; + while (std::getline(input, str)) + { + Monkey monkey; + { // items + std::getline(input, str); + std::stringstream ss{str}; + ss >> "Starting items: "; + while (std::getline(ss, str, ',')) monkey.items.emplace_back(std::stoi(str)); + } + { // operator + std::getline(input, str); + std::stringstream ss{str}; + ss >> "Operation: new = "; + ss >> str; + if (str == "old") + monkey.bin1 = Old{}; + else + monkey.bin1 = std::stoi(str); + char c; + ss >> c; + if (c == '+') + monkey.op = Op::Add; + else if (c == '*') + monkey.op = Op::Mul; + ss >> str; + if (str == "old") + monkey.bin2 = Old{}; + else + monkey.bin2 = std::stoi(str); + } + { // Test + std::getline(input, str); + std::stringstream ss{str}; + ss >> "Test: divisible by " >> monkey.divisible; + } + { // True + std::getline(input, str); + std::stringstream ss{str}; + ss >> "If true: throw to monkey " >> monkey.monkeyTrue; + } + { // False + std::getline(input, str); + std::stringstream ss{str}; + ss >> "If false: throw to monkey " >> monkey.monkeyFalse; + } + std::getline(input, str); + monkeys.emplace_back(monkey); + } + return monkeys; + } + + OUTPUT1(input) + { + std::vector inspections; + inspections.resize(input.size()); + std::vector monkeys = input; + for (int i = 0; i < 20; i++) + { + Round(monkeys, inspections, [](int64_t val) { return val / 3; }); + } + std::sort(inspections.begin(), inspections.end()); + return inspections[inspections.size() - 1] * inspections[inspections.size() - 2]; + } + + OUTPUT2(input) + { + std::vector inspections; + inspections.resize(input.size()); + std::vector monkeys = input; + int mod = 1; + for (auto& monkey : monkeys) + { + mod *= monkey.divisible; + } + for (int i = 0; i < 10000; i++) + { + Round(monkeys, inspections, [mod](int64_t val) { return val % mod; }); + } + std::sort(inspections.begin(), inspections.end()); + return inspections[inspections.size() - 1] * inspections[inspections.size() - 2]; + } +} diff --git a/src/2022/Day12.cpp b/src/2022/Day12.cpp new file mode 100644 index 0000000..c5c5e38 --- /dev/null +++ b/src/2022/Day12.cpp @@ -0,0 +1,91 @@ +#include "common/aoc.h" + +namespace y$1::day12 +{ + REGISTER_DAY(2022, Day12, Array2D, int); + + REGISTER_TEST_EXAMPLE(2022, Day12, ExampleInput, 1, 31); + REGISTER_TEST(2022, Day12, Input, 1, 380); + REGISTER_TEST_EXAMPLE(2022, Day12, ExampleInput, 2, 29); + REGISTER_TEST(2022, Day12, Input, 2, 375); + + int GetElevation(const Array2D& arr, const Index2D& index) + { + int elevation = 0; + char value = arr.Get(index.x, index.y); + if (value == 'S') + elevation = 'a' - 'a'; + else if (value == 'E') + elevation = 'z' - 'a'; + else + elevation = value - 'a'; + return elevation; + } + + std::vector> Branch(const Array2D& arr, Index2D index) + { + std::vector> branches; + int elevation = GetElevation(arr, index); + std::vector neighbors = arr.GetNeighbors(index, false); + for (auto& neighbor : neighbors) + { + int neighElevation = GetElevation(arr, neighbor); + if ((neighElevation - 1 <= elevation)) + branches.emplace_back(1, neighbor); + } + return branches; + } + + std::vector> Branch2(const Array2D& arr, Index2D index) + { + std::vector> branches; + int elevation = GetElevation(arr, index); + std::vector neighbors = arr.GetNeighbors(index, false); + for (auto& neighbor : neighbors) + { + int neighElevation = GetElevation(arr, neighbor); + if (elevation - 1 <= neighElevation) + branches.emplace_back(1, neighbor); + } + return branches; + } + + bool Goal(const Array2D& arr, Index2D index) + { + return arr.Get(index.x, index.y) == 'E'; + } + + bool Goal2(const Array2D& arr, Index2D index) + { + return arr.Get(index.x, index.y) == 'a'; + } + + READ_INPUT(input) + { + return Input::ReadArray2D(input); + } + + OUTPUT1(input) + { + Index2D pos; + for (auto it = input.begin(); it != input.end(); it++) + { + if (*it == 'S') + pos = it.index; + } + + return Helper::Dijkstras(input, pos, Branch, Goal); + } + + OUTPUT2(input) + { + Index2D pos; + for (auto it = input.begin(); it != input.end(); it++) + { + if (*it == 'E') + pos = it.index; + } + + return Helper::Dijkstras(input, pos, Branch2, Goal2); + } +} diff --git a/src/2022/Day13.cpp b/src/2022/Day13.cpp new file mode 100644 index 0000000..902e0fa --- /dev/null +++ b/src/2022/Day13.cpp @@ -0,0 +1,133 @@ +#include "common/aoc.h" + +namespace y$1::day13 +{ + struct Node + { + std::variant> nodes; + + bool operator==(const Node& rhs) const + { + return nodes == rhs.nodes; + } + + bool operator<(const Node& rhs) const + { + if (std::holds_alternative(nodes) && std::holds_alternative(rhs.nodes)) + { + return std::get(nodes) < std::get(rhs.nodes); + } + else + { + if (std::holds_alternative(nodes)) + { + Node node; + node.nodes = std::vector{Node{std::get(nodes)}}; + return node < rhs; + } + else if (std::holds_alternative(rhs.nodes)) + { + Node node; + node.nodes = std::vector{Node{std::get(rhs.nodes)}}; + return *this < node; + } + else + { + const std::vector& lhsNodes = std::get>(nodes); + const std::vector& rhsNodes = std::get>(rhs.nodes); + for (int i = 0; i < std::min(lhsNodes.size(), rhsNodes.size()); i++) + { + if (lhsNodes[i] < rhsNodes[i]) + { + return true; + } + else if (rhsNodes[i] < lhsNodes[i]) + { + return false; + } + } + return lhsNodes.size() < rhsNodes.size(); + } + } + } + }; + + REGISTER_DAY(2022, Day13, std::vector, int); + + REGISTER_TEST_EXAMPLE(2022, Day13, ExampleInput, 1, 13); + REGISTER_TEST(2022, Day13, Input, 1, 5843); + REGISTER_TEST_EXAMPLE(2022, Day13, ExampleInput, 2, 140); + REGISTER_TEST(2022, Day13, Input, 2, 26289); + + void ParseTree(const std::string& str, int& index, Node& parent) + { + std::vector nodes{}; + while (index < str.size()) + { + if (str[index] == '[') + { + index++; + Node node; + ParseTree(str, index, node); + nodes.emplace_back(node); + index++; + } + else if (str[index] >= '0' && str[index] <= '9') + { + Node node; + node.nodes = std::stoi(str.substr(index)); + nodes.emplace_back(node); + while (str[index] >= '0' && str[index] <= '9') index++; + } + else + { + break; + } + if (str[index] != ',') + break; + index++; + } + parent.nodes = nodes; + } + + READ_INPUT(input) + { + std::string str; + std::vector trees; + while (std::getline(input, str)) + { + if (str.empty()) + continue; + Node root; + int index = 1; + ParseTree(str, index, root); + trees.emplace_back(root); + } + return trees; + } + + OUTPUT1(input) + { + int sum = 0; + for (int i = 0; i < input.size(); i += 2) + { + if (input[i] < input[i + 1]) + sum += i / 2 + 1; + } + return sum; + } + + OUTPUT2(input) + { + std::vector nodes = input; + Node key1 = Node{std::vector{Node{2}}}; + Node key2 = Node{std::vector{Node{6}}}; + nodes.emplace_back(key1); + nodes.emplace_back(key2); + std::sort(nodes.begin(), nodes.end()); + auto it1 = std::find(nodes.begin(), nodes.end(), key1); + auto it2 = std::find(nodes.begin(), nodes.end(), key2); + + return (std::distance(nodes.begin(), it1) + 1) * (std::distance(nodes.begin(), it2) + 1); + } +} diff --git a/src/2022/Day14.cpp b/src/2022/Day14.cpp new file mode 100644 index 0000000..a359b2b --- /dev/null +++ b/src/2022/Day14.cpp @@ -0,0 +1,133 @@ +#include "common/aoc.h" + +namespace y$1::day14 +{ + REGISTER_DAY(2022, Day14, std::set, int); + + REGISTER_TEST_EXAMPLE(2022, Day14, ExampleInput, 1, 24); + REGISTER_TEST(2022, Day14, Input, 1, 768); + REGISTER_TEST_EXAMPLE(2022, Day14, ExampleInput, 2, 93); + REGISTER_TEST(2022, Day14, Input, 2, 26686); + + READ_INPUT(input) + { + std::string str; + std::set occupied; + int sum = 0; + while (std::getline(input, str)) + { + std::stringstream ss{str}; + Index2D start; + ss >> start.x >> "," >> start.y; + while ((ss >> "->")) + { + Index2D next; + ss >> next.x >> "," >> next.y; + for (int y = std::min(start.y, next.y); y <= std::max(start.y, next.y); y++) + { + for (int x = std::min(start.x, next.x); x <= std::max(start.x, next.x); x++) + { + occupied.emplace(Index2D{x, y}); + } + } + start = next; + } + } + return occupied; + } + + OUTPUT1(input) + { + int maxY = input.begin()->y; + for (auto& index : input) + { + maxY = std::max(maxY, index.y); + } + maxY += 2; + Array2D grid{maxY * 2 - 1, maxY}; + grid.Fill('.'); + for (auto& index : input) + { + grid.Set(index.x - 500 + maxY - 1, index.y, '#'); + } + while (true) + { + Index2D sand{maxY - 1, 0}; + while (true) + { + if (sand.y >= maxY - 2) + return grid.Count('o'); + else if (grid.Get(sand.x, sand.y + 1) == '.') + sand.y++; + else if (grid.Get(sand.x - 1, sand.y + 1) == '.') + { + sand.x--; + sand.y++; + } + else if (grid.Get(sand.x + 1, sand.y + 1) == '.') + { + sand.x++; + sand.y++; + } + else + { + grid.Set(sand.x, sand.y, 'o'); + break; + } + } + } + return 0; + return 0; + } + + OUTPUT2(input) + { + int maxY = input.begin()->y; + for (auto& index : input) + { + maxY = std::max(maxY, index.y); + } + maxY += 2; + Array2D grid{maxY * 2 - 1, maxY}; + grid.Fill('.'); + for (auto& index : input) + { + grid.Set(index.x - 500 + maxY - 1, index.y, '#'); + } + while (true) + { + Index2D sand{maxY - 1, 0}; + while (true) + { + if (grid.Get(sand.x, sand.y + 1) == '.') + sand.y++; + else if (grid.Get(sand.x - 1, sand.y + 1) == '.') + { + sand.x--; + sand.y++; + } + else if (grid.Get(sand.x + 1, sand.y + 1) == '.') + { + sand.x++; + sand.y++; + } + else if (sand.y == 0) + { + grid.Set(sand.x, sand.y, 'o'); + return grid.Count('o'); + } + else + { + grid.Set(sand.x, sand.y, 'o'); + break; + } + if (sand.y + 1 >= maxY) + { + grid.Set(sand.x, sand.y, 'o'); + break; + } + } + } + return 0; + } +} diff --git a/src/2022/Day15.cpp b/src/2022/Day15.cpp new file mode 100644 index 0000000..c0f23c9 --- /dev/null +++ b/src/2022/Day15.cpp @@ -0,0 +1,259 @@ +#include "common/aoc.h" + +namespace y$1::day15 +{ + struct Scanner + { + Index2D position; + Index2D beacon; + }; + + REGISTER_DAY(2022, Day15, std::vector, int64_t); + + REGISTER_TEST_EXAMPLE(2022, Day15, ExampleInput, 1, 26); + REGISTER_TEST(2022, Day15, Input, 1, 5564017); + REGISTER_TEST_EXAMPLE(2022, Day15, ExampleInput, 2, 56000011); + REGISTER_TEST(2022, Day15, Input, 2, 11558423398893); + + struct Line + { + int start; + int end; + + bool operator<(const Line& rhs) const + { + if (start == rhs.start) + return end < rhs.end; + return start < rhs.start; + } + }; + + bool IsOverlap(const Line& l1, const Line& l2) + { + return (l1.start >= l2.start && l1.end <= l2.end) || (l2.start >= l1.start && l2.end <= l1.end); + } + + READ_INPUT(input) + { + std::string str; + std::vector scanners; + while (std::getline(input, str)) + { + std::stringstream ss{str}; + Scanner scanner; + ss >> "Sensor at x=" >> scanner.position.x >> ", y=" >> scanner.position.y >> ": closest beacon is at x=" >> + scanner.beacon.x >> ", y=" >> scanner.beacon.y; + scanners.emplace_back(scanner); + } + return scanners; + } + + OUTPUT1(input) + { + int row = 2000000; + if (isExample) + { + row = 10; + } + std::set lines; + for (auto& scanner : input) + { + Index2D diff = scanner.position - scanner.beacon; + int manhattan = std::abs(diff.x) + std::abs(diff.y); + if ((scanner.position.y <= row && scanner.position.y + manhattan >= row) || + (scanner.position.y >= row && scanner.position.y - manhattan <= row)) + { + int distance = std::abs(row - scanner.position.y); + int count = manhattan * 2 + 1 - (distance) * 2; + Line line; + line.start = scanner.position.x - count / 2; + line.end = scanner.position.x + count / 2; + lines.emplace(line); + } + } + int min = lines.begin()->start; + int max = lines.begin()->end; + for (auto& line : lines) + { + min = std::min(min, line.start); + max = std::max(max, line.end); + } + std::set beacons; + for (auto& scanner : input) + { + if (scanner.beacon.y == row && scanner.beacon.x >= min && scanner.beacon.x <= max) + beacons.emplace(scanner.beacon); + } + + return max - min + 1 - beacons.size(); + } + +#if 0 + OUTPUT2(input) + { + Array2D grid{20, 20}; + grid.Fill('.'); + for (int y = 0; y < 20; y++) + { + for (int x = 0; x < 20; x++) + { + int i = 0; + for (auto& scanner : input) + { + if (Index2D{x, y} == scanner.position) + grid.Set(x, y, 'A' + i); + else + { + Index2D diff = scanner.position - scanner.beacon; + int manhattan = std::abs(diff.x) + std::abs(diff.y); + int manhattan2 = std::abs(scanner.position.x - x) + std::abs(scanner.position.y - y); + if (manhattan2 <= manhattan) { + grid.Set(x, y, 'a' + i); + } + } + i++; + } + + } + } + std::cout << grid << std::endl; + return 0; + // return (int64_t)2889604 * (int64_t)4000000 + (int64_t)3398893; + int row = 4000000; + if (isExample) + row = 20; + for (int i = 0; i < row; i++) + { + std::set lines; + for (auto& scanner : input) { + Index2D diff = scanner.position - scanner.beacon; + int manhattan = std::abs(diff.x) + std::abs(diff.y); + if ((scanner.position.y <= i && scanner.position.y + manhattan >= i) || (scanner.position.y >= i && scanner.position.y - manhattan <= i )) + { + int distance = std::abs(i - scanner.position.y); + int count = manhattan * 2 + 1 - (distance) * 2; + Line line; + line.start = scanner.position.x - count / 2; + line.end = scanner.position.x + count / 2; + lines.emplace(line); + } + } + std::vector nonOverlappingLines; + if (lines.size() > 0) + { + Line currentLine = *lines.begin(); + for (auto& line : lines) + { + if (currentLine.end + 1 < line.start) + { + std::cout << "Row: " << i << "Pos: " << currentLine.end << std::endl; + return (int64_t)(currentLine.end + 1) * (int64_t)4000000 + (int64_t)i; + nonOverlappingLines.emplace_back(currentLine); + currentLine = line; + } + else + currentLine.end = std::max(currentLine.end, line.end); + } + nonOverlappingLines.emplace_back(currentLine); + // std::cout << "Size: " << nonOverlappingLines.size() << std::endl; + } + } + return 10; + } +#else + int Manhattan(const Index2D& i1, const Index2D& i2) + { + return std::abs(i1.x - i2.x) + std::abs(i1.y - i2.y); + } + + bool CheckDistances(const Scanner& scanner1, const Scanner& scanner2) + { + int manhattan1 = Manhattan(scanner1.position, scanner1.beacon); + int manhattan2 = Manhattan(scanner2.position, scanner2.beacon); + int manhattan3 = Manhattan(scanner1.position, scanner2.position); + return manhattan1 + manhattan2 + 2 >= manhattan3; + } + + std::vector GetOneAway(const Scanner& scanner1, const Scanner& scanner2, const Scanner& scanner3, int range) + { + std::vector valid; + int distance = Manhattan(scanner1.position, scanner1.beacon) + 1; + for (int i = 0; i < distance * 2; i++) + { + int y = scanner1.position.y + distance - i; + if (y >= 0 && y <= range) + { + if (i >= distance) + { + if (scanner1.position.x + distance * 2 - i >= 0 && scanner1.position.x + distance * 2 - i <= range) + valid.emplace_back(scanner1.position + Index2D{distance * 2 - i, distance - i}); + if (scanner1.position.x - distance * 2 + i >= 0 && scanner1.position.x - distance * 2 + i <= range) + valid.emplace_back(scanner1.position + Index2D{i - distance * 2, distance - i}); + } + else + { + if (scanner1.position.x + i >= 0 && scanner1.position.x + i <= range) + valid.emplace_back(scanner1.position + Index2D{i, distance - i}); + if (scanner1.position.x - i >= 0 && scanner1.position.x - i <= range) + valid.emplace_back(scanner1.position + Index2D{-i, distance - i}); + } + } + } + std::vector valid2; + for (auto& pos : valid) + { + if (Manhattan(pos, scanner2.position) == Manhattan(scanner2.position, scanner2.beacon) + 1) + { + valid2.emplace_back(pos); + } + } + std::vector valid3; + for (auto& pos : valid2) + { + if (Manhattan(pos, scanner3.position) == Manhattan(scanner3.position, scanner3.beacon) + 1) + { + valid3.emplace_back(pos); + } + } + return valid3; + } + + OUTPUT2(input) + { + int range = 4000000; + if (isExample) + range = 20; + for (int i = 0; i < input.size(); i++) + { + for (int j = i + 1; j < input.size(); j++) + { + if (CheckDistances(input[i], input[j])) + { + for (int k = j + 1; k < input.size(); k++) + { + if (CheckDistances(input[i], input[k]) && CheckDistances(input[j], input[k])) + { + std::vector valid = GetOneAway(input[i], input[j], input[k], range); + for (auto& pos : valid) + { + bool found = true; + for (auto& scanner : input) + { + if (Manhattan(scanner.position, pos) <= Manhattan(scanner.position, scanner.beacon)) + { + found = false; + break; + } + } + if (found) + return (int64_t)pos.x * 4000000 + (int64_t)pos.y; + } + } + } + } + } + } + return 0; + } +#endif +} diff --git a/src/2022/Day16.cpp b/src/2022/Day16.cpp new file mode 100644 index 0000000..70c0ae2 --- /dev/null +++ b/src/2022/Day16.cpp @@ -0,0 +1,200 @@ +#include "common/aoc.h" + +namespace y$1::day16 +{ + struct Node + { + std::string name; + int flowrate; + std::set paths; + + bool operator<(const Node& rhs) const + { + return name < rhs.name; + } + }; + + std::vector> Branch(const std::set& nodes, const std::string& str) + { + Node n; + n.name = str; + const Node& node = *nodes.find(n); + std::vector> branches; + for (auto& path : node.paths) + { + branches.emplace_back(1, path); + } + return branches; + } + + int GetDistance(const std::set& nodes, + const std::string& from, + const std::string& to, + std::map& distances) + { + std::string s = from + to; + if (to < from) + s = to + from; + auto it = distances.find(s); + int distance = 0; + if (it != distances.end()) + distance = it->second; + else + { + distance = Helper::Dijkstras( + nodes, from, Branch, [to](const std::set& nodes, const std::string& str) { return str == to; }); + distances.emplace(s, distance); + } + return distance; + } + + int FindMax(const std::set& nodes, + std::map& distances, + const std::string& currentNode, + const std::set& visit, + int timeLeft, + int pressure) + { + if (timeLeft < 0) + return 0; + if (visit.empty()) + return pressure; + int max = pressure; + for (auto& node : visit) + { + Node newNode; + newNode.name = node; + std::set newVisit = visit; + int newTimeLeft = timeLeft - (GetDistance(nodes, currentNode, node, distances) + 1); + int newPressure = pressure + newTimeLeft * nodes.find(newNode)->flowrate; + newVisit.erase(node); + + max = std::max(max, FindMax(nodes, distances, node, newVisit, newTimeLeft, newPressure)); + } + return max; + } + + void FindMax(const std::set& nodes, + std::map& distances, + const std::string& currentNode, + const std::set& visit, + int timeLeft, + int pressure, + int currentBits, + std::vector& best, + const std::map& nodeIndex) + { + if (timeLeft < 0) + return; + best[currentBits] = std::max(best[currentBits], pressure); + for (auto& node : visit) + { + Node newNode; + newNode.name = node; + std::set newVisit = visit; + int newTimeLeft = timeLeft - (GetDistance(nodes, currentNode, node, distances) + 1); + int newPressure = pressure + newTimeLeft * nodes.find(newNode)->flowrate; + newVisit.erase(node); + + int bits = currentBits | (1 << (nodeIndex.find(node)->second)); + + FindMax(nodes, distances, node, newVisit, newTimeLeft, newPressure, bits, best, nodeIndex); + } + } + + std::pair, std::set> Split(const std::vector& nodes, int bits) + { + std::pair, std::set> pairs; + for (int i = 0; i < nodes.size(); i++) + { + if (bits & 1) + pairs.first.emplace(nodes[i]); + else + pairs.second.emplace(nodes[i]); + bits >>= 1; + } + return pairs; + } + + REGISTER_DAY(2022, Day16, std::set, int); + + REGISTER_TEST_EXAMPLE(2022, Day16, ExampleInput, 1, 1651); + REGISTER_TEST(2022, Day16, Input, 1, 1775); + REGISTER_TEST_EXAMPLE(2022, Day16, ExampleInput, 2, 1707); + REGISTER_TEST(2022, Day16, Input, 2, 2351); + + READ_INPUT(input) + { + std::string str; + std::set nodes; + while (std::getline(input, str)) + { + std::stringstream ss{str}; + Node node; + ss >> "Valve" >> node.name >> "has flow rate=" >> node.flowrate >> "; tunnel"; + if (ss.peek() == 's') + ss >> "s lead to valves"; + else + ss >> "leads to valve"; + while (std::getline(ss, str, ',')) + { + if (str.front() == ' ') + str = str.substr(1); + node.paths.emplace(str); + } + nodes.emplace(node); + } + return nodes; + } + + OUTPUT1(input) + { + std::map distances; + std::set nodes; + for (auto& node : input) + { + if (node.flowrate != 0) + nodes.emplace(node.name); + } + + return FindMax(input, distances, "AA", nodes, 30, 0); + } + + OUTPUT2(input) + { + if (true) + { + std::map distances; + std::map nodeIndices; + std::set nodes; + int i = 0; + for (auto& node : input) + { + if (node.flowrate != 0) + { + nodes.emplace(node.name); + nodeIndices.emplace(node.name, i++); + } + } + std::vector best; + best.resize(1 << nodes.size()); + + FindMax(input, distances, "AA", nodes, 26, 0, 0, best, nodeIndices); + int mask = (1 << nodes.size()) - 1; + int max = 0; + for (int i = 0; i < best.size(); i++) + { + int max2 = 0; + for (int j = 0; j < best.size(); j++) + { + if ((j | ((~i) & mask)) == ((~i) & mask)) + { + max2 = std::max(max2, best[j]); + } + } + max = std::max(max, best[i] + max2); + } + return max; + } + } +} diff --git a/src/2022/Day17.cpp b/src/2022/Day17.cpp new file mode 100644 index 0000000..4544541 --- /dev/null +++ b/src/2022/Day17.cpp @@ -0,0 +1,200 @@ +#include "common/aoc.h" + +namespace y$1::day17 +{ + Array2D block1{4, 1, {'#', '#', '#', '#'}}; + Array2D block2{3, 3, {'.', '#', '.', '#', '#', '#', '.', '#', '.'}}; + Array2D block3{3, 3, {'#', '#', '#', '.', '.', '#', '.', '.', '#'}}; + Array2D block4{1, 4, {'#', '#', '#', '#'}}; + Array2D block5{2, 2, {'#', '#', '#', '#'}}; + std::vector> blocks{block1, block2, block3, block4, block5}; + + bool Overlap(const Array2D& grid, const Array2D& block, int xOffset, int yOffset) + { + for (int y = 0; y < block.height; y++) + { + for (int x = 0; x < block.width; x++) + { + if (block.Get(x, y) == '#' && grid.Get(x + xOffset, y + yOffset) == '#') + { + return true; + } + } + } + return false; + } + + void Set(Array2D& grid, const Array2D& block, int xOffset, int yOffset) + { + for (int y = 0; y < block.height; y++) + { + for (int x = 0; x < block.width; x++) + { + if (block.Get(x, y) == '#') + { + grid.Set(x + xOffset, y + yOffset, '#'); + } + } + } + } + + void Print(const Array2D& grid, int height) + { + for (int y = height; y >= 0; y--) + { + for (int x = 0; x < grid.width; x++) + { + std::cout << grid.Get(x, y); + } + std::cout << std::endl; + } + std::cout << std::endl; + } + + REGISTER_DAY(2022, Day17, std::string, int64_t); + + REGISTER_TEST_EXAMPLE(2022, Day17, ExampleInput, 1, 3068); + REGISTER_TEST(2022, Day17, Input, 1, 3065); + // REGISTER_TEST_EXAMPLE(2022, Day17, ExampleInput, 2, 0); + REGISTER_TEST(2022, Day17, Input, 2, 1562536022966); + + READ_INPUT(input) + { + std::string str; + std::getline(input, str); + return str; + } + + OUTPUT1(input) + { + int j = 0; + int index = 0; + Array2D grid{7, 4044}; + grid.Fill('.'); + int top = 0; + int piece = 0; + for (int i = 0; i < 2022; i++) + { + Array2D block = blocks[piece]; + piece++; + piece %= blocks.size(); + + int x = 2; + int y = top + 3; + while (true) + { + if (input[index++] == '>') + { + x++; + if (x + block.width > 7) + x--; + else if (Overlap(grid, block, x, y)) + x--; + } + else + { + x--; + if (x < 0) + x++; + else if (Overlap(grid, block, x, y)) + x++; + } + index %= input.size(); + y--; + if (y < 0 || Overlap(grid, block, x, y)) + { + y++; + Set(grid, block, x, y); + top = std::max(top, y + block.height); + break; + } + } + j++; + } + return top; + } + + OUTPUT2(input) + { + int blockIndex = 0; + int index = 0; + Array2D grid{7, 10000}; + grid.Fill('.'); + int top = 0; + int piece = 0; + std::map, std::pair> state; + int loopStart = 0; + int loopStartHeight = 0; + int loopSize = 0; + int loopTopDiff = 0; + std::pair loop; + + int64_t total = 1000000000000; + for (int64_t i = 0; i < total; i++) + { + Array2D block = blocks[piece]; + piece++; + piece %= blocks.size(); + + int x = 2; + int y = top + 3; + while (true) + { + if (input[index++] == '>') + { + x++; + if (x + block.width > 7) + x--; + else if (Overlap(grid, block, x, y)) + x--; + } + else + { + x--; + if (x < 0) + x++; + else if (Overlap(grid, block, x, y)) + x++; + } + index %= input.size(); + y--; + if (y < 0 || Overlap(grid, block, x, y)) + { + y++; + Set(grid, block, x, y); + top = std::max(top, y + block.height); + if (loopStart == 0) + { + bool found = true; + for (int x = 0; x < grid.width; x++) + { + if (grid.Get(x, top - 1) != '#') + { + found = false; + break; + } + } + if (found) + { + auto it = state.find({piece, index}); + if (it != state.end()) + { + loopStart = it->second.first; + loopStartHeight = it->second.second; + loopSize = blockIndex - it->second.first; + loopTopDiff = top - it->second.second; + int64_t fastForward = (total - loopStart) / loopSize; + fastForward = fastForward * loopSize + loopStart; + i = fastForward; + } + state.emplace(std::pair{piece, index}, std::pair{blockIndex, top}); + } + } + break; + } + } + blockIndex++; + } + return top - loopTopDiff + (total - loopStart) / loopSize * loopTopDiff; + } +} diff --git a/src/2022/Day18.cpp b/src/2022/Day18.cpp new file mode 100644 index 0000000..82e54cf --- /dev/null +++ b/src/2022/Day18.cpp @@ -0,0 +1,105 @@ +#include "common/aoc.h" + +namespace y$1::day18 +{ + REGISTER_DAY(2022, Day18, Array3D, int); + + REGISTER_TEST_EXAMPLE(2022, Day18, ExampleInput, 1, 64); + REGISTER_TEST(2022, Day18, Input, 1, 4504); + REGISTER_TEST_EXAMPLE(2022, Day18, ExampleInput, 2, 58); + REGISTER_TEST(2022, Day18, Input, 2, 2556); + + READ_INPUT(input) + { + std::string str; + std::vector indices; + Index3D min; + Index3D max; + while (std::getline(input, str)) + { + std::stringstream ss{str}; + Index3D index; + ss >> index.x >> "," >> index.y >> "," >> index.z; + if (!min.IsValid()) + min = index; + if (!max.IsValid()) + max = index; + min.x = std::min(min.x, index.x); + min.y = std::min(min.y, index.y); + min.z = std::min(min.z, index.z); + max.x = std::max(max.x, index.x); + max.y = std::max(max.y, index.y); + max.z = std::max(max.z, index.z); + indices.emplace_back(index); + } + Array3D grid{max.x - min.x + 3, max.y - min.y + 3, max.z - min.z + 3}; + grid.Fill('.'); + for (auto& index : indices) + { + grid.Set(index.x - min.x + 1, index.y - min.y + 1, index.z - min.z + 1, '#'); + } + + return grid; + } + + OUTPUT1(input) + { + int sum = 0; + std::vector neighbors{ + Index3D{-1, 0, 0}, Index3D{1, 0, 0}, Index3D{0, -1, 0}, Index3D{0, 1, 0}, Index3D{0, 0, -1}, Index3D{0, 0, 1}}; + for (auto it = input.begin(); it != input.end(); ++it) + { + if (*it != '#') + continue; + sum += neighbors.size(); + + for (auto& neighbor : neighbors) + { + Index3D i = it.index + neighbor; + if (input.IsInside(i) && input.Get(i) == '#') + sum--; + } + } + return sum; + } + + OUTPUT2(input) + { + int sum = 0; + std::set visited; + std::stack stack; + stack.emplace(Index3D{0, 0, 0}); + std::vector neighbors{ + Index3D{-1, 0, 0}, Index3D{1, 0, 0}, Index3D{0, -1, 0}, Index3D{0, 1, 0}, Index3D{0, 0, -1}, Index3D{0, 0, 1}}; + while (!stack.empty()) + { + Index3D index = stack.top(); + stack.pop(); + + for (auto& neighbor : neighbors) + { + Index3D i = index + neighbor; + if (input.IsInside(i)) + { + if (visited.count(i) == 0 && input.Get(i) == '.') + { + visited.emplace(i); + stack.emplace(i); + } + } + } + } + for (auto& index : visited) + { + for (auto& neighbor : neighbors) + { + Index3D i = index + neighbor; + if (input.IsInside(i) && input.Get(i) == '#') + { + sum++; + } + } + } + return sum; + } +} diff --git a/src/2022/Day19.cpp b/src/2022/Day19.cpp new file mode 100644 index 0000000..b281790 --- /dev/null +++ b/src/2022/Day19.cpp @@ -0,0 +1,145 @@ +#include "common/aoc.h" + +namespace y$1::day19 +{ + struct Blueprint + { + int oreOreCost; + int clayOreCost; + int obsidianOreCost; + int obsidianClayCost; + int geodeOreCost; + int geodeObsidianCost; + }; + + struct Robots + { + int ore = 1; + int clay = 0; + int obsidian = 0; + int geode = 0; + }; + + struct Materials + { + int ore = 0; + int clay = 0; + int obsidian = 0; + int geode = 0; + }; + + REGISTER_DAY(2022, Day19, std::vector, int); + + REGISTER_TEST_EXAMPLE(2022, Day19, ExampleInput, 1, 33); + REGISTER_TEST(2022, Day19, Input, 1, 600); + REGISTER_TEST_EXAMPLE(2022, Day19, ExampleInput, 2, 3472); + REGISTER_TEST(2022, Day19, Input, 2, 6000); + + READ_INPUT(input) + { + std::string str; + std::vector blueprints; + while (std::getline(input, str)) + { + std::stringstream ss{str}; + Blueprint blueprint; + int i = 0; + // Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 3 ore and 14 + // clay. Each geode robot costs 2 ore and 7 obsidian. + ss >> "Blueprint" >> i >> ": Each ore robot costs" >> blueprint.oreOreCost >> "ore. Each clay robot costs" >> + blueprint.clayOreCost >> "ore. Each obsidian robot costs" >> blueprint.obsidianOreCost >> "ore and" >> + blueprint.obsidianClayCost >> "clay. Each geode robot costs" >> blueprint.geodeOreCost >> "ore and" >> + blueprint.geodeObsidianCost; + blueprints.emplace_back(blueprint); + } + return blueprints; + } + + void Mine(const Robots& robots, Materials& materials) + { + materials.ore += robots.ore; + materials.clay += robots.clay; + materials.obsidian += robots.obsidian; + materials.geode += robots.geode; + } + + int Max(const Blueprint& blueprint, Robots robots, Materials materials, int timeLeft) + { + if (timeLeft == 0) + return materials.geode; + timeLeft--; + + int max = 0; + + int maxOresNeeded = + std::max({blueprint.oreOreCost, blueprint.clayOreCost, blueprint.obsidianOreCost, blueprint.geodeOreCost}); + + if (materials.ore - robots.ore < blueprint.oreOreCost && materials.ore >= blueprint.oreOreCost && + robots.ore < maxOresNeeded) + { + Robots newRobots = robots; + Materials newMaterials = materials; + Mine(newRobots, newMaterials); + newRobots.ore++; + newMaterials.ore -= blueprint.oreOreCost; + max = std::max(max, Max(blueprint, newRobots, newMaterials, timeLeft)); + } + if (materials.ore - robots.ore < blueprint.clayOreCost && materials.ore >= blueprint.clayOreCost && + robots.clay < blueprint.obsidianClayCost) + { + Robots newRobots = robots; + Materials newMaterials = materials; + Mine(newRobots, newMaterials); + newRobots.clay++; + newMaterials.ore -= blueprint.clayOreCost; + max = std::max(max, Max(blueprint, newRobots, newMaterials, timeLeft)); + } + if ((materials.ore - robots.ore < blueprint.obsidianOreCost || + materials.clay - robots.clay < blueprint.obsidianClayCost) && + materials.ore >= blueprint.obsidianOreCost && materials.clay >= blueprint.obsidianClayCost && + robots.obsidian < blueprint.geodeObsidianCost) + { + Robots newRobots = robots; + Materials newMaterials = materials; + Mine(newRobots, newMaterials); + newRobots.obsidian++; + newMaterials.ore -= blueprint.obsidianOreCost; + newMaterials.clay -= blueprint.obsidianClayCost; + max = std::max(max, Max(blueprint, newRobots, newMaterials, timeLeft)); + } + if ((materials.ore - robots.ore < blueprint.geodeOreCost || + materials.obsidian - robots.obsidian < blueprint.geodeObsidianCost) && + materials.ore >= blueprint.geodeOreCost && materials.obsidian >= blueprint.geodeObsidianCost) + { + Robots newRobots = robots; + Materials newMaterials = materials; + Mine(newRobots, newMaterials); + newRobots.geode++; + newMaterials.ore -= blueprint.geodeOreCost; + newMaterials.obsidian -= blueprint.geodeObsidianCost; + max = std::max(max, Max(blueprint, newRobots, newMaterials, timeLeft)); + } + Mine(robots, materials); + return std::max(max, Max(blueprint, robots, materials, timeLeft)); + } + + OUTPUT1(input) + { + int sum = 0; + for (int i = 0; i < input.size(); i++) + { + sum += (i + 1) * Max(input[i], Robots{}, Materials{}, 24); + } + return sum; + } + + OUTPUT2(input) + { + int sum = 1; + for (int i = 0; i < input.size() && i < 3; i++) + { + sum *= Max(input[i], Robots{}, Materials{}, 32); + } + return sum; + } +} diff --git a/src/2022/Day20.cpp b/src/2022/Day20.cpp new file mode 100644 index 0000000..ed2d654 --- /dev/null +++ b/src/2022/Day20.cpp @@ -0,0 +1,76 @@ +#include "common/aoc.h" + +namespace y$1::day20 +{ + REGISTER_DAY(2022, Day20, std::vector, int64_t); + + REGISTER_TEST_EXAMPLE(2022, Day20, ExampleInput, 1, 3); + REGISTER_TEST(2022, Day20, Input, 1, 988); + REGISTER_TEST_EXAMPLE(2022, Day20, ExampleInput, 2, 1623178306); + REGISTER_TEST(2022, Day20, Input, 2, 7768531372516); + + READ_INPUT(input) + { + return Input::ReadInts(input); + } + + OUTPUT1(input) + { + int sum = 0; + std::vector> newList; + for (int i = 0; i < input.size(); i++) + { + newList.emplace_back(input[i], i); + } + for (int i = 0; i < input.size(); i++) + { + auto it = std::find_if(newList.begin(), newList.end(), [i](auto& p) { return p.second == i; }); + int distance = std::distance(newList.begin(), it); + if (input[i] == 0) + continue; + int newPos = (distance + input[i]) % ((int)input.size() - 1); + if (newPos < 0) + newPos += (int)newList.size() - 1; + std::pair p = *it; + newList.erase(it); + newList.insert(newList.begin() + newPos, p); + } + // std::sort(newList.begin(), newList.end(), [](auto& p1, auto& p2) { return p1.second < p2.second; }); + auto it = std::find_if(newList.begin(), newList.end(), [](const std::pair& p1) { return p1.first == 0; }); + int pos = std::distance(newList.begin(), it); + return newList[(pos + 1000) % input.size()].first + newList[(pos + 2000) % input.size()].first + + newList[(pos + 3000) % input.size()].first; + } + + OUTPUT2(input) + { + int sum = 0; + std::vector> newList; + for (int i = 0; i < input.size(); i++) + { + newList.emplace_back((int64_t)input[i] * (int64_t)811589153, i); + } + for (int j = 0; j < 10; j++) + { + for (int i = 0; i < input.size(); i++) + { + auto it = std::find_if(newList.begin(), newList.end(), [i](auto& p) { return p.second == i; }); + int oldPos = std::distance(newList.begin(), it); + if (it->first == 0) + continue; + int newPos = (oldPos + it->first) % ((int64_t)input.size() - 1); + if (newPos < 0) + newPos += (int64_t)newList.size() - 1; + std::pair p = *it; + newList.erase(it); + newList.insert(newList.begin() + newPos, p); + } + } + // std::sort(newList.begin(), newList.end(), [](auto& p1, auto& p2) { return p1.second < p2.second; }); + auto it = + std::find_if(newList.begin(), newList.end(), [](const std::pair& p1) { return p1.first == 0; }); + int pos = std::distance(newList.begin(), it); + return newList[(pos + 1000) % input.size()].first + newList[(pos + 2000) % input.size()].first + + newList[(pos + 3000) % input.size()].first; + } +} diff --git a/src/2022/Day21.cpp b/src/2022/Day21.cpp new file mode 100644 index 0000000..365ee7a --- /dev/null +++ b/src/2022/Day21.cpp @@ -0,0 +1,184 @@ +#include "common/aoc.h" + +namespace y$1::day21 +{ + enum class Operator + { + Add, + Mul, + Sub, + Div + + }; + + struct Operation + { + std::string lhs; + std::string rhs; + Operator op; + }; + + struct Monkey + { + std::string name; + std::variant yell; + + bool operator<(const Monkey& rhs) const + { + return name < rhs.name; + } + }; + + REGISTER_DAY(2022, Day21, std::set, int64_t); + + REGISTER_TEST_EXAMPLE(2022, Day21, ExampleInput, 1, 152); + REGISTER_TEST(2022, Day21, Input, 1, 160274622817992); + REGISTER_TEST_EXAMPLE(2022, Day21, ExampleInput, 2, 301); + REGISTER_TEST(2022, Day21, Input, 2, 3087390115721); + + READ_INPUT(input) + { + std::string str; + std::set monkeys; + while (std::getline(input, str)) + { + std::stringstream ss{str}; + Monkey monkey; + ss >> monkey.name; + monkey.name.pop_back(); // remove : + + if (str[6] >= '0' && str[6] <= '9') + { + int64_t i; + ss >> i; + monkey.yell = i; + } + else + { + Operation operation; + char c; + ss >> operation.lhs; + ss >> c; + ss >> operation.rhs; + if (c == '+') + operation.op = Operator::Add; + if (c == '-') + operation.op = Operator::Sub; + if (c == '*') + operation.op = Operator::Mul; + if (c == '/') + operation.op = Operator::Div; + monkey.yell = operation; + } + monkeys.emplace(monkey); + } + return monkeys; + } + + int64_t Resolve(const std::set& monkeys, const std::string& name) + { + Monkey findMonkey; + findMonkey.name = name; + const Monkey& monkey = *monkeys.find(findMonkey); + if (std::holds_alternative(monkey.yell)) + return std::get(monkey.yell); + + const Operation& operation = std::get(monkey.yell); + switch (operation.op) + { + case Operator::Add: + return Resolve(monkeys, operation.lhs) + Resolve(monkeys, operation.rhs); + case Operator::Sub: + return Resolve(monkeys, operation.lhs) - Resolve(monkeys, operation.rhs); + case Operator::Mul: + return Resolve(monkeys, operation.lhs) * Resolve(monkeys, operation.rhs); + case Operator::Div: + return Resolve(monkeys, operation.lhs) / Resolve(monkeys, operation.rhs); + } + return 0; + } + + bool HasHuman(const std::set& monkeys, const std::string& name) + { + if (name == "humn") + return true; + + Monkey findMonkey; + findMonkey.name = name; + const Monkey& monkey = *monkeys.find(findMonkey); + if (std::holds_alternative(monkey.yell)) + { + return HasHuman(monkeys, std::get(monkey.yell).lhs) || + HasHuman(monkeys, std::get(monkey.yell).rhs); + } + + return false; + } + + int64_t Resolve(const std::set& monkeys, const std::string& name, int64_t result) + { + if (name == "humn") + return result; + + Monkey findMonkey; + findMonkey.name = name; + const Monkey& monkey = *monkeys.find(findMonkey); + if (std::holds_alternative(monkey.yell)) + return std::get(monkey.yell); + + const Operation& operation = std::get(monkey.yell); + if (name == "root") + { + if (HasHuman(monkeys, operation.lhs)) + { + return Resolve(monkeys, operation.lhs, Resolve(monkeys, operation.rhs)); + } + else + { + return Resolve(monkeys, operation.rhs, Resolve(monkeys, operation.lhs)); + } + } + + if (HasHuman(monkeys, operation.lhs)) + { + int64_t rhs = Resolve(monkeys, operation.rhs); + switch (operation.op) + { + case Operator::Add: + return Resolve(monkeys, operation.lhs, result - rhs); // lhs + rhs = result => lhs = result - rhs + case Operator::Sub: + return Resolve(monkeys, operation.lhs, result + rhs); // lhs - rhs = result => lhs = result + rhs + case Operator::Mul: + return Resolve(monkeys, operation.lhs, result / rhs); // lhs * rhs = result => lhs = result / rhs + case Operator::Div: + return Resolve(monkeys, operation.lhs, result * rhs); // lhs / rhs = result => lhs = result * rhs + } + } + else + { + int64_t lhs = Resolve(monkeys, operation.lhs); + switch (operation.op) + { + case Operator::Add: + return Resolve(monkeys, operation.rhs, result - lhs); // lhs + rhs = result => rhs = result - lhs + case Operator::Sub: + return Resolve(monkeys, operation.rhs, lhs - result); // lhs - rhs = result => rhs = lhs - result + case Operator::Mul: + return Resolve(monkeys, operation.rhs, result / lhs); // lhs * rhs = result => result / lhs + case Operator::Div: + return Resolve(monkeys, operation.rhs, lhs * result); // lhs / rhs = result => lhs / result + } + } + return 0; + } + + OUTPUT1(input) + { + return Resolve(input, "root"); + } + + OUTPUT2(input) + { + return Resolve(input, "root", 0); + } +} diff --git a/src/2022/Day22.cpp b/src/2022/Day22.cpp new file mode 100644 index 0000000..60bb9c1 --- /dev/null +++ b/src/2022/Day22.cpp @@ -0,0 +1,284 @@ +#include "common/aoc.h" + +namespace y$1::day22 +{ + + struct Input + { + Array2D grid; + std::string directions; + }; + + bool Between(int x, int bound1, int bound2) + { + if (bound1 < bound2) + return x >= bound1 && x <= bound2; + else + return x <= bound1 && x >= bound2; + } + + REGISTER_DAY(2022, Day22, Input, int); + + REGISTER_TEST_EXAMPLE(2022, Day22, ExampleInput, 1, 6032); + REGISTER_TEST(2022, Day22, Input, 1, 89224); + REGISTER_TEST(2022, Day22, Input, 2, 136182); + + struct State + { + Index2D pos; + Index2D facing; + }; + + struct Edge + { + Index2D from1; + Index2D to1; + Index2D facing1; + Index2D from2; + Index2D to2; + Index2D facing2; + + Edge(Index2D from1, Index2D to1, Index2D facing1, Index2D from2, Index2D to2, Index2D facing2) + : from1{from1}, + to1{to1}, + facing1{facing1}, + from2{from2}, + to2{to2}, + facing2{facing2} + { + } + + void CalcTransition(Index2D& pos, Index2D& facing) + { + if (facing == facing1 && Between(pos.x, from1.x, to1.x) && Between(pos.y, from1.y, to1.y)) + { + facing.x = -facing2.x; + facing.y = -facing2.y; + Index2D diff1 = pos - from1; + int offset = std::max(std::abs(diff1.x), std::abs(diff1.y)); + Index2D diff2 = to2 - from2; + diff2.x = Helper::Sign(diff2.x); + diff2.y = Helper::Sign(diff2.y); + pos.x = from2.x + offset * diff2.x; + pos.y = from2.y + offset * diff2.y; + } + else + { + facing.x = -facing1.x; + facing.y = -facing1.y; + Index2D diff2 = pos - from2; + int offset = std::max(std::abs(diff2.x), std::abs(diff2.y)); + Index2D diff1 = to1 - from1; + diff1.x = Helper::Sign(diff1.x); + diff1.y = Helper::Sign(diff1.y); + pos.x = from1.x + offset * diff1.x; + pos.y = from1.y + offset * diff1.y; + } + } + + bool operator==(const State& state) const + { + return (state.facing == facing1 && Between(state.pos.x, from1.x, to1.x) && + Between(state.pos.y, from1.y, to1.y)) || + (state.facing == facing2 && Between(state.pos.x, from2.x, to2.x) && Between(state.pos.y, from2.y, to2.y)); + } + }; + + READ_INPUT(input) + { + Input in; + std::string str; + int max = 0; + std::vector vector; + while (std::getline(input, str)) + { + if (str.empty()) + break; + vector.emplace_back(str); + max = std::max(max, (int)str.size()); + } + + in.grid = Array2D{max, (int)vector.size()}; + in.grid.Fill(' '); + for (int i = 0; i < vector.size(); i++) + { + for (int j = 0; j < vector[i].size(); j++) + { + in.grid.Set(j, i, vector[i][j]); + } + } + + std::getline(input, in.directions); + return in; + } + + OUTPUT1(input) + { + State state; + state.facing = Index2D{1, 0}; + + for (int i = 0; i < input.grid.width; i++) + { + if (input.grid.Get(i, 0) != ' ') + { + state.pos = {i, 0}; + break; + } + } + int i = 0; + while (i < input.directions.size()) + { + if (input.directions[i] >= '0' && input.directions[i] <= '9') + { + int amount = std::stoi(&input.directions[i]); + while (input.directions[i] >= '0' && input.directions[i] <= '9') i++; + + for (int j = 0; j < amount; j++) + { + Index2D oldPos = state.pos; + state.pos = state.pos + state.facing; + if (input.grid.GetMod(state.pos.x, state.pos.y) == '#') + { + state.pos = oldPos; + break; + } + else if (input.grid.GetMod(state.pos.x, state.pos.y) == ' ') + { + while (input.grid.GetMod(state.pos.x, state.pos.y) == ' ') + { + state.pos = state.pos + state.facing; + } + if (input.grid.GetMod(state.pos.x, state.pos.y) == '#') + { + state.pos = oldPos; + break; + } + } + } + state.pos.x = ((state.pos.x % input.grid.width) + input.grid.width) % input.grid.width; + state.pos.y = ((state.pos.y % input.grid.height) + input.grid.height) % input.grid.height; + } + else + { + if (input.directions[i] == 'R') + { + int tmp = state.facing.x; + state.facing.x = -state.facing.y; + state.facing.y = tmp; + } + else + { + int tmp = state.facing.x; + state.facing.x = state.facing.y; + state.facing.y = -tmp; + } + i++; + } + } + int face = 0; + if (state.facing == Index2D{0, 1}) + face = 1; + if (state.facing == Index2D{-1, 0}) + face = 2; + if (state.facing == Index2D{0, -1}) + face = 3; + return (state.pos.y + 1) * 1000 + 4 * (state.pos.x + 1) + face; + } + + OUTPUT2(input) + { + State state; + state.facing = Index2D{1, 0}; + std::vector edges; + edges.emplace_back( + Index2D{50, 50}, Index2D{50, 99}, Index2D{-1, 0}, Index2D{0, 100}, Index2D{49, 100}, Index2D{0, -1}); + edges.emplace_back( + Index2D{50, 0}, Index2D{50, 49}, Index2D{-1, 0}, Index2D{0, 149}, Index2D{0, 100}, Index2D{-1, 0}); + edges.emplace_back( + Index2D{100, 49}, Index2D{149, 49}, Index2D{0, 1}, Index2D{99, 50}, Index2D{99, 99}, Index2D{1, 0}); + edges.emplace_back( + Index2D{50, 149}, Index2D{99, 149}, Index2D{0, 1}, Index2D{49, 150}, Index2D{49, 199}, Index2D{1, 0}); + edges.emplace_back( + Index2D{50, 0}, Index2D{99, 0}, Index2D{0, -1}, Index2D{0, 150}, Index2D{0, 199}, Index2D{-1, 0}); + edges.emplace_back( + Index2D{99, 100}, Index2D{99, 149}, Index2D{1, 0}, Index2D{149, 49}, Index2D{149, 0}, Index2D{1, 0}); + edges.emplace_back( + Index2D{100, 0}, Index2D{149, 0}, Index2D{0, -1}, Index2D{0, 199}, Index2D{49, 199}, Index2D{0, 1}); + + for (int i = 0; i < input.grid.width; i++) + { + if (input.grid.Get(i, 0) != ' ') + { + state.pos = {i, 0}; + break; + } + } + int i = 0; + while (i < input.directions.size()) + { + if (input.directions[i] >= '0' && input.directions[i] <= '9') + { + int amount = std::stoi(&input.directions[i]); + while (input.directions[i] >= '0' && input.directions[i] <= '9') i++; + + for (int j = 0; j < amount; j++) + { + Index2D oldPos = state.pos; + Index2D oldFacing = state.facing; + state.pos = state.pos + state.facing; + state.pos.x = ((state.pos.x % input.grid.width) + input.grid.width) % input.grid.width; + state.pos.y = ((state.pos.y % input.grid.height) + input.grid.height) % input.grid.height; + if (input.grid.Get(state.pos.x, state.pos.y) == '#') + { + state.pos = oldPos; + break; + } + else if (input.grid.Get(state.pos.x, state.pos.y) == ' ') + { + state.pos = oldPos; + auto it = std::find(edges.begin(), edges.end(), state); + if (it != edges.end()) + { + it->CalcTransition(state.pos, state.facing); + if (input.grid.Get(state.pos.x, state.pos.y) == '#') + { + state.pos = oldPos; + state.facing = oldFacing; + break; + } + } + else + { + std::cout << "Not found: state.pos: " << state.pos << " state.facing: " << state.facing << std::endl; + return 0; + } + } + } + } + else + { + if (input.directions[i] == 'R') + { + int tmp = state.facing.x; + state.facing.x = -state.facing.y; + state.facing.y = tmp; + } + else + { + int tmp = state.facing.x; + state.facing.x = state.facing.y; + state.facing.y = -tmp; + } + i++; + } + } + int face = 0; + if (state.facing == Index2D{0, 1}) + face = 1; + if (state.facing == Index2D{-1, 0}) + face = 2; + if (state.facing == Index2D{0, -1}) + face = 3; + return (state.pos.y + 1) * 1000 + 4 * (state.pos.x + 1) + face; + } +} diff --git a/src/2022/Day23.cpp b/src/2022/Day23.cpp new file mode 100644 index 0000000..96fe5a5 --- /dev/null +++ b/src/2022/Day23.cpp @@ -0,0 +1,263 @@ +#include "common/aoc.h" + +namespace y$1::day23 +{ + REGISTER_DAY(2022, Day23, Array2D, int); + + REGISTER_TEST_EXAMPLE(2022, Day23, ExampleInput, 1, 110); + REGISTER_TEST(2022, Day23, Input, 1, 4254); + REGISTER_TEST_EXAMPLE(2022, Day23, ExampleInput, 2, 20); + REGISTER_TEST(2022, Day23, Input, 2, 992); + + READ_INPUT(input) + { + return Input::ReadArray2D(input); + } + + void Reset(Array2D& grid, const Index2D& pos) + { + char c = grid.Get(pos); + if (c == '1') + grid.Set(pos.x, pos.y + 1, '0'); + if (c == '2') + grid.Set(pos.x, pos.y - 1, '0'); + if (c == '3') + grid.Set(pos.x + 1, pos.y, '0'); + if (c == '4') + grid.Set(pos.x - 1, pos.y, '0'); + grid.Set(pos.x, pos.y, '.'); + } + + OUTPUT1(input) + { + Array2D grid{input.width * 3, input.height * 3}; + Array2D moves{input.width * 3, input.height * 3}; + grid.Fill('.'); + moves.Fill('.'); + for (auto it = input.begin(); it != input.end(); ++it) + { + grid.Set(input.width + it.index.x, input.height + it.index.y, *it); + } + + for (int i = 0; i < 10; i++) + { + for (auto it = grid.begin(); it != grid.end(); ++it) + { + if (*it != '#') + continue; + + if (grid.GetNeighbors('#', it.index.x, it.index.y) == 0) + { + moves.Set(it.index.x, it.index.y, '0'); + } + else + { + int up = 0; + if (grid.Get(it.index.x, it.index.y - 1) == '#') + up++; + if (grid.Get(it.index.x - 1, it.index.y - 1) == '#') + up++; + if (grid.Get(it.index.x + 1, it.index.y - 1) == '#') + up++; + int down = 0; + if (grid.Get(it.index.x, it.index.y + 1) == '#') + down++; + if (grid.Get(it.index.x - 1, it.index.y + 1) == '#') + down++; + if (grid.Get(it.index.x + 1, it.index.y + 1) == '#') + down++; + int left = 0; + if (grid.Get(it.index.x - 1, it.index.y) == '#') + left++; + if (grid.Get(it.index.x - 1, it.index.y - 1) == '#') + left++; + if (grid.Get(it.index.x - 1, it.index.y + 1) == '#') + left++; + int right = 0; + if (grid.Get(it.index.x + 1, it.index.y) == '#') + right++; + if (grid.Get(it.index.x + 1, it.index.y - 1) == '#') + right++; + if (grid.Get(it.index.x + 1, it.index.y + 1) == '#') + right++; + + std::vector neighs{up, down, left, right}; + std::vector dirs{Index2D{it.index.x, it.index.y - 1}, + Index2D{it.index.x, it.index.y + 1}, + Index2D{it.index.x - 1, it.index.y}, + Index2D{it.index.x + 1, it.index.y}}; + std::vector val{'1', '2', '3', '4'}; + + bool set = false; + for (int j = 0; j < 4; j++) + { + if (neighs[(i + j) % 4] == 0) + { + Index2D index = dirs[(i + j) % 4]; + char c = moves.Get(index); + if (c != '.') + { + moves.Set(it.index.x, it.index.y, '0'); + Reset(moves, index); + } + else + { + moves.Set(index.x, index.y, val[(i + j) % 4]); + } + set = true; + break; + } + } + if (!set) + { + moves.Set(it.index.x, it.index.y, '0'); + } + } + } + + grid.Fill('.'); + for (auto it = moves.begin(); it != moves.end(); ++it) + { + if (*it != '.') + { + grid.Set(it.index.x, it.index.y, '#'); + } + } + moves.Fill('.'); + } + + Index2D min{grid.width, grid.height}; + Index2D max{0, 0}; + for (auto it = grid.begin(); it != grid.end(); ++it) + { + if (*it == '#') + { + min.x = std::min(min.x, it.index.x); + min.y = std::min(min.y, it.index.y); + max.x = std::max(max.x, it.index.x); + max.y = std::max(max.y, it.index.y); + } + } + + return (max.x - min.x + 1) * (max.y - min.y + 1) - grid.Count('#'); + } + + OUTPUT2(input) + { + Array2D grid{input.width * 3, input.height * 3}; + Array2D moves{input.width * 3, input.height * 3}; + grid.Fill('.'); + moves.Fill('.'); + for (auto it = input.begin(); it != input.end(); ++it) + { + grid.Set(input.width + it.index.x, input.height + it.index.y, *it); + } + + bool moved = true; + int i = 0; + while (moved) + { + for (auto it = grid.begin(); it != grid.end(); ++it) + { + if (*it != '#') + continue; + + if (grid.GetNeighbors('#', it.index.x, it.index.y) == 0) + { + moves.Set(it.index.x, it.index.y, '0'); + } + else + { + int up = 0; + if (grid.Get(it.index.x, it.index.y - 1) == '#') + up++; + if (grid.Get(it.index.x - 1, it.index.y - 1) == '#') + up++; + if (grid.Get(it.index.x + 1, it.index.y - 1) == '#') + up++; + int down = 0; + if (grid.Get(it.index.x, it.index.y + 1) == '#') + down++; + if (grid.Get(it.index.x - 1, it.index.y + 1) == '#') + down++; + if (grid.Get(it.index.x + 1, it.index.y + 1) == '#') + down++; + int left = 0; + if (grid.Get(it.index.x - 1, it.index.y) == '#') + left++; + if (grid.Get(it.index.x - 1, it.index.y - 1) == '#') + left++; + if (grid.Get(it.index.x - 1, it.index.y + 1) == '#') + left++; + int right = 0; + if (grid.Get(it.index.x + 1, it.index.y) == '#') + right++; + if (grid.Get(it.index.x + 1, it.index.y - 1) == '#') + right++; + if (grid.Get(it.index.x + 1, it.index.y + 1) == '#') + right++; + + std::vector neighs{up, down, left, right}; + std::vector dirs{Index2D{it.index.x, it.index.y - 1}, + Index2D{it.index.x, it.index.y + 1}, + Index2D{it.index.x - 1, it.index.y}, + Index2D{it.index.x + 1, it.index.y}}; + std::vector val{'1', '2', '3', '4'}; + + bool set = false; + for (int j = 0; j < 4; j++) + { + if (neighs[(i + j) % 4] == 0) + { + Index2D index = dirs[(i + j) % 4]; + char c = moves.Get(index); + if (c != '.') + { + moves.Set(it.index.x, it.index.y, '0'); + Reset(moves, index); + } + else + { + moves.Set(index.x, index.y, val[(i + j) % 4]); + } + set = true; + break; + } + } + if (!set) + { + moves.Set(it.index.x, it.index.y, '0'); + } + } + } + + grid.Fill('.'); + moved = false; + for (auto it = moves.begin(); it != moves.end(); ++it) + { + if (*it != '.') + { + grid.Set(it.index.x, it.index.y, '#'); + if (*it != '0') + moved = true; + } + } + moves.Fill('.'); + i++; + } + + Index2D min{grid.width, grid.height}; + Index2D max{0, 0}; + for (auto it = grid.begin(); it != grid.end(); ++it) + { + if (*it == '#') + { + min.x = std::min(min.x, it.index.x); + min.y = std::min(min.y, it.index.y); + max.x = std::max(max.x, it.index.x); + max.y = std::max(max.y, it.index.y); + } + } + return i; + } +} diff --git a/src/2022/Day24.cpp b/src/2022/Day24.cpp new file mode 100644 index 0000000..b16e47d --- /dev/null +++ b/src/2022/Day24.cpp @@ -0,0 +1,201 @@ +#include "common/aoc.h" + +namespace y$1::day24 +{ + struct World + { + const Array2D world; + Array2D up; + Array2D down; + Array2D left; + Array2D right; + + World(const Array2D& world) + : world{world} + { + up = Array2D{world.width, world.height}; + down = Array2D{world.width, world.height}; + left = Array2D{world.width, world.height}; + right = Array2D{world.width, world.height}; + up.Fill('.'); + down.Fill('.'); + right.Fill('.'); + left.Fill('.'); + for (auto it = world.begin(); it != world.end(); ++it) + { + if (*it == '^') + up.Set(it.index.x, it.index.y, '^'); + if (*it == 'v') + down.Set(it.index.x, it.index.y, 'v'); + if (*it == '>') + right.Set(it.index.x, it.index.y, '>'); + if (*it == '<') + left.Set(it.index.x, it.index.y, '<'); + } + } + }; + + struct State + { + Index2D pos; + int depth; + int vert; + int hor; + + bool operator<(const State& rhs) const + { + if (pos != rhs.pos) + return pos < rhs.pos; + if (vert != rhs.vert) + return vert < rhs.vert; + return hor < rhs.hor; + } + }; + + REGISTER_DAY(2022, Day24, World, int); + + REGISTER_TEST_EXAMPLE(2022, Day24, ExampleInput, 1, 18); + REGISTER_TEST(2022, Day24, Input, 1, 299); + REGISTER_TEST_EXAMPLE(2022, Day24, ExampleInput, 2, 54); + REGISTER_TEST(2022, Day24, Input, 2, 899); + + READ_INPUT(input) + { + return World{Input::ReadArray2D(input)}; + } + + void Step(World& world) + { + Array2D upCpy = world.up; + world.up.Fill('.'); + for (auto it = upCpy.begin(); it != upCpy.end(); ++it) + { + if (*it == '^') + { + int y = it.index.y - 1; + if (y == 0) + world.up.Set(it.index.x, world.up.height - 2, '^'); + else + world.up.Set(it.index.x, it.index.y - 1, '^'); + } + } + + Array2D downCpy = world.down; + world.down.Fill('.'); + for (auto it = downCpy.begin(); it != downCpy.end(); ++it) + { + if (*it == 'v') + { + int y = it.index.y + 1; + if (y == world.down.height - 1) + world.down.Set(it.index.x, 1, 'v'); + else + world.down.Set(it.index.x, it.index.y + 1, 'v'); + } + } + + Array2D rightCpy = world.right; + world.right.Fill('.'); + for (auto it = rightCpy.begin(); it != rightCpy.end(); ++it) + { + if (*it == '>') + { + int x = it.index.x + 1; + if (x == world.right.width - 1) + world.right.Set(1, it.index.y, '>'); + else + world.right.Set(it.index.x + 1, it.index.y, '>'); + } + } + + Array2D leftCpy = world.left; + world.left.Fill('.'); + for (auto it = leftCpy.begin(); it != leftCpy.end(); ++it) + { + if (*it == '<') + { + int x = it.index.x - 1; + if (x == 0) + world.left.Set(world.left.width - 2, it.index.y, '<'); + else + world.left.Set(it.index.x - 1, it.index.y, '<'); + } + } + } + + int PathFind(World& world, const Index2D& from, const Index2D& to) + { + std::set visited; + int lastDepth = -1; + std::queue queue; + State initialState; + initialState.pos = from; + initialState.depth = 0; + initialState.vert = 0; + initialState.hor = 0; + queue.emplace(initialState); + visited.emplace(initialState); + while (!queue.empty()) + { + State state = queue.front(); + queue.pop(); + if (state.pos == to) + { + return state.depth; + } + if (lastDepth != state.depth) + { + Step(world); + lastDepth = state.depth; + } + + std::vector moves{Index2D{0, 0}, Index2D{1, 0}, Index2D{-1, 0}, Index2D{0, 1}, Index2D{0, -1}}; + for (auto& move : moves) + { + Index2D newPos = state.pos + move; + if (!world.world.IsInside(newPos)) + continue; + if (world.world.Get(newPos) == '#') + continue; + if (world.up.Get(newPos) == '^') + continue; + if (world.down.Get(newPos) == 'v') + continue; + if (world.left.Get(newPos) == '<') + continue; + if (world.right.Get(newPos) == '>') + continue; + State newState; + newState.pos = newPos; + newState.depth = state.depth + 1; + newState.vert = state.vert + 1; + newState.hor = state.hor + 1; + if (newState.vert == world.world.height - 2) + newState.vert = 0; + if (newState.hor == world.world.width - 2) + newState.hor = 0; + if (visited.count(newState) > 0) + continue; + visited.emplace(newState); + queue.emplace(newState); + } + } + return 0; + } + + OUTPUT1(input) + { + World world = input; + return PathFind(world, Index2D{1, 0}, Index2D{world.world.width - 2, world.world.height - 1}); + } + + OUTPUT2(input) + { + World world = input; + int path1 = PathFind(world, Index2D{1, 0}, Index2D{world.world.width - 2, world.world.height - 1}); + int path2 = PathFind(world, Index2D{world.world.width - 2, world.world.height - 1}, Index2D{1, 0}); + int path3 = PathFind(world, Index2D{1, 0}, Index2D{world.world.width - 2, world.world.height - 1}); + + return path1 + path2 + path3 + 2; + } +} diff --git a/src/2022/Day25.cpp b/src/2022/Day25.cpp new file mode 100644 index 0000000..1da30f4 --- /dev/null +++ b/src/2022/Day25.cpp @@ -0,0 +1,112 @@ +#include "common/aoc.h" + +namespace y$1::day25 +{ + int64_t Pow(int64_t number, int64_t pow) + { + int64_t result = number; + for (int i = 0; i < pow; i++) + { + result *= number; + } + return result; + } + + int64_t ConvertToBase10(const std::string& string) + { + int64_t total = 0; + for (int i = 0; i < string.size(); i++) + { + total *= 5; + if (string[i] == '1') + total += 1; + else if (string[i] == '2') + total += 2; + else if (string[i] == '-') + total += -1; + else if (string[i] == '=') + total += -2; + else if (string[i] == '0') + total += 0; + else + std::cout << "Invalid character in " << string << std::endl; + } + return total; + } + + std::string ConvertToBase5(int64_t base10) + { + // Convert to base 5 + std::string base5 = ""; + int64_t numbers = log(base10) / log(5) + 1; + for (int i = 0; i < numbers + 1; i++) base5.push_back('0'); + int64_t base5Max = Pow(5, numbers - 2); + + for (int i = 1; i < base5.size(); i++) + { + int64_t val = base10 / base5Max; + base5[i] = val + '0'; + base10 -= val * base5Max; + base5Max /= 5; + } + return base5; + } + + std::string ConvertToSNAFU(const std::string& base5) + { + std::string snafu = base5; + for (int i = snafu.size() - 1; i > 0; i--) + { + if (snafu[i] == '3') + { + snafu[i] = '='; + snafu[i - 1] += 1; + } + else if (snafu[i] == '4') + { + snafu[i] = '-'; + snafu[i - 1] += 1; + } + else if (snafu[i] == '5') + { + snafu[i] = '0'; + snafu[i - 1] += 1; + } + } + if (snafu[0] == '0') + return snafu.substr(1); + return snafu; + } + + REGISTER_DAY(2022, Day25, std::vector, std::string); + + REGISTER_TEST_EXAMPLE(2022, Day25, ExampleInput, 1, "2=-1=0"); + REGISTER_TEST(2022, Day25, Input, 1, "2=12-100--1012-0=012"); + REGISTER_TEST(2022, Day25, Input, 2, ""); + + READ_INPUT(input) + { + return Input::ReadLines(input); + } + + OUTPUT1(input) + { + int64_t base10 = 0; + for (auto& line : input) + { + base10 += ConvertToBase10(line); + } + + std::string base5 = ConvertToBase5(base10); + return ConvertToSNAFU(base5); + } + + OUTPUT2(input) + { + std::cout << " ___ ___" << std::endl; + std::cout << " (o o) (o o)" << std::endl; + std::cout << "( V ) MERRY CHRISTMAS! ( V )" << std::endl; + std::cout << "--m-m----------------------m-m--" << std::endl; + return ""; + } +} diff --git a/src/2024/Day01.cpp b/src/2024/Day01.cpp index 411aaca..8527eac 100644 --- a/src/2024/Day01.cpp +++ b/src/2024/Day01.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day01 +namespace y2024::day01 { using InputType = std::pair, std::vector>; REGISTER_DAY(2024, Day01, InputType, int); diff --git a/src/2024/Day02.cpp b/src/2024/Day02.cpp index f4972a7..e69608f 100644 --- a/src/2024/Day02.cpp +++ b/src/2024/Day02.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day02 +namespace y2024::day02 { REGISTER_DAY(2024, Day02, std::vector>, int); diff --git a/src/2024/Day03.cpp b/src/2024/Day03.cpp index de95296..5da13bd 100644 --- a/src/2024/Day03.cpp +++ b/src/2024/Day03.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day03 +namespace y2024::day03 { REGISTER_DAY(2024, Day03, std::string, int32_t); diff --git a/src/2024/Day04.cpp b/src/2024/Day04.cpp index d2f9ae9..c8c704f 100644 --- a/src/2024/Day04.cpp +++ b/src/2024/Day04.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day04 +namespace y2024::day04 { REGISTER_DAY(2024, Day04, Array2D, int32_t); diff --git a/src/2024/Day05.cpp b/src/2024/Day05.cpp index cc35788..e20b38b 100644 --- a/src/2024/Day05.cpp +++ b/src/2024/Day05.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day05 +namespace y2024::day05 { struct Manual { diff --git a/src/2024/Day06.cpp b/src/2024/Day06.cpp index d65bbbb..9411622 100644 --- a/src/2024/Day06.cpp +++ b/src/2024/Day06.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day06 +namespace y2024::day06 { REGISTER_DAY(2024, Day06, Array2D, int32_t); diff --git a/src/2024/Day07.cpp b/src/2024/Day07.cpp index 2774db8..c565267 100644 --- a/src/2024/Day07.cpp +++ b/src/2024/Day07.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day07 +namespace y2024::day07 { struct Data { diff --git a/src/2024/Day08.cpp b/src/2024/Day08.cpp index 7c8493f..7f70df8 100644 --- a/src/2024/Day08.cpp +++ b/src/2024/Day08.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day08 +namespace y2024::day08 { struct Data { diff --git a/src/2024/Day09.cpp b/src/2024/Day09.cpp index 0540245..5554497 100644 --- a/src/2024/Day09.cpp +++ b/src/2024/Day09.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day09 +namespace y2024::day09 { REGISTER_DAY(2024, Day09, std::vector, int64_t); diff --git a/src/2024/Day10.cpp b/src/2024/Day10.cpp index 3c08c84..0889fb8 100644 --- a/src/2024/Day10.cpp +++ b/src/2024/Day10.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day10 +namespace y2024::day10 { REGISTER_DAY(2024, Day10, Array2D, int32_t); diff --git a/src/2024/Day11.cpp b/src/2024/Day11.cpp index 40ed4c9..8610ae0 100644 --- a/src/2024/Day11.cpp +++ b/src/2024/Day11.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day11 +namespace y2024::day11 { using Stones = std::map; REGISTER_DAY(2024, Day11, Stones, int64_t); diff --git a/src/2024/Day12.cpp b/src/2024/Day12.cpp index 50f2e36..5ce1db0 100644 --- a/src/2024/Day12.cpp +++ b/src/2024/Day12.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day12 +namespace y2024::day12 { REGISTER_DAY(2024, Day12, Array2D, int); diff --git a/src/2024/Day13.cpp b/src/2024/Day13.cpp index 50d8374..1644195 100644 --- a/src/2024/Day13.cpp +++ b/src/2024/Day13.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day13 +namespace y2024::day13 { struct ClawMachine { diff --git a/src/2024/Day14.cpp b/src/2024/Day14.cpp index 9bf95af..5c99dd7 100644 --- a/src/2024/Day14.cpp +++ b/src/2024/Day14.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day14 +namespace y2024::day14 { struct Robot { diff --git a/src/2024/Day15.cpp b/src/2024/Day15.cpp index aa51540..bd62b4b 100644 --- a/src/2024/Day15.cpp +++ b/src/2024/Day15.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day15 +namespace y2024::day15 { struct Map { diff --git a/src/2024/Day16.cpp b/src/2024/Day16.cpp index f91044d..c3860ad 100644 --- a/src/2024/Day16.cpp +++ b/src/2024/Day16.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day16 +namespace y2024::day16 { REGISTER_DAY(2024, Day16, Array2D, int32_t); diff --git a/src/2024/Day17.cpp b/src/2024/Day17.cpp index 291085a..abd8cfa 100644 --- a/src/2024/Day17.cpp +++ b/src/2024/Day17.cpp @@ -2,7 +2,7 @@ #include "common/aoc.h" -namespace day17 +namespace y2024::day17 { struct Program { diff --git a/src/2024/Day18.cpp b/src/2024/Day18.cpp index cb84203..a63e45f 100644 --- a/src/2024/Day18.cpp +++ b/src/2024/Day18.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day18 +namespace y2024::day18 { using Memory = std::map; REGISTER_DAY(2024, Day18, Memory, int32_t); diff --git a/src/2024/Day19.cpp b/src/2024/Day19.cpp index 353a590..3a23aaf 100644 --- a/src/2024/Day19.cpp +++ b/src/2024/Day19.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day19 +namespace y2024::day19 { struct Towels { diff --git a/src/2024/Day20.cpp b/src/2024/Day20.cpp index 1d0e297..fe0af19 100644 --- a/src/2024/Day20.cpp +++ b/src/2024/Day20.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day20 +namespace y2024::day20 { REGISTER_DAY(2024, Day20, Array2D, int32_t); diff --git a/src/2024/Day21.cpp b/src/2024/Day21.cpp index 7000d14..13936b4 100644 --- a/src/2024/Day21.cpp +++ b/src/2024/Day21.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day21 +namespace y2024::day21 { REGISTER_DAY(2024, Day21, std::vector, int64_t); diff --git a/src/2024/Day22.cpp b/src/2024/Day22.cpp index 0ec210a..aa474f9 100644 --- a/src/2024/Day22.cpp +++ b/src/2024/Day22.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day22 +namespace y2024::day22 { REGISTER_DAY(2024, Day22, std::vector, int64_t); diff --git a/src/2024/Day23.cpp b/src/2024/Day23.cpp index 3b0ee4d..6b9d134 100644 --- a/src/2024/Day23.cpp +++ b/src/2024/Day23.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day23 +namespace y2024::day23 { struct Network { diff --git a/src/2024/Day24.cpp b/src/2024/Day24.cpp index f0e0c4b..a8699e9 100644 --- a/src/2024/Day24.cpp +++ b/src/2024/Day24.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day24 +namespace y2024::day24 { struct Gate { diff --git a/src/2024/Day25.cpp b/src/2024/Day25.cpp index 44915ed..672baf8 100644 --- a/src/2024/Day25.cpp +++ b/src/2024/Day25.cpp @@ -1,6 +1,6 @@ #include "common/aoc.h" -namespace day25 +namespace y2024::day25 { struct KeysLocks {