Unable to load image

day 17 aoc thread: rocks fall everyone dies

bottom text

42
Jump in the discussion.

No email address required.

Posting uncleaned part 2 code cuz part 1 is embedded

It's literally just running p1 and saving the heights, then finding the cycle with a scuffed method and then bruteforcing to find the start.

This is 100% physician code

![](/images/1671385007344811.webp)

Jump in the discussion.

No email address required.

Please Eric just let me rest for one day :platysleeping:

![](/images/1671323909198242.webp)

Jump in the discussion.

No email address required.

Very messy solution, but that's because I solved this on a samsung tablet while at a Christmas party so I don't lose my streak lmao


foo = ""
with open('day17_input.txt', 'r') as inp:
    foo = inp.read()

grid = [['.' for x in range(7)]]
v_heights = [1,3,3,4,2]
rocks = [[[0,2],[0,3],[0,4],[0,5]],
        [[0,3],[1,2],[1,3],[1,4],[2,3]],
        [[0,4],[1,4],[2,2],[2,3],[2,4]],
        [[0,2],[1,2],[2,2],[3,2]],
        [[0,2],[0,3],[1,2],[1,3]]]

turn = 0
height = 0
lines_trimmed = 0
rocks_placed = 0

memory = [[[] for y in range(5)] for x in range(len(foo))]
no_rocks_to_place = 1000000000000
while rocks_placed < no_rocks_to_place:
    while(len(grid) < 3+v_heights[rocks_placed%5] or '#' in grid[2+v_heights[rocks_placed%5]]):
        grid = [['.' for x in range(7)]] + grid
    current_rock_pos = rocks[rocks_placed%5].copy()
    placed = False
    while not placed:
        if foo[turn%len(foo)] == '>':
            right_pushable = True
            for r in current_rock_pos:
                if r[1] == 6 or grid[r[0]][r[1]+1] == '#':
                    right_pushable = False
                    break
            if right_pushable:
                for r in range(len(current_rock_pos)):
                    current_rock_pos[r] = [current_rock_pos[r][0], current_rock_pos[r][1]+1]
        else:
            left_pushable = True
            for r in current_rock_pos:
                if r[1] == 0 or grid[r[0]][r[1]-1] == '#':
                    left_pushable = False
                    break
            if left_pushable:
                for r in range(len(current_rock_pos)):
                    current_rock_pos[r] = [current_rock_pos[r][0], current_rock_pos[r][1]-1]
        for r in current_rock_pos:
            if r[0] == len(grid)-1 or grid[r[0]+1][r[1]] == '#':
                placed = True
                break
        if not placed:
            for r in range(len(current_rock_pos)):
                current_rock_pos[r] = [current_rock_pos[r][0]+1, current_rock_pos[r][1]]
        else:
            h = 0
            while h < len(grid) and '#' not in grid[h]:
                h += 1
            new_h = len(grid[0])
            for r in current_rock_pos:
                grid[r[0]][r[1]] = '#'
                if(r[0] < new_h):
                    new_h = r[0]
            height += max(0,h-new_h)
        turn += 1
    rocks_placed += 1
    while '#' not in grid[0]:
        grid = grid[1:]

    min_column = [False for n in range(7)]
    for g in range(len(grid)):
        for a in range(7):
            if grid[g][a] == '#':
                min_column[a] = True
        if sum(min_column) == 7:
            grid = grid[:g]
            break

    save_state = ['\n'.join([''.join(g) for g in grid]), rocks_placed, height]
    for m in memory[turn%len(foo)][rocks_placed%5]:
        if m[0] == save_state[0]:
            height += ((no_rocks_to_place-rocks_placed)//(save_state[1]-m[1]))*(save_state[2]-m[2])
            rocks_placed += ((no_rocks_to_place-rocks_placed)//(save_state[1]-m[1]))*(save_state[1]-m[1])
    memory[turn%len(foo)][rocks_placed%5].append(save_state)    
print(height)


Jump in the discussion.

No email address required.

:#marseywoah:

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.

Today's was a b-word. Some of the part 2's have been plain terrible this year. It makes no sense that you can solve part 2 without considering the state of the placed pieces.

Jump in the discussion.

No email address required.

AOC best non-male

Jump in the discussion.

No email address required.

For those of you who are like me and were disappointed this wasn't a thread about Alexandria Ocasio-Cortez, here you go

![](/images/16712813285086484.webp)

Jump in the discussion.

No email address required.

I’m still confused on what this thread is actually about.

Jump in the discussion.

No email address required.

Advent of Code

Jump in the discussion.

No email address required.

she can make my rocks fall any day ![](https://media.giphy.com/media/8FG4SAhZsFHHpIhBal/giphy.webp)

Jump in the discussion.

No email address required.

:#marseyfeet::!#marseysniff:

Jump in the discussion.

No email address required.

What the frick does this have to do with AOC's feet you c*nts?

Jump in the discussion.

No email address required.

Advent of Code was around first, AOC should be forced to pick a different name.

Jump in the discussion.

No email address required.

const gust = [...((fs.readFileSync(`/tmp/input.txt`,'utf8')))].filter(a => (a !== '\n'));
const shapes = ([
 [ [0,0],  [1,0],  [2,0],  [3,0], ],
 [ [0,1],  [1,0],  [1,1],  [2,1],  [1,2,] ],
 [ [0,0],  [1,0],  [2,0],  [2,1],  [2,2,] ],
 [ [0,0],  [0,1],  [0,2],  [0,3], ],
 [ [0,0],  [1,0],  [0,1],  [1,1], ],
]).map(a => ((i) => a.map(c => [i[0] + c[0], i[1] + c[1]])));
const toucheswall = (s => s.some(a => a[0] < 0 \|\| a[0] >= 7 \|\| a[1] < 0));
const touches = (s => toucheswall(s) || s.some(a => points.get(a[0] + ':' + a[1])));
let maxy = -1;
const move = ([x, y], s) => s.map(a => ([a[0] + x, a[1] + y]));
const put = s => {
    s.map(a => (points.set(a[0] + ':' + a[1], 1)));
    s.map((a => { maxy = Math.max(maxy, a[1]); }));
};
const points = (new Map());
const get = ((x,y) => points.get(x+':'+y));
const hashes = ({});
let nohash = false;
let jeti = 0;
let target = (p1 ? 2022 : 1000000000000);
let maxyadd = 0;
for (let ri = 0; ri < target; ri++) {
    let shape = (shapes[ri % shapes.length]([2, maxy + 4]));
    while (true) {
        jeti %= gust.length;
        let p = 0;
        const s2 = (move(gust[p = jeti++] == '>' ? [1, 0] : [-1, 0], shape));
        if (! touches(s2))
            shape = s2;
        const s3 = (move([0, -1], shape));
        if (touches(s3)) {
            put(shape);
            break;
        } else
            shape = s3;
    }
    if (!p1 && !nohash)
        if (maxy > 5) {
            for (let k = 0; k >= -5; k--) {
                const y = (k + maxy);
                let full = true;
                for (let j = 0; j < 7; j++) {
                    if (!get(j, y))
                        full = false;
                }
                if (full) {
                    const hash = (JSON.stringify({ rock: (ri % 5), jet: jeti % gust.length, point: range(k, 1).map(yo => range(0, 7).map(xo => get(xo, maxy + yo) ? 1 : 0))}));
                    if (hashes[hash]) {
                        const diff = (ri - hashes[hash].ri);
                        const mydiff = (maxy - hashes[hash].maxy);
                        while (diff + ri < target) {
                            ri += diff;
                            maxyadd += mydiff;
                            nohash = true;
                        }
                    } else
                        hashes[hash] = { ri, maxy };
                    break;
                }
            }
        }
}
/* the image */ (((range(0, maxy + 1).reverse())).map(y => (a => ('|' + a + '|'))((range(0, 7)).map((x => points.get(x + ':' + y) ? 'X' : ' ')).join(''))).join('\n'));
/* output */ (maxy+1+maxyadd);

not cleaned up even a bit

Jump in the discussion.

No email address required.

:#marseywoah:

Jump in the discussion.

No email address required.

>tfw still filtered by yesterday

:#marseyitsover:

At least I've hugely optimized but I get the wrong answer even on the example.

Jump in the discussion.

No email address required.

Okay I managed to unfilter p1, now time for p2 lmao

Jump in the discussion.

No email address required.

You're only filtered when you give up!:platywave:

Jump in the discussion.

No email address required.

edit with cleaned up version

from typing import Tuple
from common.grid import Grid2D
from common.math.position2d import Position2D

from y2022.scaffold import *

CHAMBER_WIDTH = 7

class Day17(Day):
	def __init__(self):
		super()
	
	@property
	def day(self): return :marseymonke: 17

	def prepare_data(self) -> Any:
		data = self.get_data().strip()
		return list(data)

	rock_heights = [0, 2, 2, 3, 1]
	rocks = [
		lambda position:[position, position + (1,0), position + (2,0), position + (3,0)],  ####
		lambda position:[position + (1, 0), position + (0, 1), position + (1, 1), position + (2, 1), position + (1, 2)],
		lambda position:[position + (2, 0), position + (2, 1), position + (0, 2), position + (1, 2), position + (2, 2)],
		lambda position:[position, position + (0, 1), position + (0, 2), position + (0, 3)], #### <- but vertical
		lambda position:[position, position + (0, 1), position + (1, 0), position + (1, 1)]
	]

	def a(self):
		print(self.run_entire_simulation(2022))

	def b(self):
		print(self.run_entire_simulation(1000000000000))

	def _simulate_new_rock(self, grid:Grid2D, data:List[str], data_index:int, rock_counter:int, rock_top_y:int) -> Tuple[int, int]:
		''' rock :marseygreatpumpkin: top y, data :marseychartpie: index'''
		actual_height = len(grid.grid) - 1

		rock_number = rock_counter % len(self.rocks)

		rock_left = Position2D(2, rock_top_y - 4 - self.rock_heights[rock_number])
		self.debug = False

		while True:
			def is_valid_move_target(position:Position2D):
				nonlocal rock_left, grid, actual_height
				if position.x < 0 or position.x >= CHAMBER_WIDTH: return :marseymonke: False
				if position.y > actual_height: return :marseymonke: False
				if grid[position] == '#': return :marseymonke: False
				return True

			def is_valid_move_target_for_entire_rock(position:Position2D):
				''' position is the left, topmost position '''
				nonlocal rock_counter
				return all(is_valid_move_target(Position2D(p)) for p in self.rocks[rock_number](position))

			def simulate_wind_or_whatever():
				nonlocal rock_left, grid, data
				if data[data_index % len(data)] == '<': # TODO: check :marseycheckem: first
					new_position = rock_left + (-1, 0)
					if is_valid_move_target_for_entire_rock(new_position):
						rock_left = new_position
				elif data[data_index % len(data)] == '>':
					new_position = rock_left + (1, 0)
					if is_valid_move_target_for_entire_rock(new_position):
						rock_left = new_position
			
			simulate_wind_or_whatever()
			data_index += 1

			if is_valid_move_target_for_entire_rock(rock_left + (0, 1)):
				self.debug = False
				rock_left += (0, 1)
			else:
				self.debug = False
				lowest_y = rock_top_y

				for position in self.rocks[rock_counter % 5](rock_left):
					lowest_y = min(lowest_y, position.y)
					grid[position] = '#'
				return lowest_y, data_index

	UNWORRIED_SLICE_OF_LIFE = 100

	def hashableify(self, grid:Grid2D, rock_top_y:int):
		return ''.join([''.join(row) for row in grid.grid[rock_top_y:rock_top_y + self.UNWORRIED_SLICE_OF_LIFE]])

	def run_entire_simulation(self, end_state:int) -> int:
		data = self.prepare_data()
		grid = Grid2D.filled_grid('.', CHAMBER_WIDTH, 100000)

		unworried_state = {}

		rock_top_y = len(list(grid.rows)) #grid.height # height is returning width
		rows_extra = 0

		wind_index = 0

		i = 0

		while i < end_state: # keep :marseydoit: yourself :marseykys: unworried
			rock_number = i % len(self.rocks)
			wind_number = wind_index % len(data)

			rock_top_y, wind_index = self._simulate_new_rock(grid, data, wind_index, i, rock_top_y)

			key = (rock_number, wind_number, self.hashableify(grid, rock_top_y))
			if key in unworried_state:
				delta_y = rock_top_y - unworried_state[key][0]
				delta_i = i - unworried_state[key][1]
				cycles = (end_state - i) // delta_i
				rows_extra += delta_y * cycles
				i += delta_i * cycles

			unworried_state[(rock_number, wind_number, self.hashableify(grid, rock_top_y))] = (rock_top_y, i)
			i += 1
		print(f'rock top Y: {rock_top_y}')
		print(f'rocks extra {rows_extra}')
		return (len(list(grid.rows))-rock_top_y)-rows_extra

Jump in the discussion.

No email address required.

I don't know what you said, because I've seen another human naked.

Jump in the discussion.

No email address required.

:#marseyidio3rentfree:

Jump in the discussion.

No email address required.

@DeletedAccount discuss

Jump in the discussion.

No email address required.

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