banan-os/userspace/aoc2023/day22/main.cpp

192 lines
3.8 KiB
C++

#include <BAN/HashSet.h>
#include <BAN/Sort.h>
#include <BAN/Vector.h>
#include <ctype.h>
#include <inttypes.h>
#include <stdio.h>
using i8 = int8_t;
using i16 = int16_t;
using i32 = int32_t;
using i64 = int64_t;
using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
struct Position
{
i64 x, y, z;
bool operator==(const Position& other) const
{
return x == other.x && y == other.y && z == other.z;
}
};
static constexpr bool rectangle_contains(const Position& c1, const Position& c2, const Position& p)
{
ASSERT(c1.x <= c2.x);
ASSERT(c1.y <= c2.y);
return (c1.x <= p.x && p.x <= c2.x) && (c1.y <= p.y && p.y <= c2.y);
}
struct Brick
{
Position corners[2];
BAN::HashSet<Brick*> supporting;
BAN::HashSet<Brick*> supported_by;
bool supports(const Brick& other) const
{
if (corners[1].z + 1 != other.corners[0].z)
return false;
for (i32 i = 0; i < 4; i++)
if (rectangle_contains(corners[0], corners[1], { other.corners[i / 2].x, other.corners[i % 2].y, 0 }))
return true;
for (i32 i = 0; i < 4; i++)
if (rectangle_contains(other.corners[0], other.corners[1], { corners[i / 2].x, corners[i % 2].y, 0 }))
return true;
return false;
}
};
i64 parse_i64(BAN::StringView str)
{
i64 result = 0;
for (char c : str)
{
ASSERT(isdigit(c));
result = (result * 10) + (c - '0');
}
return result;
}
BAN::Vector<Brick> parse_bricks(FILE* fp)
{
BAN::Vector<Brick> bricks;
char buffer[64];
while (fgets(buffer, sizeof(buffer), fp))
{
BAN::StringView line(buffer);
ASSERT(line.back() == '\n');
line = line.substring(0, line.size() - 1);
if (line.empty())
break;
auto corner_strs = MUST(line.split('~'));
ASSERT(corner_strs.size() == 2);
Brick brick;
for (i32 i = 0; i < 2; i++)
{
auto coords = MUST(corner_strs[i].split(','));
ASSERT(coords.size() == 3);
brick.corners[i].x = parse_i64(coords[0]);
brick.corners[i].y = parse_i64(coords[1]);
brick.corners[i].z = parse_i64(coords[2]);
}
ASSERT(brick.corners[0].x <= brick.corners[1].x);
ASSERT(brick.corners[0].y <= brick.corners[1].y);
ASSERT(brick.corners[0].z <= brick.corners[1].z);
MUST(bricks.push_back(brick));
}
return bricks;
}
i64 puzzle1(FILE* fp)
{
auto brick_comp = [](const Brick& b1, const Brick& b2) { return b1.corners[0].z < b2.corners[0].z; };
auto bricks = parse_bricks(fp);
BAN::sort::sort(bricks.begin(), bricks.end(), brick_comp);
// Simulate brick falling
for (size_t i = 0; i < bricks.size();)
{
bool can_fall = bricks[i].corners[0].z > 1;
for (size_t j = 0; j < i && can_fall; j++)
if (bricks[j].supports(bricks[i]))
can_fall = false;
if (!can_fall)
i++;
else
{
bricks[i].corners[0].z--;
bricks[i].corners[1].z--;
for (; i > 0; i--)
{
if (brick_comp(bricks[i - 1], bricks[i]))
break;
BAN::swap(bricks[i - 1], bricks[i]);
}
}
}
// Store brick supporting structures
for (size_t i = 0; i < bricks.size(); i++)
{
for (size_t j = 0; j < bricks.size(); j++)
{
if (i == j)
continue;
if (bricks[i].supports(bricks[j]))
{
MUST(bricks[i].supporting.insert(&bricks[j]));
MUST(bricks[j].supported_by.insert(&bricks[i]));
}
}
}
i64 result = 0;
for (const auto& brick : bricks)
{
bool disintegratable = true;
for (const auto* support : brick.supporting)
if (support->supported_by.size() <= 1)
disintegratable = false;
result += disintegratable;
}
// OFF BY 7
return result;
}
i64 puzzle2(FILE* fp)
{
(void)fp;
return -1;
}
int main(int argc, char** argv)
{
const char* file_path = "/usr/share/aoc2023/day22_input.txt";
if (argc >= 2)
file_path = argv[1];
FILE* fp = fopen(file_path, "r");
if (fp == nullptr)
{
perror("fopen");
return 1;
}
printf("puzzle1: %" PRId64 "\n", puzzle1(fp));
fseek(fp, 0, SEEK_SET);
printf("puzzle2: %" PRId64 "\n", puzzle2(fp));
fclose(fp);
}