Add 2021 solutions
This commit is contained in:
@@ -8,13 +8,9 @@ fi
|
||||
list=$(find -name "Day*.cpp" | awk -F '/' '{print $3 "/" $4}' | awk -F '.' '{print $1}' | sed 's/Day//g' | sort)
|
||||
|
||||
for item in $list; do
|
||||
echo $item
|
||||
year=$(echo $item | awk -F '/' '{print $1}')
|
||||
day=$(echo $item | awk -F '/' '{print $2}')
|
||||
echo "year: $year"
|
||||
echo "day: $day"
|
||||
dir="res/$year/day$day/input.txt"
|
||||
echo $dir
|
||||
if [ ! -e $dir ]; then
|
||||
webitem=$(echo $day | sed 's/^0//g')
|
||||
echo "Fetching $dir"
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
199
|
||||
200
|
||||
208
|
||||
210
|
||||
200
|
||||
207
|
||||
240
|
||||
269
|
||||
260
|
||||
263
|
||||
@@ -0,0 +1,6 @@
|
||||
forward 5
|
||||
down 5
|
||||
forward 8
|
||||
up 3
|
||||
down 8
|
||||
forward 2
|
||||
@@ -0,0 +1,12 @@
|
||||
00100
|
||||
11110
|
||||
10110
|
||||
10111
|
||||
10101
|
||||
01111
|
||||
00111
|
||||
11100
|
||||
10000
|
||||
11001
|
||||
00010
|
||||
01010
|
||||
@@ -0,0 +1,19 @@
|
||||
7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1
|
||||
|
||||
22 13 17 11 0
|
||||
8 2 23 4 24
|
||||
21 9 14 16 7
|
||||
6 10 3 18 5
|
||||
1 12 20 15 19
|
||||
|
||||
3 15 0 2 22
|
||||
9 18 13 17 5
|
||||
19 8 7 25 23
|
||||
20 11 10 24 4
|
||||
14 21 16 12 6
|
||||
|
||||
14 21 17 24 4
|
||||
10 16 15 9 19
|
||||
18 8 23 26 20
|
||||
22 11 13 6 5
|
||||
2 0 12 3 7
|
||||
@@ -0,0 +1,10 @@
|
||||
0,9 -> 5,9
|
||||
8,0 -> 0,8
|
||||
9,4 -> 3,4
|
||||
2,2 -> 2,1
|
||||
7,0 -> 7,4
|
||||
6,4 -> 2,0
|
||||
0,9 -> 2,9
|
||||
3,4 -> 1,4
|
||||
0,0 -> 8,8
|
||||
5,5 -> 8,2
|
||||
@@ -0,0 +1 @@
|
||||
3,4,3,1,2
|
||||
@@ -0,0 +1 @@
|
||||
16,1,2,0,4,2,7,1,2,14
|
||||
@@ -0,0 +1,10 @@
|
||||
be cfbegad cbdgef fgaecd cgeb fdcge agebfd fecdb fabcd edb | fdgacbe cefdb cefbgd gcbe
|
||||
edbfga begcd cbg gc gcadebf fbgde acbgfd abcde gfcbed gfec | fcgedb cgb dgebacf gc
|
||||
fgaebd cg bdaec gdafb agbcfd gdcbef bgcad gfac gcb cdgabef | cg cg fdcagb cbg
|
||||
fbegcd cbd adcefb dageb afcb bc aefdc ecdab fgdeca fcdbega | efabcd cedba gadfec cb
|
||||
aecbfdg fbg gf bafeg dbefa fcge gcbea fcaegb dgceab fcbdga | gecf egdcabf bgf bfgea
|
||||
fgeab ca afcebg bdacfeg cfaedg gcfdb baec bfadeg bafgc acf | gebdcfa ecba ca fadegcb
|
||||
dbcfg fgd bdegcaf fgec aegbdf ecdfab fbedc dacgb gdcebf gf | cefg dcbef fcge gbcadfe
|
||||
bdfegc cbegaf gecbf dfcage bdacg ed bedf ced adcbefg gebcd | ed bcgafe cdgba cbgef
|
||||
egadfb cdbfeg cegd fecab cgb gbdefca cg fgcdab egfdb bfceg | gbdfcae bgc cg cgb
|
||||
gcafb gcf dcaebfg ecagb gf abcdeg gaef cafbge fdbac fegbdc | fgae cfgab fg bagce
|
||||
@@ -0,0 +1,5 @@
|
||||
2199943210
|
||||
3987894921
|
||||
9856789892
|
||||
8767896789
|
||||
9899965678
|
||||
@@ -0,0 +1,10 @@
|
||||
[({(<(())[]>[[{[]{<()<>>
|
||||
[(()[<>])]({[<{<<[]>>(
|
||||
{([(<{}[<>[]}>{[]{[(<()>
|
||||
(((({<>}<{<{<>}{[]{[]{}
|
||||
[[<[([]))<([[{}[[()]]]
|
||||
[{[{({}]{}}([{[{{{}}([]
|
||||
{<[[]]>}<{[{[{[]{()[[[]
|
||||
[<(<(<(<{}))><([]([]()
|
||||
<{([([[(<>()){}]>(<<{{
|
||||
<{([{{}}[<[[[<>{}]]]>[]]
|
||||
@@ -0,0 +1,10 @@
|
||||
5483143223
|
||||
2745854711
|
||||
5264556173
|
||||
6141336146
|
||||
6357385478
|
||||
4167524645
|
||||
2176841721
|
||||
6882881134
|
||||
4846848554
|
||||
5283751526
|
||||
@@ -0,0 +1,7 @@
|
||||
start-A
|
||||
start-b
|
||||
A-c
|
||||
A-b
|
||||
b-d
|
||||
A-end
|
||||
b-end
|
||||
@@ -0,0 +1,21 @@
|
||||
6,10
|
||||
0,14
|
||||
9,10
|
||||
0,3
|
||||
10,4
|
||||
4,11
|
||||
6,0
|
||||
6,12
|
||||
4,1
|
||||
0,13
|
||||
10,12
|
||||
3,4
|
||||
3,0
|
||||
8,4
|
||||
1,10
|
||||
2,14
|
||||
8,10
|
||||
9,0
|
||||
|
||||
fold along y=7
|
||||
fold along x=5
|
||||
@@ -0,0 +1,18 @@
|
||||
NNCB
|
||||
|
||||
CH -> B
|
||||
HH -> N
|
||||
CB -> H
|
||||
NH -> C
|
||||
HB -> C
|
||||
HC -> B
|
||||
HN -> C
|
||||
NN -> C
|
||||
BH -> H
|
||||
NC -> B
|
||||
NB -> B
|
||||
BN -> B
|
||||
BB -> N
|
||||
BC -> B
|
||||
CC -> N
|
||||
CN -> C
|
||||
@@ -0,0 +1,10 @@
|
||||
1163751742
|
||||
1381373672
|
||||
2136511328
|
||||
3694931569
|
||||
7463417111
|
||||
1319128137
|
||||
1359912421
|
||||
3125421639
|
||||
1293138521
|
||||
2311944581
|
||||
@@ -0,0 +1 @@
|
||||
9C0141080250320F1802104A08
|
||||
@@ -0,0 +1 @@
|
||||
target area: x=20..30, y=-10..-5
|
||||
@@ -0,0 +1,10 @@
|
||||
[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]]
|
||||
[[[5,[2,8]],4],[5,[[9,9],0]]]
|
||||
[6,[[[6,2],[5,6]],[[7,6],[4,7]]]]
|
||||
[[[6,[0,7]],[0,9]],[4,[9,[9,0]]]]
|
||||
[[[7,[6,4]],[3,[1,3]]],[[[5,5],1],9]]
|
||||
[[6,[[7,3],[3,2]]],[[[3,8],[5,7]],4]]
|
||||
[[[[5,4],[7,7]],8],[[8,3],8]]
|
||||
[[9,3],[[9,9],[6,[4,9]]]]
|
||||
[[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]]
|
||||
[[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]
|
||||
@@ -0,0 +1,136 @@
|
||||
--- scanner 0 ---
|
||||
404,-588,-901
|
||||
528,-643,409
|
||||
-838,591,734
|
||||
390,-675,-793
|
||||
-537,-823,-458
|
||||
-485,-357,347
|
||||
-345,-311,381
|
||||
-661,-816,-575
|
||||
-876,649,763
|
||||
-618,-824,-621
|
||||
553,345,-567
|
||||
474,580,667
|
||||
-447,-329,318
|
||||
-584,868,-557
|
||||
544,-627,-890
|
||||
564,392,-477
|
||||
455,729,728
|
||||
-892,524,684
|
||||
-689,845,-530
|
||||
423,-701,434
|
||||
7,-33,-71
|
||||
630,319,-379
|
||||
443,580,662
|
||||
-789,900,-551
|
||||
459,-707,401
|
||||
|
||||
--- scanner 1 ---
|
||||
686,422,578
|
||||
605,423,415
|
||||
515,917,-361
|
||||
-336,658,858
|
||||
95,138,22
|
||||
-476,619,847
|
||||
-340,-569,-846
|
||||
567,-361,727
|
||||
-460,603,-452
|
||||
669,-402,600
|
||||
729,430,532
|
||||
-500,-761,534
|
||||
-322,571,750
|
||||
-466,-666,-811
|
||||
-429,-592,574
|
||||
-355,545,-477
|
||||
703,-491,-529
|
||||
-328,-685,520
|
||||
413,935,-424
|
||||
-391,539,-444
|
||||
586,-435,557
|
||||
-364,-763,-893
|
||||
807,-499,-711
|
||||
755,-354,-619
|
||||
553,889,-390
|
||||
|
||||
--- scanner 2 ---
|
||||
649,640,665
|
||||
682,-795,504
|
||||
-784,533,-524
|
||||
-644,584,-595
|
||||
-588,-843,648
|
||||
-30,6,44
|
||||
-674,560,763
|
||||
500,723,-460
|
||||
609,671,-379
|
||||
-555,-800,653
|
||||
-675,-892,-343
|
||||
697,-426,-610
|
||||
578,704,681
|
||||
493,664,-388
|
||||
-671,-858,530
|
||||
-667,343,800
|
||||
571,-461,-707
|
||||
-138,-166,112
|
||||
-889,563,-600
|
||||
646,-828,498
|
||||
640,759,510
|
||||
-630,509,768
|
||||
-681,-892,-333
|
||||
673,-379,-804
|
||||
-742,-814,-386
|
||||
577,-820,562
|
||||
|
||||
--- scanner 3 ---
|
||||
-589,542,597
|
||||
605,-692,669
|
||||
-500,565,-823
|
||||
-660,373,557
|
||||
-458,-679,-417
|
||||
-488,449,543
|
||||
-626,468,-788
|
||||
338,-750,-386
|
||||
528,-832,-391
|
||||
562,-778,733
|
||||
-938,-730,414
|
||||
543,643,-506
|
||||
-524,371,-870
|
||||
407,773,750
|
||||
-104,29,83
|
||||
378,-903,-323
|
||||
-778,-728,485
|
||||
426,699,580
|
||||
-438,-605,-362
|
||||
-469,-447,-387
|
||||
509,732,623
|
||||
647,635,-688
|
||||
-868,-804,481
|
||||
614,-800,639
|
||||
595,780,-596
|
||||
|
||||
--- scanner 4 ---
|
||||
727,592,562
|
||||
-293,-554,779
|
||||
441,611,-461
|
||||
-714,465,-776
|
||||
-743,427,-804
|
||||
-660,-479,-426
|
||||
832,-632,460
|
||||
927,-485,-438
|
||||
408,393,-506
|
||||
466,436,-512
|
||||
110,16,151
|
||||
-258,-428,682
|
||||
-393,719,612
|
||||
-211,-452,876
|
||||
808,-476,-593
|
||||
-575,615,604
|
||||
-485,667,467
|
||||
-680,325,-822
|
||||
-627,-443,-432
|
||||
872,-547,-609
|
||||
833,512,582
|
||||
807,604,487
|
||||
839,-516,451
|
||||
891,-625,532
|
||||
-652,-548,-490
|
||||
30,-46,-14
|
||||
@@ -0,0 +1,7 @@
|
||||
..#.#..#####.#.#.#.###.##.....###.##.#..###.####..#####..#....#..#..##..###..######.###...####..#..#####..##..#.#####...##.#.#..#.##..#.#......#.###.######.###.####...#.##.##..#..#..#####.....#.#....###..#.##......#.....#..#..#..##..#...##.######.####.####.#.#...#.......#..#.#.#...####.##.#......#..#...##.#.##..#...##.#.##..###.#......#.#.......#.#.#.####.###.##...#.....####.#..#..#.##.#....##..#.####....##...##..#...#......#.#.......#.......##..####..#...#.#.#...##..#.#..###..#####........#..####......#..#
|
||||
|
||||
#..#.
|
||||
#....
|
||||
##..#
|
||||
..#..
|
||||
..###
|
||||
@@ -0,0 +1,2 @@
|
||||
Player 1 starting position: 4
|
||||
Player 2 starting position: 8
|
||||
@@ -0,0 +1,60 @@
|
||||
on x=-5..47,y=-31..22,z=-19..33
|
||||
on x=-44..5,y=-27..21,z=-14..35
|
||||
on x=-49..-1,y=-11..42,z=-10..38
|
||||
on x=-20..34,y=-40..6,z=-44..1
|
||||
off x=26..39,y=40..50,z=-2..11
|
||||
on x=-41..5,y=-41..6,z=-36..8
|
||||
off x=-43..-33,y=-45..-28,z=7..25
|
||||
on x=-33..15,y=-32..19,z=-34..11
|
||||
off x=35..47,y=-46..-34,z=-11..5
|
||||
on x=-14..36,y=-6..44,z=-16..29
|
||||
on x=-57795..-6158,y=29564..72030,z=20435..90618
|
||||
on x=36731..105352,y=-21140..28532,z=16094..90401
|
||||
on x=30999..107136,y=-53464..15513,z=8553..71215
|
||||
on x=13528..83982,y=-99403..-27377,z=-24141..23996
|
||||
on x=-72682..-12347,y=18159..111354,z=7391..80950
|
||||
on x=-1060..80757,y=-65301..-20884,z=-103788..-16709
|
||||
on x=-83015..-9461,y=-72160..-8347,z=-81239..-26856
|
||||
on x=-52752..22273,y=-49450..9096,z=54442..119054
|
||||
on x=-29982..40483,y=-108474..-28371,z=-24328..38471
|
||||
on x=-4958..62750,y=40422..118853,z=-7672..65583
|
||||
on x=55694..108686,y=-43367..46958,z=-26781..48729
|
||||
on x=-98497..-18186,y=-63569..3412,z=1232..88485
|
||||
on x=-726..56291,y=-62629..13224,z=18033..85226
|
||||
on x=-110886..-34664,y=-81338..-8658,z=8914..63723
|
||||
on x=-55829..24974,y=-16897..54165,z=-121762..-28058
|
||||
on x=-65152..-11147,y=22489..91432,z=-58782..1780
|
||||
on x=-120100..-32970,y=-46592..27473,z=-11695..61039
|
||||
on x=-18631..37533,y=-124565..-50804,z=-35667..28308
|
||||
on x=-57817..18248,y=49321..117703,z=5745..55881
|
||||
on x=14781..98692,y=-1341..70827,z=15753..70151
|
||||
on x=-34419..55919,y=-19626..40991,z=39015..114138
|
||||
on x=-60785..11593,y=-56135..2999,z=-95368..-26915
|
||||
on x=-32178..58085,y=17647..101866,z=-91405..-8878
|
||||
on x=-53655..12091,y=50097..105568,z=-75335..-4862
|
||||
on x=-111166..-40997,y=-71714..2688,z=5609..50954
|
||||
on x=-16602..70118,y=-98693..-44401,z=5197..76897
|
||||
on x=16383..101554,y=4615..83635,z=-44907..18747
|
||||
off x=-95822..-15171,y=-19987..48940,z=10804..104439
|
||||
on x=-89813..-14614,y=16069..88491,z=-3297..45228
|
||||
on x=41075..99376,y=-20427..49978,z=-52012..13762
|
||||
on x=-21330..50085,y=-17944..62733,z=-112280..-30197
|
||||
on x=-16478..35915,y=36008..118594,z=-7885..47086
|
||||
off x=-98156..-27851,y=-49952..43171,z=-99005..-8456
|
||||
off x=2032..69770,y=-71013..4824,z=7471..94418
|
||||
on x=43670..120875,y=-42068..12382,z=-24787..38892
|
||||
off x=37514..111226,y=-45862..25743,z=-16714..54663
|
||||
off x=25699..97951,y=-30668..59918,z=-15349..69697
|
||||
off x=-44271..17935,y=-9516..60759,z=49131..112598
|
||||
on x=-61695..-5813,y=40978..94975,z=8655..80240
|
||||
off x=-101086..-9439,y=-7088..67543,z=33935..83858
|
||||
off x=18020..114017,y=-48931..32606,z=21474..89843
|
||||
off x=-77139..10506,y=-89994..-18797,z=-80..59318
|
||||
off x=8476..79288,y=-75520..11602,z=-96624..-24783
|
||||
on x=-47488..-1262,y=24338..100707,z=16292..72967
|
||||
off x=-84341..13987,y=2429..92914,z=-90671..-1318
|
||||
off x=-37810..49457,y=-71013..-7894,z=-105357..-13188
|
||||
off x=-27365..46395,y=31009..98017,z=15428..76570
|
||||
off x=-70369..-16548,y=22648..78696,z=-1892..86821
|
||||
on x=-53470..21291,y=-120233..-33476,z=-44150..38147
|
||||
off x=-93533..-4276,y=-16170..68771,z=-104985..-24507
|
||||
@@ -0,0 +1,5 @@
|
||||
#############
|
||||
#...........#
|
||||
###B#C#B#D###
|
||||
#A#D#C#A#
|
||||
#########
|
||||
@@ -0,0 +1,9 @@
|
||||
v...>>.vv>
|
||||
.vv>>.vv..
|
||||
>>.>v>...v
|
||||
>>v>>.>.v.
|
||||
v>v.vv.v..
|
||||
>.>>..v...
|
||||
.vv..>.>v.
|
||||
v.v..>>v.v
|
||||
....v..v.>
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day01
|
||||
{
|
||||
REGISTER_DAY(2021, Day01, std::vector<int>, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day01, ExampleInput, 1, 7);
|
||||
REGISTER_TEST(2021, Day01, Input, 1, 1722);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day01, ExampleInput, 2, 5);
|
||||
REGISTER_TEST(2021, Day01, Input, 2, 1748);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
return Input::ReadInts(input);
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int count = 0;
|
||||
for (size_t i = 0; i < input.size() - 1; i++)
|
||||
{
|
||||
if (input[i] < input[i + 1])
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int count = 0;
|
||||
for (size_t i = 0; i < input.size() - 3; i++)
|
||||
{
|
||||
if (input[i] + input[i + 1] + input[i + 2] < input[i + 1] + input[i + 2] + input[i + 3])
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day02
|
||||
{
|
||||
enum class Dir
|
||||
{
|
||||
Forward,
|
||||
Down,
|
||||
Up
|
||||
};
|
||||
|
||||
struct Move
|
||||
{
|
||||
Dir dir;
|
||||
int amount;
|
||||
};
|
||||
|
||||
REGISTER_DAY(2021, Day02, std::vector<Move>, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day02, ExampleInput, 1, 150);
|
||||
REGISTER_TEST(2021, Day02, Input, 1, 1815044);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day02, ExampleInput, 2, 900);
|
||||
REGISTER_TEST(2021, Day02, Input, 2, 1739283308);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::vector<Move> moves;
|
||||
std::string str;
|
||||
while (getline(input, str))
|
||||
{
|
||||
std::stringstream ss{str};
|
||||
std::string s;
|
||||
int i;
|
||||
ss >> s >> i;
|
||||
if (s == "forward")
|
||||
moves.emplace_back(Move{Dir::Forward, i});
|
||||
else if (s == "down")
|
||||
moves.emplace_back(Move{Dir::Down, i});
|
||||
else if (s == "up")
|
||||
moves.emplace_back(Move{Dir::Up, i});
|
||||
}
|
||||
return moves;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
for (auto&& move : input)
|
||||
{
|
||||
switch (move.dir)
|
||||
{
|
||||
case Dir::Forward:
|
||||
x += move.amount;
|
||||
break;
|
||||
case Dir::Down:
|
||||
y += move.amount;
|
||||
break;
|
||||
case Dir::Up:
|
||||
y -= move.amount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return x * y;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int aim = 0;
|
||||
for (auto&& move : input)
|
||||
{
|
||||
switch (move.dir)
|
||||
{
|
||||
case Dir::Forward:
|
||||
x += move.amount;
|
||||
y += aim * move.amount;
|
||||
break;
|
||||
case Dir::Down:
|
||||
aim += move.amount;
|
||||
break;
|
||||
case Dir::Up:
|
||||
aim -= move.amount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return x * y;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day03
|
||||
{
|
||||
REGISTER_DAY(2021, Day03, std::set<std::string>, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day03, ExampleInput, 1, 198);
|
||||
REGISTER_TEST(2021, Day03, Input, 1, 2498354);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day03, ExampleInput, 2, 230);
|
||||
REGISTER_TEST(2021, Day03, Input, 2, 3277956);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::set<std::string> strings;
|
||||
std::string str;
|
||||
while (getline(input, str))
|
||||
{
|
||||
strings.emplace(str);
|
||||
}
|
||||
return strings;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int gamma = 0;
|
||||
int width = input.begin()->size();
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
size_t count = 0;
|
||||
for (auto&& str : input)
|
||||
{
|
||||
if (str[x] == '1')
|
||||
count++;
|
||||
}
|
||||
if (count >= input.size() / 2)
|
||||
{
|
||||
gamma |= BIT(width - x - 1);
|
||||
}
|
||||
}
|
||||
int invertMask = BIT(width) - 1;
|
||||
return gamma * (gamma ^ invertMask);
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int width = input.begin()->size();
|
||||
|
||||
std::set<std::string> oxygen = input;
|
||||
std::set<std::string> carbon = input;
|
||||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
char mostCommon = '0';
|
||||
size_t count = 0;
|
||||
for (auto it = oxygen.begin(); it != oxygen.end(); it++)
|
||||
{
|
||||
if (it->at(i) == '1')
|
||||
count++;
|
||||
}
|
||||
if (count * 2 >= oxygen.size())
|
||||
mostCommon = '1';
|
||||
for (auto it = oxygen.begin(); it != oxygen.end();)
|
||||
{
|
||||
if (oxygen.size() == 1)
|
||||
break;
|
||||
if (it->at(i) != mostCommon)
|
||||
it = oxygen.erase(it);
|
||||
else
|
||||
it++;
|
||||
}
|
||||
|
||||
char leastCommon = '0';
|
||||
count = 0;
|
||||
for (auto it = carbon.begin(); it != carbon.end(); it++)
|
||||
{
|
||||
if (it->at(i) == '1')
|
||||
count++;
|
||||
}
|
||||
if (count * 2 < carbon.size())
|
||||
leastCommon = '1';
|
||||
for (auto it = carbon.begin(); it != carbon.end();)
|
||||
{
|
||||
if (carbon.size() == 1)
|
||||
break;
|
||||
if (it->at(i) != leastCommon)
|
||||
it = carbon.erase(it);
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
int oxygenVal = Helper::BinStrToInt(*oxygen.begin());
|
||||
int carbonVal = Helper::BinStrToInt(*carbon.begin());
|
||||
return oxygenVal * carbonVal;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day04
|
||||
{
|
||||
struct Game
|
||||
{
|
||||
std::vector<int> input;
|
||||
std::vector<Array2D<int>> boards;
|
||||
};
|
||||
|
||||
bool MarkAndCheck(Array2D<int>& board, int number)
|
||||
{
|
||||
Index2D index = board.Find(number);
|
||||
if (index)
|
||||
{
|
||||
board[index] = -1;
|
||||
// Check board is filled
|
||||
bool filledX = true;
|
||||
bool filledY = true;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
if (board.Get(i, index.y) != -1)
|
||||
filledX = false;
|
||||
if (board.Get(index.x, i) != -1)
|
||||
filledY = false;
|
||||
}
|
||||
return filledX || filledY;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
REGISTER_DAY(2021, Day04, Game, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day04, ExampleInput, 1, 4512);
|
||||
REGISTER_TEST(2021, Day04, Input, 1, 54275);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day04, ExampleInput, 2, 1924);
|
||||
REGISTER_TEST(2021, Day04, Input, 2, 13158);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
Game game;
|
||||
std::string str;
|
||||
getline(input, str);
|
||||
std::stringstream ss{str};
|
||||
while (getline(ss, str, ','))
|
||||
{
|
||||
game.input.emplace_back(atoi(str.c_str()));
|
||||
}
|
||||
getline(input, str);
|
||||
while (!input.eof())
|
||||
{
|
||||
Array2D<int> array2D{5, 5};
|
||||
for (int y = 0; y < 5; y++)
|
||||
{
|
||||
getline(input, str);
|
||||
std::stringstream ss{str};
|
||||
for (int x = 0; x < 5; x++)
|
||||
{
|
||||
int i;
|
||||
ss >> i;
|
||||
array2D.Set(x, y, i);
|
||||
}
|
||||
}
|
||||
game.boards.emplace_back(array2D);
|
||||
getline(input, str);
|
||||
}
|
||||
return game;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
Game game = input; // Copy the data to be able to modify it
|
||||
int winner = -1;
|
||||
int i = 0;
|
||||
while (winner == -1)
|
||||
{
|
||||
int number = game.input[i];
|
||||
for (auto& board : game.boards)
|
||||
{
|
||||
if (MarkAndCheck(board, number))
|
||||
{
|
||||
int total = 0;
|
||||
for (auto& val : board)
|
||||
{
|
||||
if (val != -1)
|
||||
total += val;
|
||||
}
|
||||
return total * number;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
Game game = input; // Copy the data to be able to modify it
|
||||
int winner = -1;
|
||||
int i = 0;
|
||||
while (winner == -1)
|
||||
{
|
||||
int number = game.input[i];
|
||||
for (auto it = game.boards.begin(); it != game.boards.end();)
|
||||
{
|
||||
if (MarkAndCheck(*it, number))
|
||||
{
|
||||
if (game.boards.size() == 1)
|
||||
{
|
||||
int total = 0;
|
||||
for (auto& val : game.boards.front())
|
||||
{
|
||||
if (val != -1)
|
||||
total += val;
|
||||
}
|
||||
return total * number;
|
||||
}
|
||||
it = game.boards.erase(it);
|
||||
}
|
||||
else
|
||||
it++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day05
|
||||
{
|
||||
struct Line
|
||||
{
|
||||
int x1;
|
||||
int y1;
|
||||
int x2;
|
||||
int y2;
|
||||
};
|
||||
|
||||
REGISTER_DAY(2021, Day05, std::vector<Line>, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day05, ExampleInput, 1, 5);
|
||||
REGISTER_TEST(2021, Day05, Input, 1, 5442);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day05, ExampleInput, 2, 12);
|
||||
REGISTER_TEST(2021, Day05, Input, 2, 19571);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::string str;
|
||||
std::vector<Line> lines;
|
||||
while (getline(input, str))
|
||||
{
|
||||
std::stringstream ss{str};
|
||||
Line line;
|
||||
ss >> line.x1 >> "," >> line.y1 >> "->" >> line.x2 >> "," >> line.y2;
|
||||
lines.emplace_back(line);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
Index2D max;
|
||||
for (auto& line : input)
|
||||
{
|
||||
max.x = std::max({max.x, line.x1, line.x2});
|
||||
max.y = std::max({max.y, line.y1, line.y2});
|
||||
}
|
||||
Array2D<uint8_t> overlap{max.x + 1, max.y + 1};
|
||||
for (auto& line : input)
|
||||
{
|
||||
if (line.x1 == line.x2 || line.y1 == line.y2)
|
||||
{
|
||||
int width = std::max(std::abs(line.x1 - line.x2), std::abs(line.y1 - line.y2)) + 1;
|
||||
int deltaX = Helper::Sign(line.x2 - line.x1);
|
||||
int deltaY = Helper::Sign(line.y2 - line.y1);
|
||||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
Index2D index{line.x1 + deltaX * i, line.y1 + deltaY * i};
|
||||
overlap[index]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
int count = 0;
|
||||
overlap.Each(
|
||||
[&](const Array2D<uint8_t>& overlap, const Index2D& index)
|
||||
{
|
||||
if (overlap[index] > 1)
|
||||
count++;
|
||||
});
|
||||
return count;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
Index2D max;
|
||||
for (auto& line : input)
|
||||
{
|
||||
max.x = std::max({max.x, line.x1, line.x2});
|
||||
max.y = std::max({max.y, line.y1, line.y2});
|
||||
}
|
||||
Array2D<uint8_t> overlap{max.x + 1, max.y + 1};
|
||||
for (auto& line : input)
|
||||
{
|
||||
int width = std::max(std::abs(line.x1 - line.x2), std::abs(line.y1 - line.y2)) + 1;
|
||||
int deltaX = Helper::Sign(line.x2 - line.x1);
|
||||
int deltaY = Helper::Sign(line.y2 - line.y1);
|
||||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
Index2D index{line.x1 + deltaX * i, line.y1 + deltaY * i};
|
||||
overlap[index]++;
|
||||
}
|
||||
}
|
||||
int count = 0;
|
||||
overlap.Each(
|
||||
[&](const Array2D<uint8_t>& overlap, const Index2D& index)
|
||||
{
|
||||
if (overlap[index] > 1)
|
||||
count++;
|
||||
});
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day06
|
||||
{
|
||||
|
||||
int64_t GetPopulation(std::vector<int64_t>& lenternfishes, int days)
|
||||
{
|
||||
for (int i = 0; i < days; i++)
|
||||
{
|
||||
int64_t newBorn = lenternfishes[0];
|
||||
for (size_t j = 1; j < lenternfishes.size(); j++)
|
||||
{
|
||||
lenternfishes[j - 1] = lenternfishes[j];
|
||||
}
|
||||
lenternfishes[8] = newBorn;
|
||||
lenternfishes[6] += newBorn;
|
||||
}
|
||||
return Helper::Sum<int64_t>(lenternfishes);
|
||||
}
|
||||
|
||||
REGISTER_DAY(2021, Day06, std::vector<int64_t>, int64_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day06, ExampleInput, 1, 5934);
|
||||
REGISTER_TEST(2021, Day06, Input, 1, 374994);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day06, ExampleInput, 2, 26984457539);
|
||||
REGISTER_TEST(2021, Day06, Input, 2, 1686252324092);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::vector<int64_t> ints;
|
||||
ints.resize(9);
|
||||
|
||||
std::string str;
|
||||
while (getline(input, str, ','))
|
||||
{
|
||||
ints[atoi(str.c_str())]++;
|
||||
}
|
||||
return ints;
|
||||
}
|
||||
|
||||
OUTPUT1(inputConst)
|
||||
{
|
||||
InputType input = inputConst;
|
||||
return GetPopulation(input, 80);
|
||||
}
|
||||
|
||||
OUTPUT2(inputConst)
|
||||
{
|
||||
InputType input = inputConst;
|
||||
return GetPopulation(input, 256);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day07
|
||||
{
|
||||
REGISTER_DAY(2021, Day07, std::vector<int>, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day07, ExampleInput, 1, 37);
|
||||
REGISTER_TEST(2021, Day07, Input, 1, 359648);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day07, ExampleInput, 2, 168);
|
||||
REGISTER_TEST(2021, Day07, Input, 2, 100727924);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
return Input::ReadInts(input, ',');
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int max = Helper::Max(input);
|
||||
int min = Helper::Min(input);
|
||||
int minCost = std::numeric_limits<int>::max();
|
||||
for (int i = min; i < max + 1; i++)
|
||||
{
|
||||
int cost = 0;
|
||||
for (auto num : input)
|
||||
{
|
||||
cost += std::abs(num - i);
|
||||
}
|
||||
minCost = std::min(minCost, cost);
|
||||
}
|
||||
return minCost;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int max = Helper::Max(input);
|
||||
int min = Helper::Min(input);
|
||||
int minCost = std::numeric_limits<int>::max();
|
||||
for (int i = min; i < max + 1; i++)
|
||||
{
|
||||
int cost = 0;
|
||||
for (auto num : input)
|
||||
{
|
||||
int steps = std::abs(num - i);
|
||||
cost += steps * (steps + 1) / 2;
|
||||
}
|
||||
minCost = std::min(minCost, cost);
|
||||
}
|
||||
return minCost;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day08
|
||||
{
|
||||
struct Signal
|
||||
{
|
||||
std::vector<std::set<char>> numbers;
|
||||
std::vector<std::set<char>> display;
|
||||
};
|
||||
|
||||
REGISTER_DAY(2021, Day08, std::vector<Signal>, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day08, ExampleInput, 1, 26);
|
||||
REGISTER_TEST(2021, Day08, Input, 1, 301);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day08, ExampleInput, 2, 61229);
|
||||
REGISTER_TEST(2021, Day08, Input, 2, 908067);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::string str;
|
||||
std::vector<Signal> signals;
|
||||
while (getline(input, str))
|
||||
{
|
||||
Signal signal;
|
||||
std::stringstream ss{str};
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
std::string s;
|
||||
ss >> s;
|
||||
std::set<char> set;
|
||||
for (char c : s) set.emplace(c);
|
||||
signal.numbers.emplace_back(set);
|
||||
}
|
||||
char c;
|
||||
ss >> c;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
std::string s;
|
||||
ss >> s;
|
||||
std::set<char> set;
|
||||
for (char c : s) set.emplace(c);
|
||||
signal.display.emplace_back(set);
|
||||
}
|
||||
signals.emplace_back(signal);
|
||||
}
|
||||
return signals;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int count = 0;
|
||||
for (auto&& signal : input)
|
||||
{
|
||||
for (auto&& number : signal.display)
|
||||
{
|
||||
if (number.size() == 2 || number.size() == 3 || number.size() == 4 || number.size() == 7)
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int sum = 0;
|
||||
for (auto&& signal : input)
|
||||
{
|
||||
std::vector<std::set<char>> numbers(10);
|
||||
// Find all numbers with unique amount of segments
|
||||
for (auto&& number : signal.numbers)
|
||||
{
|
||||
if (number.size() == 2)
|
||||
numbers[1] = number;
|
||||
if (number.size() == 3)
|
||||
numbers[7] = number;
|
||||
if (number.size() == 4)
|
||||
numbers[4] = number;
|
||||
if (number.size() == 7)
|
||||
numbers[8] = number;
|
||||
}
|
||||
|
||||
// Find all numbers with five and six segments
|
||||
std::vector<std::set<char>> fivesegs;
|
||||
std::vector<std::set<char>> sixsegs;
|
||||
for (auto&& number : signal.numbers)
|
||||
{
|
||||
if (number.size() == 5)
|
||||
fivesegs.emplace_back(number);
|
||||
if (number.size() == 6)
|
||||
sixsegs.emplace_back(number);
|
||||
}
|
||||
|
||||
// Find number 3 (only five segment number which 1 is a subset of)
|
||||
for (auto it = fivesegs.begin(); it != fivesegs.end(); it++)
|
||||
{
|
||||
if (Helper::IsSubset(numbers[1], *it))
|
||||
{
|
||||
numbers[3] = *it;
|
||||
fivesegs.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Find number 6 (only six segment number which is not a subset of 1)
|
||||
for (auto it = sixsegs.begin(); it != sixsegs.end(); it++)
|
||||
{
|
||||
if (!Helper::IsSubset(numbers[1], *it))
|
||||
{
|
||||
numbers[6] = *it;
|
||||
sixsegs.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Find number 5 (only five segment number which is a subset of 6)
|
||||
for (auto it = fivesegs.begin(); it != fivesegs.end(); it++)
|
||||
{
|
||||
if (Helper::IsSubset(*it, numbers[6]))
|
||||
{
|
||||
numbers[5] = *it;
|
||||
fivesegs.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Find number 2 (last five segment number)
|
||||
numbers[2] = fivesegs.front();
|
||||
|
||||
// Find number 9 (only six segment number which 4 is a subset of)
|
||||
for (auto it = sixsegs.begin(); it != sixsegs.end(); it++)
|
||||
{
|
||||
if (Helper::IsSubset(numbers[4], *it))
|
||||
{
|
||||
numbers[9] = *it;
|
||||
sixsegs.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Find number 0 (last six segment number)
|
||||
numbers[0] = sixsegs.front();
|
||||
|
||||
// Calculate the segment display
|
||||
int num = 0;
|
||||
for (auto number : signal.display)
|
||||
{
|
||||
auto it = std::find(numbers.begin(), numbers.end(), number);
|
||||
int i = it - numbers.begin();
|
||||
num = num * 10 + i;
|
||||
}
|
||||
sum += num;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day09
|
||||
{
|
||||
REGISTER_DAY(2021, Day09, Array2D<int>, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day09, ExampleInput, 1, 15);
|
||||
REGISTER_TEST(2021, Day09, Input, 1, 478);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day09, ExampleInput, 2, 1134);
|
||||
REGISTER_TEST(2021, Day09, Input, 2, 1327014);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
return Input::ReadDigitsAsArray2D(input);
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int count = 0;
|
||||
Index2D index{0, 0};
|
||||
for (auto& val : input)
|
||||
{
|
||||
Index2D indices[4]{
|
||||
{index.x - 1, index.y}, {index.x, index.y - 1}, {index.x + 1, index.y}, {index.x, index.y + 1}};
|
||||
bool all = true;
|
||||
for (auto& ind : indices)
|
||||
{
|
||||
if (input.IsInside(ind) && input[ind] <= val)
|
||||
{
|
||||
all = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (all)
|
||||
count += val + 1;
|
||||
input.Increment(index);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
std::vector<Index2D> basins;
|
||||
Index2D index{0, 0};
|
||||
for (auto& val : input)
|
||||
{
|
||||
Index2D indices[4]{
|
||||
{index.x - 1, index.y}, {index.x, index.y - 1}, {index.x + 1, index.y}, {index.x, index.y + 1}};
|
||||
bool all = true;
|
||||
for (auto& ind : indices)
|
||||
{
|
||||
if (input.IsInside(ind) && input[ind] <= val)
|
||||
{
|
||||
all = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (all)
|
||||
basins.emplace_back(index);
|
||||
input.Increment(index);
|
||||
}
|
||||
|
||||
std::vector<int> numbers;
|
||||
for (auto&& basin : basins)
|
||||
{
|
||||
std::stack<Index2D> stack;
|
||||
std::set<Index2D> visited;
|
||||
stack.emplace(basin);
|
||||
visited.emplace(basin);
|
||||
while (!stack.empty())
|
||||
{
|
||||
auto index = stack.top();
|
||||
stack.pop();
|
||||
Index2D indices[4]{
|
||||
{index.x - 1, index.y}, {index.x, index.y - 1}, {index.x + 1, index.y}, {index.x, index.y + 1}};
|
||||
for (auto&& ind : indices)
|
||||
{
|
||||
if (input.IsInside(ind) && input[ind] != 9 && visited.find(ind) == visited.end())
|
||||
{
|
||||
stack.emplace(ind);
|
||||
visited.emplace(ind);
|
||||
}
|
||||
}
|
||||
}
|
||||
numbers.emplace_back(visited.size());
|
||||
}
|
||||
|
||||
std::sort(numbers.begin(), numbers.end());
|
||||
return numbers[numbers.size() - 1] * numbers[numbers.size() - 2] * numbers[numbers.size() - 3];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day10
|
||||
{
|
||||
REGISTER_DAY(2021, Day10, std::vector<std::string>, int64_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day10, ExampleInput, 1, 26397);
|
||||
REGISTER_TEST(2021, Day10, Input, 1, 240123);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day10, ExampleInput, 2, 288957);
|
||||
REGISTER_TEST(2021, Day10, Input, 2, 3260812321);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
return Input::ReadLines(input);
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
std::map<char, int64_t> values{{')', 3}, {']', 57}, {'}', 1197}, {'>', 25137}};
|
||||
Mapper<char, char> mapper{{'(', ')'}, {'[', ']'}, {'{', '}'}, {'<', '>'}};
|
||||
int64_t count = 0;
|
||||
for (auto&& str : input)
|
||||
{
|
||||
std::stack<char> stack;
|
||||
stack.emplace(str[0]);
|
||||
for (size_t i = 1; i < str.size(); i++)
|
||||
{
|
||||
char* ptr = mapper.GetFirst(str[i]);
|
||||
if (ptr)
|
||||
{
|
||||
if (stack.top() != *ptr)
|
||||
{
|
||||
count += values[str[i]];
|
||||
break;
|
||||
}
|
||||
stack.pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
stack.emplace(str[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
Mapper<char, char> mapper{{'(', ')'}, {'[', ']'}, {'{', '}'}, {'<', '>'}};
|
||||
std::map<char, int64_t> values{{'(', 1}, {'[', 2}, {'{', 3}, {'<', 4}};
|
||||
int64_t count = 0;
|
||||
std::vector<int64_t> scores;
|
||||
for (auto&& str : input)
|
||||
{
|
||||
std::stack<char> stack;
|
||||
stack.emplace(str[0]);
|
||||
bool valid = true;
|
||||
for (size_t i = 1; i < str.size(); i++)
|
||||
{
|
||||
char* ptr = mapper.GetFirst(str[i]);
|
||||
if (ptr)
|
||||
{
|
||||
if (stack.top() != *ptr)
|
||||
{
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
stack.pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
stack.emplace(str[i]);
|
||||
}
|
||||
}
|
||||
if (valid)
|
||||
{
|
||||
int64_t score = 0;
|
||||
while (!stack.empty())
|
||||
{
|
||||
score *= 5;
|
||||
score += values[stack.top()];
|
||||
stack.pop();
|
||||
}
|
||||
scores.emplace_back(score);
|
||||
}
|
||||
}
|
||||
std::sort(scores.begin(), scores.end());
|
||||
return scores[scores.size() / 2];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day11
|
||||
{
|
||||
|
||||
std::set<Index2D> CalculateFlashing(Array2D<int>& array)
|
||||
{
|
||||
for (auto& val : array) val++;
|
||||
std::set<Index2D> flashed;
|
||||
bool hasChanged = true;
|
||||
while (hasChanged)
|
||||
{
|
||||
Array2D<int> arrayCpy = array;
|
||||
hasChanged = false;
|
||||
Index2D index{0, 0};
|
||||
for (auto& val : array)
|
||||
{
|
||||
if (val > 9 && flashed.find(index) == flashed.end())
|
||||
{
|
||||
flashed.emplace(index);
|
||||
hasChanged = true;
|
||||
for (int y = -1; y < 2; y++)
|
||||
{
|
||||
for (int x = -1; x < 2; x++)
|
||||
{
|
||||
if (x == 0 && y == 0)
|
||||
continue;
|
||||
Index2D newIndex{index.x + x, index.y + y};
|
||||
if (array.IsInside(newIndex))
|
||||
arrayCpy[newIndex]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
array.Increment(index);
|
||||
}
|
||||
array = arrayCpy;
|
||||
}
|
||||
return flashed;
|
||||
}
|
||||
|
||||
REGISTER_DAY(2021, Day11, Array2D<int>, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day11, ExampleInput, 1, 1656);
|
||||
REGISTER_TEST(2021, Day11, Input, 1, 1667);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day11, ExampleInput, 2, 195);
|
||||
REGISTER_TEST(2021, Day11, Input, 2, 488);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
return Input::ReadDigitsAsArray2D(input);
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
InputType array = input;
|
||||
|
||||
int count = 0;
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
std::set<Index2D> flashed = CalculateFlashing(array);
|
||||
count += flashed.size();
|
||||
for (auto& flash : flashed) array[flash] = 0;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
InputType array = input;
|
||||
|
||||
int count = 1;
|
||||
while (true)
|
||||
{
|
||||
std::set<Index2D> flashed = CalculateFlashing(array);
|
||||
if (flashed.size() == array.width * array.height)
|
||||
return count;
|
||||
for (auto& flash : flashed) array[flash] = 0;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day12
|
||||
{
|
||||
struct Node
|
||||
{
|
||||
std::set<std::string> connections;
|
||||
};
|
||||
|
||||
struct Path
|
||||
{
|
||||
std::vector<std::string> path{"start"};
|
||||
bool hasDuplicate = false;
|
||||
};
|
||||
|
||||
using NodeMap = std::map<std::string, Node>;
|
||||
REGISTER_DAY(2021, Day12, NodeMap, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day12, ExampleInput, 1, 10);
|
||||
REGISTER_TEST(2021, Day12, Input, 1, 3887);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day12, ExampleInput, 2, 36);
|
||||
REGISTER_TEST(2021, Day12, Input, 2, 104834);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
NodeMap nodes;
|
||||
std::string str;
|
||||
while (getline(input, str))
|
||||
{
|
||||
std::stringstream ss{str};
|
||||
std::string from, to;
|
||||
getline(ss, from, '-');
|
||||
getline(ss, to);
|
||||
auto itFrom = nodes.find(from);
|
||||
auto itTo = nodes.find(to);
|
||||
if (itFrom == nodes.end())
|
||||
itFrom = nodes.emplace(from, Node{}).first;
|
||||
if (itTo == nodes.end())
|
||||
itTo = nodes.emplace(to, Node{}).first;
|
||||
|
||||
itFrom->second.connections.emplace(to);
|
||||
itTo->second.connections.emplace(from);
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int count = 0;
|
||||
std::stack<std::vector<std::string>> paths;
|
||||
paths.emplace(std::vector<std::string>{"start"});
|
||||
while (!paths.empty())
|
||||
{
|
||||
auto path = paths.top();
|
||||
paths.pop();
|
||||
if (path.back() == "end")
|
||||
{
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
auto it = input.find(path.back());
|
||||
for (auto& connection : it->second.connections)
|
||||
{
|
||||
if (connection[0] >= 'a' && connection[0] <= 'z')
|
||||
{
|
||||
if (std::find(path.begin(), path.end(), connection) == path.end())
|
||||
{
|
||||
std::vector<std::string> cpy = path;
|
||||
cpy.emplace_back(connection);
|
||||
paths.emplace(cpy);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::string> cpy = path;
|
||||
cpy.emplace_back(connection);
|
||||
paths.emplace(cpy);
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int count = 0;
|
||||
std::stack<Path> paths;
|
||||
paths.emplace(Path{});
|
||||
while (!paths.empty())
|
||||
{
|
||||
auto path = paths.top();
|
||||
paths.pop();
|
||||
if (path.path.back() == "end")
|
||||
{
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto it = input.find(path.path.back());
|
||||
for (auto& connection : it->second.connections)
|
||||
{
|
||||
if (connection[0] >= 'a' && connection[0] <= 'z')
|
||||
{
|
||||
if (std::find(path.path.begin(), path.path.end(), connection) == path.path.end())
|
||||
{
|
||||
Path cpy = path;
|
||||
cpy.path.emplace_back(connection);
|
||||
paths.emplace(cpy);
|
||||
}
|
||||
else if (!path.hasDuplicate && connection != "start")
|
||||
{
|
||||
Path cpy = path;
|
||||
cpy.path.emplace_back(connection);
|
||||
cpy.hasDuplicate = true;
|
||||
paths.emplace(cpy);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Path cpy = path;
|
||||
cpy.path.emplace_back(connection);
|
||||
paths.emplace(cpy);
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day13
|
||||
{
|
||||
|
||||
void Fold(std::set<Index2D>& indices, bool x, int fold)
|
||||
{
|
||||
std::set<Index2D> newIndices;
|
||||
for (auto& index : indices)
|
||||
{
|
||||
// y axis
|
||||
if (x)
|
||||
{
|
||||
Index2D newIndex = index;
|
||||
if (newIndex.x > fold)
|
||||
newIndex.x = fold - (newIndex.x - 1) % fold - 1;
|
||||
newIndices.emplace(newIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
Index2D newIndex = index;
|
||||
if (newIndex.y > fold)
|
||||
newIndex.y = fold - (newIndex.y - 1) % fold - 1;
|
||||
newIndices.emplace(newIndex);
|
||||
}
|
||||
}
|
||||
indices = newIndices;
|
||||
}
|
||||
|
||||
struct Paper
|
||||
{
|
||||
std::set<Index2D> indices;
|
||||
std::vector<std::pair<bool, int>> folds;
|
||||
};
|
||||
|
||||
REGISTER_DAY(2021, Day13, Paper, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day13, ExampleInput, 1, 17);
|
||||
REGISTER_TEST(2021, Day13, Input, 1, 716);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day13, ExampleInput, 2, 16);
|
||||
REGISTER_TEST(2021, Day13, Input, 2, 97);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
Paper paper;
|
||||
std::string str;
|
||||
while (getline(input, str))
|
||||
{
|
||||
if (str.empty())
|
||||
break;
|
||||
Index2D index;
|
||||
std::stringstream ss{str};
|
||||
ss >> index.x >> "," >> index.y;
|
||||
paper.indices.emplace(index);
|
||||
}
|
||||
|
||||
while (getline(input, str))
|
||||
{
|
||||
char c, c2;
|
||||
std::string s;
|
||||
int i;
|
||||
std::stringstream ss{str};
|
||||
ss >> s >> s >> c >> c2 >> i;
|
||||
paper.folds.emplace_back(c == 'x', i);
|
||||
}
|
||||
return paper;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
std::set<Index2D> indices = input.indices;
|
||||
Fold(indices, input.folds.front().first, input.folds.front().second);
|
||||
return indices.size();
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
std::set<Index2D> indices = input.indices;
|
||||
for (auto& fold : input.folds)
|
||||
{
|
||||
Fold(indices, fold.first, fold.second);
|
||||
}
|
||||
|
||||
Index2D max = *indices.begin();
|
||||
for (auto index : indices)
|
||||
{
|
||||
max.x = std::max(index.x, max.x);
|
||||
max.y = std::max(index.y, max.y);
|
||||
}
|
||||
Array2D<char> board{max.x + 1, max.y + 1};
|
||||
board.Fill(' ');
|
||||
for (auto& index : indices)
|
||||
{
|
||||
board[index] = '#';
|
||||
}
|
||||
std::cout << board;
|
||||
// Not the "correct" output to part 2, but it verifies something at least
|
||||
return indices.size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day14
|
||||
{
|
||||
struct Data
|
||||
{
|
||||
std::string str;
|
||||
std::map<std::string, char> pairs;
|
||||
};
|
||||
|
||||
REGISTER_DAY(2021, Day14, Data, int64_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day14, ExampleInput, 1, 1588);
|
||||
REGISTER_TEST(2021, Day14, Input, 1, 4517);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day14, ExampleInput, 2, 2188189693529);
|
||||
REGISTER_TEST(2021, Day14, Input, 2, 4704817645083);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
Data data;
|
||||
getline(input, data.str);
|
||||
std::string str;
|
||||
getline(input, str);
|
||||
|
||||
while (getline(input, str))
|
||||
{
|
||||
data.pairs.emplace(str.substr(0, 2), str[6]);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
std::string str = input.str;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
std::string newString;
|
||||
for (size_t j = 0; j < str.size() - 1; j++)
|
||||
{
|
||||
auto it = input.pairs.find(str.substr(j, 2));
|
||||
newString.push_back(str[j]);
|
||||
newString.push_back(it->second);
|
||||
}
|
||||
newString.push_back(str.back());
|
||||
str = newString;
|
||||
}
|
||||
std::map<char, int64_t> occurences;
|
||||
for (char c : str)
|
||||
{
|
||||
occurences[c]++;
|
||||
}
|
||||
int64_t min = occurences.begin()->second;
|
||||
char minChar = occurences.begin()->first;
|
||||
int64_t max = occurences.begin()->second;
|
||||
char maxChar = occurences.begin()->first;
|
||||
for (auto& occurence : occurences)
|
||||
{
|
||||
if (occurence.second < min)
|
||||
{
|
||||
min = occurence.second;
|
||||
minChar = occurence.first;
|
||||
}
|
||||
if (occurence.second > max)
|
||||
{
|
||||
max = occurence.second;
|
||||
maxChar = occurence.first;
|
||||
}
|
||||
}
|
||||
return occurences[maxChar] - occurences[minChar];
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
std::string str = input.str;
|
||||
std::map<std::string, int64_t> pairCounts;
|
||||
for (size_t j = 0; j < str.size() - 1; j++)
|
||||
{
|
||||
pairCounts[input.str.substr(j, 2)]++;
|
||||
}
|
||||
for (int i = 0; i < 40; i++)
|
||||
{
|
||||
std::map<std::string, int64_t> cpy = pairCounts;
|
||||
for (auto& pairCount : cpy)
|
||||
{
|
||||
if (pairCount.second <= 0)
|
||||
continue;
|
||||
auto it = input.pairs.find(pairCount.first);
|
||||
std::string firstPair = pairCount.first.substr(0, 1) + it->second;
|
||||
std::string secondPair = it->second + pairCount.first.substr(1, 1);
|
||||
pairCounts[firstPair] += pairCount.second;
|
||||
pairCounts[secondPair] += pairCount.second;
|
||||
pairCounts[pairCount.first] -= pairCount.second;
|
||||
}
|
||||
}
|
||||
std::map<char, int64_t> occurences;
|
||||
for (auto& pairCount : pairCounts)
|
||||
{
|
||||
if (pairCount.second != 0)
|
||||
occurences[pairCount.first[0]] += pairCount.second;
|
||||
}
|
||||
occurences[str.back()]++;
|
||||
int64_t min = occurences.begin()->second;
|
||||
char minChar = occurences.begin()->first;
|
||||
int64_t max = occurences.begin()->second;
|
||||
char maxChar = occurences.begin()->first;
|
||||
for (auto& occurence : occurences)
|
||||
{
|
||||
if (occurence.second < min)
|
||||
{
|
||||
min = occurence.second;
|
||||
minChar = occurence.first;
|
||||
}
|
||||
if (occurence.second > max)
|
||||
{
|
||||
max = occurence.second;
|
||||
maxChar = occurence.first;
|
||||
}
|
||||
}
|
||||
return occurences[maxChar] - occurences[minChar];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day15
|
||||
{
|
||||
|
||||
int Heuristic(const Array2D<int>& array, const Index2D& index)
|
||||
{
|
||||
return std::abs(index.x - array.width + 1) && std::abs(index.y - array.height + 1);
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, Index2D>> Branch(const Array2D<int>& array, const Index2D& index)
|
||||
{
|
||||
Index2D indices[4]{{index.x - 1, index.y}, {index.x, index.y - 1}, {index.x + 1, index.y}, {index.x, index.y + 1}};
|
||||
std::vector<std::pair<int, Index2D>> moves;
|
||||
for (auto& index : indices)
|
||||
{
|
||||
if (array.IsInside(index))
|
||||
moves.emplace_back(std::pair<int, Index2D>{array[index], index});
|
||||
}
|
||||
return moves;
|
||||
}
|
||||
|
||||
int Goal(const Array2D<int>& array, const Index2D& index)
|
||||
{
|
||||
return index.x == array.width - 1 && index.y == array.height - 1;
|
||||
}
|
||||
|
||||
int Pathfinder(const Array2D<int>& array)
|
||||
{
|
||||
return Helper::AStar(array, Index2D{0, 0}, Heuristic, Branch, Goal);
|
||||
}
|
||||
|
||||
REGISTER_DAY(2021, Day15, Array2D<int>, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day15, ExampleInput, 1, 40);
|
||||
REGISTER_TEST(2021, Day15, Input, 1, 714);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day15, ExampleInput, 2, 315);
|
||||
REGISTER_TEST(2021, Day15, Input, 2, 2948);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
return Input::ReadDigitsAsArray2D(input);
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
return Pathfinder(input);
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
Array2D<int> array{input.width * 5, input.height * 5};
|
||||
Index2D index{0, 0};
|
||||
for (auto& val : array)
|
||||
{
|
||||
val = input.GetMod(index.x, index.y) + index.x / input.width + index.y / input.height;
|
||||
if (val >= 10)
|
||||
val = val % 10 + 1;
|
||||
array.Increment(index);
|
||||
}
|
||||
return Pathfinder(array);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day16
|
||||
{
|
||||
int64_t Read(const std::string& str, int& offset, int size)
|
||||
{
|
||||
int64_t i = Helper::BinStrToInt64(str.substr(offset, size));
|
||||
offset += size;
|
||||
return i;
|
||||
}
|
||||
|
||||
std::pair<int64_t, int64_t> ReadPacket(const std::string& str, int& offset)
|
||||
{
|
||||
int64_t version = Read(str, offset, 3);
|
||||
int64_t type = Read(str, offset, 3);
|
||||
|
||||
if (type == 4)
|
||||
{
|
||||
// Normal packet
|
||||
int64_t type = Read(str, offset, 1);
|
||||
int64_t val = 0;
|
||||
while (type == 1)
|
||||
{
|
||||
val = (val << 4) | Read(str, offset, 4);
|
||||
type = Read(str, offset, 1);
|
||||
}
|
||||
val = (val << 4) | Read(str, offset, 4);
|
||||
return {version, val};
|
||||
}
|
||||
else
|
||||
{
|
||||
// Packet containing packets
|
||||
int64_t lengthId = Read(str, offset, 1);
|
||||
std::vector<int64_t> values;
|
||||
int64_t versionTotal = version;
|
||||
if (lengthId == 0)
|
||||
{
|
||||
int64_t totalLength = Read(str, offset, 15);
|
||||
int64_t start = offset;
|
||||
while (offset < start + totalLength)
|
||||
{
|
||||
auto [version, value] = ReadPacket(str, offset);
|
||||
values.emplace_back(value);
|
||||
versionTotal += version;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int64_t totalPackets = Read(str, offset, 11);
|
||||
for (int64_t i = 0; i < totalPackets; i++)
|
||||
{
|
||||
auto [version, value] = ReadPacket(str, offset);
|
||||
values.emplace_back(value);
|
||||
versionTotal += version;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == 0)
|
||||
return {versionTotal,
|
||||
std::accumulate(values.begin(), values.end(), 0ll, [](int64_t sum, int64_t val) { return sum + val; })};
|
||||
else if (type == 1)
|
||||
return {
|
||||
versionTotal,
|
||||
std::accumulate(values.begin(), values.end(), 1ll, [](int64_t prod, int64_t val) { return prod * val; })};
|
||||
else if (type == 2)
|
||||
return {
|
||||
versionTotal,
|
||||
std::accumulate(
|
||||
values.begin(), values.end(), values.front(), [](int64_t max, int64_t val) { return std::min(max, val); })};
|
||||
else if (type == 3)
|
||||
return {
|
||||
versionTotal,
|
||||
std::accumulate(
|
||||
values.begin(), values.end(), values.front(), [](int64_t min, int64_t val) { return std::max(min, val); })};
|
||||
else if (type == 5)
|
||||
return {versionTotal, values[0] > values[1] ? 1 : 0};
|
||||
else if (type == 6)
|
||||
return {versionTotal, values[0] < values[1] ? 1 : 0};
|
||||
else if (type == 7)
|
||||
return {versionTotal, values[0] == values[1] ? 1 : 0};
|
||||
}
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
std::pair<int64_t, int64_t> ReadPacket(const std::string& str)
|
||||
{
|
||||
int offset = 0;
|
||||
return ReadPacket(str, offset);
|
||||
}
|
||||
|
||||
REGISTER_DAY(2021, Day16, std::string, int64_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day16, ExampleInput, 1, 20);
|
||||
REGISTER_TEST(2021, Day16, Input, 1, 984);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day16, ExampleInput, 2, 1);
|
||||
REGISTER_TEST(2021, Day16, Input, 2, 1015320896946);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::string str;
|
||||
getline(input, str);
|
||||
std::string bin;
|
||||
for (char c : str)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
{
|
||||
char val = c - '0'; // vs compiler throws warnings if this is inlined into the bitset function...
|
||||
bin += std::bitset<4>(val).to_string();
|
||||
}
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
{
|
||||
char val = c - 'A' + 10; // vs compiler throws warnings if this is inlined into the bitset function...
|
||||
bin += std::bitset<4>(val).to_string();
|
||||
}
|
||||
}
|
||||
return bin;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
return ReadPacket(input).first;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
return ReadPacket(input).second;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day17
|
||||
{
|
||||
struct Area
|
||||
{
|
||||
Index2D p1;
|
||||
Index2D p2;
|
||||
};
|
||||
|
||||
REGISTER_DAY(2021, Day17, Area, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day17, ExampleInput, 1, 45);
|
||||
REGISTER_TEST(2021, Day17, Input, 1, 2701);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day17, ExampleInput, 2, 112);
|
||||
REGISTER_TEST(2021, Day17, Input, 2, 1070);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
Area area;
|
||||
input >> "target area: x=" >> area.p1.x >> ".." >> area.p2.x >> ", y=" >> area.p1.y >> ".." >> area.p2.y;
|
||||
return area;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
int v = -input.p1.y;
|
||||
return v * (v - 1) / 2;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int count = 0;
|
||||
for (int y = input.p1.y - 1; y <= -input.p1.y; y++)
|
||||
{
|
||||
for (int x = 1; x <= input.p2.x; x++)
|
||||
{
|
||||
int xPos = 0;
|
||||
int yPos = 0;
|
||||
|
||||
int vx = x;
|
||||
int vy = y;
|
||||
while (xPos <= input.p2.x && yPos >= input.p1.y)
|
||||
{
|
||||
if (xPos >= input.p1.x && xPos <= input.p2.x && yPos >= input.p1.y && yPos <= input.p2.y)
|
||||
{
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
xPos += vx;
|
||||
yPos += vy;
|
||||
vx--;
|
||||
if (vx < 0)
|
||||
vx = 0;
|
||||
vy--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day18
|
||||
{
|
||||
struct Node
|
||||
{
|
||||
Node* parent = nullptr;
|
||||
int value = 0;
|
||||
std::vector<Node> nodes;
|
||||
|
||||
Node() = default;
|
||||
|
||||
Node(const std::string& str)
|
||||
: nodes{Node{}, Node{}}
|
||||
{
|
||||
UpdateParents();
|
||||
std::stringstream ss{str};
|
||||
ss >> *this;
|
||||
}
|
||||
|
||||
Node(int value)
|
||||
: value{value}
|
||||
{
|
||||
}
|
||||
|
||||
Node(const Node& left, const Node& right)
|
||||
: nodes{left, right}
|
||||
{
|
||||
UpdateParents();
|
||||
}
|
||||
|
||||
Node& Left()
|
||||
{
|
||||
return nodes[0];
|
||||
}
|
||||
|
||||
const Node& Left() const
|
||||
{
|
||||
return nodes[0];
|
||||
}
|
||||
|
||||
Node& Right()
|
||||
{
|
||||
return nodes[1];
|
||||
}
|
||||
|
||||
const Node& Right() const
|
||||
{
|
||||
return nodes[1];
|
||||
}
|
||||
|
||||
bool IsNumber() const
|
||||
{
|
||||
return nodes.size() == 0;
|
||||
}
|
||||
|
||||
int& Number()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
int Number() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
int Calculate()
|
||||
{
|
||||
int i = 0;
|
||||
if (Left().IsNumber())
|
||||
i += 3 * Left().Number();
|
||||
else
|
||||
i += 3 * Left().Calculate();
|
||||
|
||||
if (Right().IsNumber())
|
||||
i += 2 * Right().Number();
|
||||
else
|
||||
i += 2 * Right().Calculate();
|
||||
return i;
|
||||
}
|
||||
|
||||
void AddToLeft(int value, Node* from)
|
||||
{
|
||||
if (Left().IsNumber())
|
||||
Left().Number() += value;
|
||||
else
|
||||
{
|
||||
Node& node = Left();
|
||||
if (&node == from)
|
||||
{
|
||||
if (parent != nullptr)
|
||||
parent->AddToLeft(value, this);
|
||||
}
|
||||
else
|
||||
node.AddToRightDown(value);
|
||||
}
|
||||
}
|
||||
|
||||
void AddToRightDown(int value)
|
||||
{
|
||||
if (Right().IsNumber())
|
||||
Right().Number() += value;
|
||||
else
|
||||
{
|
||||
Right().AddToRightDown(value);
|
||||
}
|
||||
}
|
||||
|
||||
void AddToRight(int value, Node* from)
|
||||
{
|
||||
if (Right().IsNumber())
|
||||
Right().Number() += value;
|
||||
else
|
||||
{
|
||||
Node& node = Right();
|
||||
if (&node == from)
|
||||
{
|
||||
if (parent != nullptr)
|
||||
parent->AddToRight(value, this);
|
||||
}
|
||||
else
|
||||
node.AddToLeftDown(value);
|
||||
}
|
||||
}
|
||||
|
||||
void AddToLeftDown(int value)
|
||||
{
|
||||
if (Left().IsNumber())
|
||||
Left().Number() += value;
|
||||
else
|
||||
{
|
||||
Left().AddToLeftDown(value);
|
||||
}
|
||||
}
|
||||
|
||||
bool Explode(int depth = 0)
|
||||
{
|
||||
if (depth >= 4)
|
||||
{
|
||||
parent->AddToLeft(Left().Number(), this);
|
||||
parent->AddToRight(Right().Number(), this);
|
||||
|
||||
if (!parent->Left().IsNumber() && &parent->Left() == this)
|
||||
parent->Left() = 0;
|
||||
if (!parent->Right().IsNumber() && &parent->Right() == this)
|
||||
parent->Right() = 0;
|
||||
return true;
|
||||
}
|
||||
if (!Left().IsNumber())
|
||||
if (Left().Explode(depth + 1))
|
||||
return true;
|
||||
if (!Right().IsNumber())
|
||||
if (Right().Explode(depth + 1))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Split()
|
||||
{
|
||||
if (!Left().IsNumber())
|
||||
{
|
||||
if (Left().Split())
|
||||
return true;
|
||||
}
|
||||
else if (Left().Number() >= 10)
|
||||
{
|
||||
int val = Left().Number();
|
||||
Node node{(val >> 1), (val >> 1) + (val % 2)};
|
||||
node.parent = this;
|
||||
Left() = node;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Right().IsNumber())
|
||||
{
|
||||
if (Right().Split())
|
||||
return true;
|
||||
}
|
||||
else if (Right().Number() >= 10)
|
||||
{
|
||||
int val = Right().Number();
|
||||
Node node{(val >> 1), (val >> 1) + (val % 2)};
|
||||
node.parent = this;
|
||||
Right() = node;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void UpdateParents()
|
||||
{
|
||||
if (!Left().IsNumber())
|
||||
{
|
||||
Left().parent = this;
|
||||
Left().UpdateParents();
|
||||
}
|
||||
if (!Right().IsNumber())
|
||||
{
|
||||
Right().parent = this;
|
||||
Right().UpdateParents();
|
||||
}
|
||||
}
|
||||
|
||||
void Print(std::ostream& stream, int depth) const
|
||||
{
|
||||
std::vector<char> depthStart{'|', '<', '{', '(', '['};
|
||||
std::vector<char> depthEnd{'|', '>', '}', ')', ']'};
|
||||
stream << depthStart[depth];
|
||||
if (Left().IsNumber())
|
||||
stream << Left().Number();
|
||||
else
|
||||
Left().Print(stream, depth + 1);
|
||||
stream << ",";
|
||||
if (Right().IsNumber())
|
||||
stream << Right().Number();
|
||||
else
|
||||
Right().Print(stream, depth + 1);
|
||||
stream << depthEnd[depth];
|
||||
}
|
||||
|
||||
void operator=(int value)
|
||||
{
|
||||
nodes.clear();
|
||||
this->value = value;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const Node& node)
|
||||
{
|
||||
node.Print(stream, 0);
|
||||
return stream;
|
||||
}
|
||||
|
||||
friend std::istream& operator>>(std::istream& stream, Node& node)
|
||||
{
|
||||
stream >> "[";
|
||||
if (stream.peek() == '[')
|
||||
{
|
||||
Node left{Node{}, Node{}};
|
||||
stream >> left;
|
||||
left.parent = &node;
|
||||
node.Left() = left;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
stream >> i;
|
||||
node.Left() = i;
|
||||
}
|
||||
stream >> ",";
|
||||
if (stream.peek() == '[')
|
||||
{
|
||||
Node right{Node{}, Node{}};
|
||||
stream >> right;
|
||||
right.parent = &node;
|
||||
node.Right() = right;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
stream >> i;
|
||||
node.Right() = i;
|
||||
}
|
||||
stream >> "]";
|
||||
return stream;
|
||||
}
|
||||
};
|
||||
|
||||
Node Reduce(const Node& lhs, const Node& rhs)
|
||||
{
|
||||
Node node{lhs, rhs};
|
||||
bool changed = true;
|
||||
while (changed)
|
||||
{
|
||||
changed = false;
|
||||
while (node.Explode()) changed = true;
|
||||
if (node.Split())
|
||||
changed = true;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
REGISTER_DAY(2021, Day18, std::vector<Node>, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day18, ExampleInput, 1, 4140);
|
||||
REGISTER_TEST(2021, Day18, Input, 1, 4137);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day18, ExampleInput, 2, 3993);
|
||||
REGISTER_TEST(2021, Day18, Input, 2, 4573);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::vector<Node> nodes;
|
||||
std::string str;
|
||||
while (getline(input, str))
|
||||
{
|
||||
nodes.emplace_back(str);
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
Node node = input[0];
|
||||
for (size_t i = 1; i < input.size(); i++)
|
||||
{
|
||||
node = Reduce(node, input[i]);
|
||||
}
|
||||
return node.Calculate();
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
int max = 0;
|
||||
for (size_t i = 0; i < input.size() - 1; i++)
|
||||
{
|
||||
for (size_t j = 1; j < input.size(); j++)
|
||||
{
|
||||
max = std::max(max, Reduce(input[j], input[i]).Calculate());
|
||||
max = std::max(max, Reduce(input[i], input[j]).Calculate());
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day19
|
||||
{
|
||||
constexpr int MAX_ORIENTATIONS = 24;
|
||||
constexpr int MIN_OVERLAP = 12;
|
||||
|
||||
struct Scanner
|
||||
{
|
||||
std::set<Index3D> beacons;
|
||||
};
|
||||
|
||||
struct Overlap
|
||||
{
|
||||
bool overlapping = false;
|
||||
int orientation = 0;
|
||||
Index3D offset{0, 0};
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const Overlap& overlap)
|
||||
{
|
||||
if (overlap.overlapping)
|
||||
return stream << "true " << overlap.orientation << " " << overlap.offset;
|
||||
else
|
||||
return stream << "false";
|
||||
}
|
||||
|
||||
operator bool()
|
||||
{
|
||||
return overlapping;
|
||||
}
|
||||
};
|
||||
|
||||
Index3D RotateY(const Index3D& index)
|
||||
{
|
||||
return Index3D{-index.z, index.y, index.x};
|
||||
}
|
||||
|
||||
Index3D RotateY2(const Index3D& index)
|
||||
{
|
||||
return Index3D{-index.x, index.y, -index.z};
|
||||
}
|
||||
|
||||
Index3D RotateY3(const Index3D& index)
|
||||
{
|
||||
return Index3D{index.z, index.y, -index.x};
|
||||
}
|
||||
|
||||
Index3D RotateX(const Index3D& index)
|
||||
{
|
||||
return Index3D{index.x, -index.z, index.y};
|
||||
}
|
||||
|
||||
Index3D RotateX2(const Index3D& index)
|
||||
{
|
||||
return Index3D{index.x, -index.y, -index.z};
|
||||
}
|
||||
|
||||
Index3D RotateX3(const Index3D& index)
|
||||
{
|
||||
return Index3D{index.x, index.z, -index.y};
|
||||
}
|
||||
|
||||
Index3D RotateZ(const Index3D& index)
|
||||
{
|
||||
return Index3D{-index.y, index.x, index.z};
|
||||
}
|
||||
|
||||
Index3D RotateZ2(const Index3D& index)
|
||||
{
|
||||
return Index3D{-index.x, -index.y, index.z};
|
||||
}
|
||||
|
||||
Index3D RotateZ3(const Index3D& index)
|
||||
{
|
||||
return Index3D{index.y, -index.x, index.z};
|
||||
}
|
||||
|
||||
Index3D Orient(const Index3D& index, int i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
// Facing forward
|
||||
case 0:
|
||||
return index;
|
||||
case 1:
|
||||
return RotateZ(index);
|
||||
case 2:
|
||||
return RotateZ2(index);
|
||||
case 3:
|
||||
return RotateZ3(index);
|
||||
|
||||
// Facing left
|
||||
case 4:
|
||||
return RotateY(index);
|
||||
case 5:
|
||||
return RotateX(RotateY(index));
|
||||
case 6:
|
||||
return RotateX2(RotateY(index));
|
||||
case 7:
|
||||
return RotateX3(RotateY(index));
|
||||
|
||||
// Facing backward
|
||||
case 8:
|
||||
return RotateY2(index);
|
||||
case 9:
|
||||
return RotateZ(RotateY2(index));
|
||||
case 10:
|
||||
return RotateZ2(RotateY2(index));
|
||||
case 11:
|
||||
return RotateZ3(RotateY2(index));
|
||||
|
||||
// Facing right
|
||||
case 12:
|
||||
return RotateY3(index);
|
||||
case 13:
|
||||
return RotateX(RotateY3(index));
|
||||
case 14:
|
||||
return RotateX2(RotateY3(index));
|
||||
case 15:
|
||||
return RotateX3(RotateY3(index));
|
||||
|
||||
// Facing down
|
||||
case 16:
|
||||
return RotateX(index);
|
||||
case 17:
|
||||
return RotateY(RotateX(index));
|
||||
case 18:
|
||||
return RotateY2(RotateX(index));
|
||||
case 19:
|
||||
return RotateY3(RotateX(index));
|
||||
|
||||
// Facing up
|
||||
case 20:
|
||||
return RotateX3(index);
|
||||
case 21:
|
||||
return RotateY(RotateX3(index));
|
||||
case 22:
|
||||
return RotateY2(RotateX3(index));
|
||||
case 23:
|
||||
return RotateY3(RotateX3(index));
|
||||
}
|
||||
std::cout << "Invalid orientation: " << i << std::endl;
|
||||
return index;
|
||||
}
|
||||
|
||||
Overlap IsOverlapping(const std::set<Index3D>& layout, const Scanner& scanner)
|
||||
{
|
||||
for (auto& index : layout)
|
||||
{
|
||||
int beaconsLeft = scanner.beacons.size();
|
||||
for (auto it = scanner.beacons.begin(); it != scanner.beacons.end(); it++)
|
||||
{
|
||||
if (beaconsLeft < MIN_OVERLAP)
|
||||
break;
|
||||
beaconsLeft--;
|
||||
|
||||
for (int i = 0; i < MAX_ORIENTATIONS; i++)
|
||||
{
|
||||
Index3D offset = index - Orient(*it, i);
|
||||
int count = 0;
|
||||
for (auto it2 = scanner.beacons.begin(); it2 != scanner.beacons.end(); it2++)
|
||||
{
|
||||
if (layout.count(offset + Orient(*it2, i)))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count >= MIN_OVERLAP)
|
||||
return {true, i, offset};
|
||||
}
|
||||
}
|
||||
}
|
||||
return {false, 0, Index3D{0, 0}};
|
||||
}
|
||||
|
||||
std::pair<int, int> Solve(std::vector<Scanner> scanners)
|
||||
{
|
||||
// Find first overlap to initialize the "correct" layout
|
||||
std::set<Index3D> layout;
|
||||
for (auto it = scanners.begin(); it != scanners.end(); it++)
|
||||
{
|
||||
bool found = false;
|
||||
for (auto it2 = it; it2 != scanners.end(); it2++)
|
||||
{
|
||||
if (it == it2)
|
||||
continue;
|
||||
Overlap overlap = IsOverlapping(it->beacons, *it2);
|
||||
if (overlap)
|
||||
{
|
||||
layout = it->beacons;
|
||||
scanners.erase(it);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
break;
|
||||
}
|
||||
|
||||
// Find overlapping scanners one by one
|
||||
std::vector<Index3D> scannerPos{Index3D{0, 0, 0}};
|
||||
while (!scanners.empty())
|
||||
{
|
||||
bool removed = false;
|
||||
for (auto it = scanners.begin(); it != scanners.end(); it++)
|
||||
{
|
||||
Overlap overlap = IsOverlapping(layout, *it);
|
||||
if (overlap)
|
||||
{
|
||||
for (auto& beacon : it->beacons)
|
||||
{
|
||||
layout.emplace(overlap.offset + Orient(beacon, overlap.orientation));
|
||||
}
|
||||
scannerPos.emplace_back(overlap.offset);
|
||||
scanners.erase(it);
|
||||
removed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!removed)
|
||||
{
|
||||
std::cout << "Could not find position of any remaining scanners" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Find largest manhattan distance between two scanners
|
||||
int maxDistance = 0;
|
||||
for (size_t i = 0; i < scannerPos.size(); i++)
|
||||
{
|
||||
for (size_t j = i + 1; j < scannerPos.size(); j++)
|
||||
{
|
||||
Index3D distance = scannerPos[i] - scannerPos[j];
|
||||
maxDistance = std::max(maxDistance, std::abs(distance.x) + std::abs(distance.y) + std::abs(distance.z));
|
||||
}
|
||||
}
|
||||
return {layout.size(), maxDistance};
|
||||
}
|
||||
|
||||
REGISTER_DAY(2021, Day19, std::vector<Scanner>, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day19, ExampleInput, 1, 79);
|
||||
REGISTER_TEST(2021, Day19, Input, 1, 359);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day19, ExampleInput, 2, 3621);
|
||||
REGISTER_TEST(2021, Day19, Input, 2, 12292);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::vector<Scanner> scanners;
|
||||
std::string str;
|
||||
while (getline(input, str))
|
||||
{
|
||||
Scanner scanner;
|
||||
getline(input, str);
|
||||
while (!str.empty())
|
||||
{
|
||||
std::stringstream ss{str};
|
||||
Index3D index;
|
||||
ss >> index.x >> "," >> index.y >> "," >> index.z;
|
||||
scanner.beacons.emplace(index);
|
||||
str.clear();
|
||||
getline(input, str);
|
||||
}
|
||||
scanners.emplace_back(scanner);
|
||||
}
|
||||
return scanners;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
return Solve(input).first;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
return Solve(input).second;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day20
|
||||
{
|
||||
struct Data
|
||||
{
|
||||
std::string line;
|
||||
Array2D<char> grid;
|
||||
};
|
||||
|
||||
int GetNumber(const Array2D<char>& array, Index2D index)
|
||||
{
|
||||
int num = 0;
|
||||
for (int y = index.y - 1; y <= index.y + 1; y++)
|
||||
{
|
||||
for (int x = index.x - 1; x <= index.x + 1; x++)
|
||||
{
|
||||
num <<= 1;
|
||||
Index2D newIndex{x, y};
|
||||
if (array.IsInside(newIndex) && array[newIndex] == '#')
|
||||
num |= 1;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
int Solve(const Data& input, int iter)
|
||||
{
|
||||
int SIZE = (2 * iter) * 2;
|
||||
Array2D<char> output{input.grid.width + SIZE, input.grid.height + SIZE};
|
||||
Index2D index{0, 0};
|
||||
output.Fill('.');
|
||||
for (auto& val : input.grid)
|
||||
{
|
||||
output.Set(index.x + SIZE / 2, index.y + SIZE / 2, val);
|
||||
input.grid.Increment(index);
|
||||
}
|
||||
for (int i = 0; i < iter; i++)
|
||||
{
|
||||
Array2D<char> cpy = output;
|
||||
Index2D index{0, 0};
|
||||
for (auto& grid : output)
|
||||
{
|
||||
int num = GetNumber(cpy, index);
|
||||
output[index] = input.line[num];
|
||||
output.Increment(index);
|
||||
}
|
||||
std::string str;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (int y = iter; y < output.height - iter; y++)
|
||||
for (int x = iter; x < output.width - iter; x++)
|
||||
if (output.Get(x, y) == '#')
|
||||
count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
REGISTER_DAY(2021, Day20, Data, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day20, ExampleInput, 1, 35);
|
||||
REGISTER_TEST(2021, Day20, Input, 1, 5203);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day20, ExampleInput, 2, 3351);
|
||||
REGISTER_TEST(2021, Day20, Input, 2, 18806);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
Data data;
|
||||
std::getline(input, data.line);
|
||||
std::string str;
|
||||
getline(input, str);
|
||||
data.grid = Input::ReadArray2D(input);
|
||||
return data;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
return Solve(input, 2);
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
return Solve(input, 50);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day21
|
||||
{
|
||||
|
||||
int Mod(int i)
|
||||
{
|
||||
return (i - 1) % 10 + 1;
|
||||
}
|
||||
|
||||
std::pair<int64_t, int64_t> Roll(int position1, int points1, int position2, int points2, bool player1, int depth)
|
||||
{
|
||||
if (points2 >= 21)
|
||||
return {0, 1};
|
||||
else if (points1 >= 21)
|
||||
return {1, 0};
|
||||
|
||||
// 3: 111
|
||||
// 4: 211 121 112
|
||||
// 5: 221 212 122 311 131 113
|
||||
// 6: 222 321 312 213 231 123 132
|
||||
// 7: 223 232 323 133 331 313
|
||||
// 8: 233 323 322
|
||||
// 9: 333
|
||||
std::map<int, int> outcomes{{3, 1}, {4, 3}, {5, 6}, {6, 7}, {7, 6}, {8, 3}, {9, 1}};
|
||||
|
||||
std::pair<int64_t, int64_t> wins{0, 0};
|
||||
int initialPos = 0;
|
||||
int initialPoints = 0;
|
||||
if (player1)
|
||||
{
|
||||
initialPos = position1;
|
||||
initialPoints = points1;
|
||||
}
|
||||
else
|
||||
{
|
||||
initialPos = position2;
|
||||
initialPoints = points2;
|
||||
}
|
||||
for (auto [value, times] : outcomes)
|
||||
{
|
||||
if (player1)
|
||||
{
|
||||
position1 = initialPos;
|
||||
points1 = initialPoints;
|
||||
position1 = Mod(position1 + value);
|
||||
points1 += position1;
|
||||
}
|
||||
else
|
||||
{
|
||||
position2 = initialPos;
|
||||
points2 = initialPoints;
|
||||
position2 = Mod(position2 + value);
|
||||
points2 += position2;
|
||||
}
|
||||
auto subwins = Roll(position1, points1, position2, points2, !player1, depth + 1);
|
||||
wins.first += times * subwins.first;
|
||||
wins.second += times * subwins.second;
|
||||
}
|
||||
return wins;
|
||||
}
|
||||
|
||||
REGISTER_DAY(2021, Day21, std::vector<int>, int64_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day21, ExampleInput, 1, 739785);
|
||||
REGISTER_TEST(2021, Day21, Input, 1, 503478);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day21, ExampleInput, 2, 444356092776315);
|
||||
REGISTER_TEST(2021, Day21, Input, 2, 716241959649754);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::vector<int> players;
|
||||
int i;
|
||||
std::string str;
|
||||
while (getline(input, str))
|
||||
{
|
||||
std::stringstream ss{str};
|
||||
ss >> "Player" >> i >> "starting position:" >> i;
|
||||
players.emplace_back(i);
|
||||
}
|
||||
return players;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
std::vector<int> positions = input;
|
||||
std::vector<int> points;
|
||||
points.resize(input.size());
|
||||
for (int i = 1; i < 10000; i += 3)
|
||||
{
|
||||
int index = (i - 1) % 2;
|
||||
positions[index] = Mod(positions[index] + 3 * (i + 1));
|
||||
points[index] += positions[index];
|
||||
if (points[index] >= 1000)
|
||||
{
|
||||
return ((int64_t)i + 2ll) * (int64_t)points[(index + 1) % 2];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
std::pair<int64_t, int64_t> wins = Roll(input[0], 0, input[1], 0, true, 0);
|
||||
return std::max(wins.first, wins.second);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day22
|
||||
{
|
||||
|
||||
struct Overlap;
|
||||
|
||||
struct Volume
|
||||
{
|
||||
int sign = 0;
|
||||
Index3D min = Index3D{0, 0};
|
||||
Index3D max = Index3D{0, 0};
|
||||
|
||||
Volume()
|
||||
{
|
||||
}
|
||||
|
||||
Volume(int sign, const Index3D& min, const Index3D& max)
|
||||
: sign{sign},
|
||||
min{min},
|
||||
max{max}
|
||||
{
|
||||
}
|
||||
|
||||
int64_t GetCubes() const
|
||||
{
|
||||
return ((int64_t)max.x - (int64_t)min.x + 1ll) * ((int64_t)max.y - (int64_t)min.y + 1ll) *
|
||||
((int64_t)max.z - (int64_t)min.z + 1ll);
|
||||
}
|
||||
|
||||
Overlap GetOverlap(const Volume& other) const;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const Volume& volume)
|
||||
{
|
||||
return stream << volume.min << " " << volume.max;
|
||||
}
|
||||
};
|
||||
|
||||
struct Overlap
|
||||
{
|
||||
bool overlap = false;
|
||||
Volume volume;
|
||||
|
||||
Overlap(bool overlap, const Volume& volume)
|
||||
: overlap{overlap},
|
||||
volume{volume}
|
||||
{
|
||||
}
|
||||
|
||||
operator bool()
|
||||
{
|
||||
return overlap;
|
||||
}
|
||||
};
|
||||
|
||||
Overlap Volume::GetOverlap(const Volume& other) const
|
||||
{
|
||||
if (min.x > other.max.x || min.y > other.max.y || min.z > other.max.z || max.x < other.min.x ||
|
||||
max.y < other.min.y || max.z < other.min.z)
|
||||
return Overlap{false, Volume{0, Index3D{}, Index3D{}}};
|
||||
|
||||
return Overlap{
|
||||
true,
|
||||
Volume{-other.sign,
|
||||
Index3D{std::max(min.x, other.min.x), std::max(min.y, other.min.y), std::max(min.z, other.min.z)},
|
||||
Index3D{std::min(max.x, other.max.x), std::min(max.y, other.max.y), std::min(max.z, other.max.z)}}};
|
||||
}
|
||||
|
||||
REGISTER_DAY(2021, Day22, std::vector<Volume>, int64_t);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day22, ExampleInput, 1, 474140);
|
||||
REGISTER_TEST(2021, Day22, Input, 1, 596598);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day22, ExampleInput, 2, 2758514936282235);
|
||||
REGISTER_TEST(2021, Day22, Input, 2, 1199121349148621);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::vector<Volume> volumes;
|
||||
std::string str;
|
||||
while (getline(input, str))
|
||||
{
|
||||
Volume volume;
|
||||
std::stringstream ss{str};
|
||||
std::string s;
|
||||
ss >> s >> "x=" >> volume.min.x >> ".." >> volume.max.x >> "," >> "y=" >> volume.min.y >> ".." >> volume.max.y >>
|
||||
"," >> "z=" >> volume.min.z >> ".." >> volume.max.z;
|
||||
volume.sign = s == "on" ? 1 : -1;
|
||||
volumes.emplace_back(volume);
|
||||
}
|
||||
return volumes;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
Array3D<char> values{101, 101, 101};
|
||||
values.Fill('.');
|
||||
for (auto& region : input)
|
||||
{
|
||||
for (int z = std::max(region.min.z, -50); z <= std::min(region.max.z, 50); z++)
|
||||
{
|
||||
for (int y = std::max(region.min.y, -50); y <= std::min(region.max.y, 50); y++)
|
||||
{
|
||||
for (int x = std::max(region.min.x, -50); x <= std::min(region.max.x, 50); x++)
|
||||
{
|
||||
if (values.IsInside(Index3D{x + 50, y + 50, z + 50}))
|
||||
{
|
||||
values.Set(x + 50, y + 50, z + 50, region.sign > 0 ? '#' : '.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return values.Count('#');
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
std::vector<Volume> volumes;
|
||||
for (auto& volume : input)
|
||||
{
|
||||
size_t size = volumes.size();
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
Overlap overlap = volume.GetOverlap(volumes[i]);
|
||||
if (overlap)
|
||||
{
|
||||
volumes.emplace_back(overlap.volume);
|
||||
}
|
||||
}
|
||||
if (volume.sign > 0)
|
||||
{
|
||||
volumes.emplace_back(volume);
|
||||
}
|
||||
}
|
||||
return Helper::Sum<int64_t>(volumes,
|
||||
[](int64_t sum, const Volume& vol) { return sum + vol.GetCubes() * vol.sign; });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day23
|
||||
{
|
||||
|
||||
using State = std::map<Index2D, char>;
|
||||
|
||||
bool Find(const State& state, const Index2D& pos, char c)
|
||||
{
|
||||
auto it = state.find(pos);
|
||||
if (it != state.end())
|
||||
return it->second == c;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ValidateState(int height, const State& state)
|
||||
{
|
||||
return Find(state, {2, 1}, 'A') && Find(state, {2, 2}, 'A') && Find(state, {4, 1}, 'B') &&
|
||||
Find(state, {4, 2}, 'B') && Find(state, {6, 1}, 'C') && Find(state, {6, 2}, 'C') &&
|
||||
Find(state, {8, 1}, 'D') && Find(state, {8, 2}, 'D');
|
||||
}
|
||||
|
||||
int Heuristic(int height, const State& state)
|
||||
{
|
||||
int h = 0;
|
||||
for (auto& piece : state)
|
||||
{
|
||||
// Cost to move piece to the top of the room
|
||||
if (piece.second == 'A' && piece.first.x != 2)
|
||||
h += std::abs(piece.first.x - 2) + std::abs(piece.first.y - 0) + 1;
|
||||
if (piece.second == 'B' && piece.first.x != 4)
|
||||
h += (std::abs(piece.first.x - 4) + std::abs(piece.first.y - 0) + 1) * 10;
|
||||
if (piece.second == 'C' && piece.first.x != 6)
|
||||
h += (std::abs(piece.first.x - 6) + std::abs(piece.first.y - 0) + 1) * 100;
|
||||
if (piece.second == 'D' && piece.first.x != 8)
|
||||
h += (std::abs(piece.first.x - 8) + std::abs(piece.first.y - 0) + 1) * 1000;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
int GetCost(char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'A':
|
||||
return 1;
|
||||
case 'B':
|
||||
return 10;
|
||||
case 'C':
|
||||
return 100;
|
||||
case 'D':
|
||||
return 1000;
|
||||
}
|
||||
std::cout << "Invalid char: " << c << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, State>> ValidStates(int height, const State& state)
|
||||
{
|
||||
std::vector<std::pair<int, State>> newStates;
|
||||
for (auto& piece : state)
|
||||
{
|
||||
if (piece.first.y > 0)
|
||||
{ // Piece is in the room, move to hallway
|
||||
|
||||
// Check if already at correct position
|
||||
bool canMove = false;
|
||||
if (piece.first.x == (piece.second - 'A') * 2 + 2)
|
||||
{
|
||||
for (int i = piece.first.y + 1; i < 1 + height; i++)
|
||||
{
|
||||
if (state.find({piece.first.x, i})->second != piece.second)
|
||||
{
|
||||
canMove = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
canMove = true;
|
||||
|
||||
// Check if piece is obstructed by others in the room
|
||||
for (int i = piece.first.y - 1; i > 0; i--)
|
||||
{
|
||||
if (state.count({piece.first.x, i}) != 0)
|
||||
{
|
||||
canMove = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (canMove)
|
||||
{
|
||||
// Check hallways to the left
|
||||
for (int i = piece.first.x - 1; i >= 0; i--)
|
||||
{
|
||||
// Is valid position in hallway
|
||||
if (i == 0 || i % 2 == 1 || i == 10)
|
||||
{
|
||||
if (state.count({i, 0}) == 0)
|
||||
{
|
||||
State newState = state;
|
||||
newState[{i, 0}] = piece.second;
|
||||
newState.erase(piece.first);
|
||||
newStates.emplace_back(std::pair<int, State>{
|
||||
(piece.first.y + std::abs(piece.first.x - i)) * GetCost(piece.second), newState});
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check hallways to the right
|
||||
for (int i = piece.first.x + 1; i < 11; i++)
|
||||
{
|
||||
// Is valid position in hallway
|
||||
if (i == 0 || i % 2 == 1 || i == 10)
|
||||
{
|
||||
if (state.count({i, 0}) == 0)
|
||||
{
|
||||
State newState = state;
|
||||
newState[{i, 0}] = piece.second;
|
||||
newState.erase(piece.first);
|
||||
newStates.emplace_back(std::pair<int, State>{
|
||||
(piece.first.y + std::abs(piece.first.x - i)) * GetCost(piece.second), newState});
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // Piece is in the hallway, move to room
|
||||
|
||||
int x = (piece.second - 'A') * 2 + 2;
|
||||
int dir = Helper::Sign(x - piece.first.x);
|
||||
bool canMove = true;
|
||||
|
||||
// Check if hallway is clear to correct position
|
||||
for (int i = piece.first.x + dir; (dir < 0 && i > x) || (dir > 0 && i < x); i += dir)
|
||||
{
|
||||
if (state.count({i, 0}) != 0)
|
||||
{
|
||||
canMove = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (canMove)
|
||||
{
|
||||
// Check if room is filled with same piece or no pieces
|
||||
int pos = height;
|
||||
for (int i = 1; i < 1 + height; i++)
|
||||
{
|
||||
if (state.count({x, i}) != 0)
|
||||
{
|
||||
if (state.find({x, i})->second == piece.second)
|
||||
{
|
||||
if (pos == height)
|
||||
pos = i - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pos != 0)
|
||||
{
|
||||
State newState = state;
|
||||
newState[{x, pos}] = piece.second;
|
||||
newState.erase(piece.first);
|
||||
newStates.emplace_back(
|
||||
std::pair<int, State>{(pos + std::abs(piece.first.x - x)) * GetCost(piece.second), newState});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return newStates;
|
||||
}
|
||||
|
||||
int Solve(const State& state, int h)
|
||||
{
|
||||
return Helper::AStar(h, state, Heuristic, ValidStates, ValidateState);
|
||||
}
|
||||
|
||||
REGISTER_DAY(2021, Day23, State, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day23, ExampleInput, 1, 12521);
|
||||
REGISTER_TEST(2021, Day23, Input, 1, 14350);
|
||||
REGISTER_TEST_EXAMPLE(2021, Day23, ExampleInput, 2, 44169);
|
||||
REGISTER_TEST(2021, Day23, Input, 2, 49742);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::string str;
|
||||
getline(input, str);
|
||||
getline(input, str);
|
||||
getline(input, str);
|
||||
std::map<Index2D, char> state;
|
||||
state.emplace(Index2D{2, 1}, str[3]);
|
||||
state.emplace(Index2D{4, 1}, str[5]);
|
||||
state.emplace(Index2D{6, 1}, str[7]);
|
||||
state.emplace(Index2D{8, 1}, str[9]);
|
||||
|
||||
getline(input, str);
|
||||
state.emplace(Index2D{2, 2}, str[3]);
|
||||
state.emplace(Index2D{4, 2}, str[5]);
|
||||
state.emplace(Index2D{6, 2}, str[7]);
|
||||
state.emplace(Index2D{8, 2}, str[9]);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
return Solve(input, 2);
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
State state;
|
||||
for (auto& piece : input)
|
||||
{
|
||||
if (piece.first.y == 2)
|
||||
state.emplace(Index2D{piece.first.x, 4}, piece.second);
|
||||
else
|
||||
state.emplace(piece.first, piece.second);
|
||||
}
|
||||
state.emplace(Index2D{2, 2}, 'D');
|
||||
state.emplace(Index2D{2, 3}, 'D');
|
||||
state.emplace(Index2D{4, 2}, 'C');
|
||||
state.emplace(Index2D{4, 3}, 'B');
|
||||
state.emplace(Index2D{6, 2}, 'B');
|
||||
state.emplace(Index2D{6, 3}, 'A');
|
||||
state.emplace(Index2D{8, 2}, 'A');
|
||||
state.emplace(Index2D{8, 3}, 'C');
|
||||
|
||||
return Solve(state, 4);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day24
|
||||
{
|
||||
|
||||
enum class Operation
|
||||
{
|
||||
Inp,
|
||||
Add,
|
||||
Mul,
|
||||
Div,
|
||||
Mod,
|
||||
Eql
|
||||
};
|
||||
|
||||
struct Instruction
|
||||
{
|
||||
Operation operation;
|
||||
char dst;
|
||||
std::string src;
|
||||
};
|
||||
|
||||
int64_t Read(const std::string& str, const std::map<char, int64_t>& data)
|
||||
{
|
||||
if (str[0] >= 'a' && str[0] <= 'z')
|
||||
{
|
||||
auto it = data.find(str[0]);
|
||||
if (it != data.end())
|
||||
return it->second;
|
||||
return 0;
|
||||
}
|
||||
return atoll(str.c_str());
|
||||
};
|
||||
|
||||
int64_t Read(char c, const std::map<char, int64_t>& data)
|
||||
{
|
||||
auto it = data.find(c);
|
||||
if (it != data.end())
|
||||
return it->second;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ValidateInput(const std::vector<Instruction>& instructions, const std::string& str)
|
||||
{
|
||||
int inputOffset = 0;
|
||||
std::map<char, int64_t> data;
|
||||
for (int i = 0; i < instructions.size(); i++)
|
||||
{
|
||||
switch (instructions[i].operation)
|
||||
{
|
||||
case Operation::Inp:
|
||||
data[instructions[i].dst] = str[inputOffset++] - '0';
|
||||
break;
|
||||
case Operation::Add:
|
||||
data[instructions[i].dst] = Read(instructions[i].dst, data) + Read(instructions[i].src, data);
|
||||
break;
|
||||
case Operation::Mul:
|
||||
data[instructions[i].dst] = Read(instructions[i].dst, data) * Read(instructions[i].src, data);
|
||||
break;
|
||||
case Operation::Div:
|
||||
data[instructions[i].dst] = Read(instructions[i].dst, data) / Read(instructions[i].src, data);
|
||||
break;
|
||||
case Operation::Mod:
|
||||
data[instructions[i].dst] = Read(instructions[i].dst, data) % Read(instructions[i].src, data);
|
||||
break;
|
||||
case Operation::Eql:
|
||||
data[instructions[i].dst] = Read(instructions[i].dst, data) == Read(instructions[i].src, data) ? 1 : 0;
|
||||
break;
|
||||
default:
|
||||
std::cout << "Invalid operation" << std::endl;
|
||||
}
|
||||
}
|
||||
return data['z'] == 0;
|
||||
}
|
||||
|
||||
REGISTER_DAY(2021, Day24, std::vector<Instruction>, int64_t);
|
||||
|
||||
REGISTER_TEST(2021, Day24, Input, 1, 99919765949498);
|
||||
REGISTER_TEST(2021, Day24, Input, 2, 24913111616151);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
std::vector<Instruction> instructions;
|
||||
std::string str;
|
||||
while (getline(input, str))
|
||||
{
|
||||
Instruction instruction;
|
||||
std::string_view sv(str.c_str(), 3);
|
||||
if (sv == "inp")
|
||||
instruction.operation = Operation::Inp;
|
||||
else if (sv == "add")
|
||||
instruction.operation = Operation::Add;
|
||||
else if (sv == "mul")
|
||||
instruction.operation = Operation::Mul;
|
||||
else if (sv == "div")
|
||||
instruction.operation = Operation::Div;
|
||||
else if (sv == "mod")
|
||||
instruction.operation = Operation::Mod;
|
||||
else if (sv == "eql")
|
||||
instruction.operation = Operation::Eql;
|
||||
else
|
||||
std::cout << "Invalid operation: " << sv << std::endl;
|
||||
instruction.dst = str[4];
|
||||
if (instruction.operation != Operation::Inp)
|
||||
instruction.src = str.substr(6);
|
||||
instructions.emplace_back(instruction);
|
||||
}
|
||||
return instructions;
|
||||
}
|
||||
|
||||
OUTPUT1(input)
|
||||
{
|
||||
std::string str = "99919765949498";
|
||||
if (ValidateInput(input, str))
|
||||
return atoll(str.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
std::string str = "24913111616151";
|
||||
if (ValidateInput(input, str))
|
||||
return atoll(str.c_str());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
#include "common/aoc.h"
|
||||
|
||||
namespace y2021::day25
|
||||
{
|
||||
REGISTER_DAY(2021, Day25, Array2D<char>, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2021, Day25, ExampleInput, 1, 58);
|
||||
REGISTER_TEST(2021, Day25, Input, 1, 419);
|
||||
|
||||
READ_INPUT(input)
|
||||
{
|
||||
return Input::ReadArray2D(input);
|
||||
}
|
||||
|
||||
OUTPUT1(inputConst)
|
||||
{
|
||||
Array2D<char> input = inputConst;
|
||||
bool hasMoved = true;
|
||||
int i = 0;
|
||||
while (hasMoved)
|
||||
{
|
||||
hasMoved = false;
|
||||
Array2D<char> cpy = input;
|
||||
Index2D index{0, 0};
|
||||
for (auto& c : cpy)
|
||||
{
|
||||
if (c == '>')
|
||||
{
|
||||
Index2D newIndex = index;
|
||||
newIndex.x = (newIndex.x + 1) % cpy.width;
|
||||
if (cpy[newIndex] == '.')
|
||||
{
|
||||
input[newIndex] = '>';
|
||||
input[index] = '.';
|
||||
hasMoved = true;
|
||||
}
|
||||
}
|
||||
cpy.Increment(index);
|
||||
}
|
||||
cpy = input;
|
||||
index = {0, 0};
|
||||
for (auto& c : cpy)
|
||||
{
|
||||
if (c == 'v')
|
||||
{
|
||||
Index2D newIndex = index;
|
||||
newIndex.y = (newIndex.y + 1) % cpy.height;
|
||||
if (cpy[newIndex] == '.')
|
||||
{
|
||||
input[newIndex] = 'v';
|
||||
input[index] = '.';
|
||||
hasMoved = true;
|
||||
}
|
||||
}
|
||||
cpy.Increment(index);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
OUTPUT2(input)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user