Unable to load image

day 17 aoc thread: rocks fall everyone dies

bottom text

42
Jump in the discussion.

No email address required.

Kinda liked the doing the tetris game as a bitmap.

Part two is super jank and honestly shocked me that it actually worked.


#include <iostream>
#include <array>
#include <vector>
#include <bitset>
#include <queue>
#include <algorithm>
#include <map>

typedef std::array<uint8_t, 4> block_type;
typedef uint16_t row_type;

class rock_type {
public:
    int height;
    std::vector<row_type> rock;
    std::pair<int, int> space;
    rock_type(int h, std::vector<row_type> r, std::pair<int, int> s) {
        height = h;
        rock = r;
        space = s;
    }
    void move_rock(bool left) {
        //std::cout << "MAKING MOVE: " << (left ? "LEFT" : "RIGHT") << '\n';
        if (left && space.first == 0) return;
        if (!left && space.second == 0) return;

        for (auto& row : rock) {
            if (left) row = row << 1;
            else row = row >> 1;
        }
        if (left) {
            space.first -= 1;
            space.second += 1;
        }
        else {
            space.first += 1;
            space.second -= 1;
        }
    }
};

class circular_queue {
public:
    std::string order;
    size_t location;

    circular_queue(std::string o) {
        order = o;
        location = 0;
    }

    circular_queue() {
        order = "";
        location = 0;
    }

    bool get() {
        bool out = order[location] == '<';
        location++;
        if (location >= order.size()) location = 0;
        return out;
    }
};

rock_type line_hor{ 1, {{0b000111100}} , {2, 1} };
rock_type cross{ 3, {{0b000010000},
                     {0b000111000},
                     {0b000010000}} , {2, 2} };
rock_type reverse_L{ 3, {{0b000111000},
                         {0b000001000},
                         {0b000001000}} , {2, 2} };
rock_type line_vert{ 4, {{0b000100000},
                        {0b000100000},
                        {0b000100000},
                        {0b000100000}} , {2, 4} };
rock_type square{ 2, {{0b000110000},
                      {0b000110000}} , {2, 3} };

const std::array<rock_type, 5> rock_order = { line_hor, cross, reverse_L, line_vert, square };

class game_area {
private:
    static const row_type empty{ 0b100000001 };
    static const row_type start{ 0b111111111 };
public:
    std::vector<row_type> field;
    int last_rock = 1; 
    circular_queue move_order;

    void add_row(row_type row) {
        field.emplace_back(row);
    }
    void add_row() {
        field.push_back(game_area::empty);
    }
    game_area() {}

    game_area(circular_queue move_order) {
        this->move_order = move_order;
        add_row(game_area::start);
    }

    void place_rock(size_t row, rock_type rock) {
        last_rock = std::max(last_rock, (int)row + rock.height);
        for (size_t i{ 0 }; i < rock.height; ++i) {
            field[row + i] = field[row + i] | rock.rock[i];
        }
    }
    
    void remove_rock(size_t row, rock_type rock) {
        last_rock = std::max(last_rock, (int)row - rock.height);
        for (size_t i{ 0 }; i < rock.height; ++i) {
            field[row + i] = field[row + i] ^ rock.rock[i];
        }
    }
    void expand_field(rock_type rock) {
        while (field.size() - last_rock - 3 - rock.height > 0) add_row();
    }

    bool make_move(rock_type& rock) {
        bool left = move_order.get();
        rock.mp4e_rock(left);
        return left;
    }

    void draw_temp(size_t curr_row, rock_type rock) {
        place_rock(curr_row, rock);
        std::clog << *this << '\n';
        remove_rock(curr_row, rock);
    }

    void add_rock(rock_type rock, bool debug = false) {
        expand_field(rock);
        size_t curr_row = field.size() - rock.height;
        //make_move(rock);
        if (debug) 
            draw_temp(curr_row, rock);
        while (true) {
            bool left = make_move(rock);
            if (!can_place(curr_row, rock)) rock.mp4e_rock(!left);
            if (debug) draw_temp(curr_row, rock);
            --curr_row;
            if (!can_place(curr_row, rock)) break;
        };
        ++curr_row;
        //if (debug) draw_temp(curr_row, rock);
        place_rock(curr_row, rock);
        field.resize(last_rock);
    }

    bool can_place(size_t row, rock_type rock) {
        for (size_t i = 0; i < rock.height; i++) {
            if((field[row + i] & rock.rock[i]) > 0) return false;
        }
        return true;
    }

    friend std::ostream& operator<<(std::ostream& os, game_area game) {
        for (auto it = game.field.rbegin(); it != game.field.rend() - 1; it++) {
            std::bitset<9> a(*it);
            for (size_t i{ 0 }; i < a.size(); i++) {
                if (i == 0 || i == a.size() - 1) os << "|";
                else if (a[a.size() - i - 1] == 1) os << "#";
                else os << ".";
            }
            os << '\n';
        }
        os << "+-------+\n";
        return os;
    }
};

int main()
{
    {
        circular_queue move_order{ "input" };
        game_area game(move_order);
        std::map<std::tuple<int, int, int>, std::pair<int, int>> states;
        int count = 0;
        int gain, circle;
        int last_height = 0;
        int i{ 0 };
        for (; true; ++i) {
            if (i == 2022) std::clog << "Part One: " << game.last_rock - 1 << std::endl;
            game.add_rock(rock_order[i % 5]);
            auto key = std::make_tuple(game.field.back(), game.mp4e_order.location, i % 5);
            if (states.contains(key)) {
                if (count > 100) {
                    gain = game.last_rock - states[key].first;
                    circle = i - states[key].second;
                    break;
                }
                count++;
            }
            states[key] = { game.last_rock, i };
        }

        int64_t test = (1'000'000'000'000LL - i) / circle * gain;
        int64_t mod = (1'000'000'000'000LL - i) % circle;

        for (size_t j{ 0 }; j < mod; ++j) {
            game.add_rock(rock_order[(i+j) % 5]);
        }
        std::clog << "Part Two: " << test + game.last_rock - 1 << std::endl;
    }

}

Jump in the discussion.

No email address required.

Your pulitzer's in the mail

Jump in the discussion.

No email address required.

Link copied to clipboard
Action successful!
Error, please refresh the page and try again.