view 2022/17/17.jl @ 64:c9010e9a5257

Day 12 Part 2 Add memoization implementation for count function
author Lewin Bormann <lbo@spheniscida.de>
date Sat, 23 Dec 2023 15:13:15 +0100
parents 05ddc45b4210
children
line wrap: on
line source

using StaticArrays;

const test_input = "test_input.txt";

const rocks = Vector{Matrix{Int}}([[1 1 1 1], [0 1 0; 1 1 1; 0 1 0], [0 0 1; 0 0 1; 1 1 1], [1;1;1;1][:,:], [1 1; 1 1]]);

const ChamberWidth = 7;
const InitialVOff = 3;
const Line = MVector{ChamberWidth, Bool};

const Chamber = Vector{Line};

function show_chamber(c::Chamber)
	for l in reverse(c)
		println(String(map(x -> x ? '@' : '.', l)));
	end
end

@enum Direction begin
	L
	R
end

function parsechar(c::Char)::Direction
	if c == '<'
		L
	elseif c == '>'
		R
	end
end	

function parse_input(f::String)::Vector{Direction}
	open(f; read=true) do fh
		l = readline(fh);
		map(parsechar, collect(l))
	end
end

function would_overlap(r::Matrix{Int}, left::Int, up::Int, c::Chamber)::Bool
    if left+size(r, 2)-1 > ChamberWidth || left < 1
        println("lateral stop");
        return true;
    end
    if up > length(c)
        return false;
    end

    lines_overlap = length(c) - up + 1;
    zs = zeros(Bool, ChamberWidth);
    for l = 1:lines_overlap
        cl = c[end-l+1];
        rl = r[end-l+1,:];
        rlc = Line(zs);
        rlc[left:left+size(r, 2)-1] .= rl;
        if any((>)(1), Int.(cl) .+ Int.(rlc))
            @show (cl, rlc)
            return true;
        end
    end
    false
end

function move_rock(r::Matrix{Int}, d::Direction, left::Int, up::Int, c::Chamber)::Tuple{Int,Int,Bool}
    newl, newu = left, up;

    println("Jet pushes $d");
    if would_overlap(r, left + (d == L ? -1 : +1), newu, c)
        # Lateral move didn't work, just ignore
        #
    else
        println("  ok");
        newl = left + (d == L ? -1 : 1);
    end

    if would_overlap(r, newl, up-1, c)
        return (newl, up, true);
    else
        println("Rock falls 1");
        newu = up-1;
    end

    (newl, newu, false)
end

function merge_rock(c::Chamber, r::Matrix{Int}, left::Int, up::Int)
	z = zeros(Bool, ChamberWidth);
	for i = 1:(up-length(c)+size(r, 1)-1)
		push!(c, Line(z));
	end

        for i = 0:size(r, 1)-1
            cl = c[up+i];
            rl = r[end-i, :];
            rlc = Line(z);
            rlc[left:left+size(r, 2)-1] .= rl;
            cl .|= rlc;
        end
end

function handle_fall(jets::Vector{Direction}; maxi=2022)::Int
	c = Chamber();
	rs = Iterators.cycle(rocks);
	jets = Iterators.cycle(jets);
	jetst = 0;
	i = 0;
	for rock = rs
		i += 1;
                @show i
                show_chamber(c);
		# Coordinates relative to floor.
		# Left is position of left-most edge, up position of bottom part.
                left, up = 3, length(c)+4+(i == 1 ? 1 : 0);
		settled = false;
		for j = 1:3
			jet, jetst = iterate(jets, jetst);
			left, up, settled = move_rock(rock, jet, left, up, c);
			@assert !settled;
		end
		while !settled && up > 1
			jet, jetst = iterate(jets, jetst);
			left, up, settled = move_rock(rock, jet, left, up, c);
		end
		# Update chamber image
		merge_rock(c, rock, left, up);
		show_chamber(c);
		if i == maxi
			break
		end
	end
        println("---");
	show_chamber(c);
	length(c)
end

handle_fall(parse_input("17/test_input.txt"); maxi=10);