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.



Now playing: Gang-Plank Galleon (DKC).mp3

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