• Pyro
    link
    fedilink
    arrow-up
    2
    ·
    2 months ago

    Python

    def part1(data: str):
        elements = map(int, data.split(','))
        total = 0
        for ele in elements:
            # a spell element will add (90 // number) bricks for 90 columns
            total += 90 // ele
        return total
    
    assert part1("1,2,3,5,9") == 193
    
    # Gets all spell elements needed to build a wall
    # Useful for part 2 and part 3
    def get_elements(data: str):
        wall = map(int, data.split(','))
        elements = []   # spell elements
    
        for col_idx, fragments in enumerate(wall):
            # fix for 1-based indexing
            col = col_idx + 1
    
            # account bricks for recorded elements
            for ele in elements:
                if col % ele == 0:
                    fragments -= 1
            
            # if we still have fragments, we need to add a new element with that column number
            if fragments > 0:
                elements.append(col)
        
        return elements
    
    def part2(data: str):
        # Get all spell elements needed to build the wall
        elements = get_elements(data)
        # return product of all elements
        ans = 1
        for ele in elements:
            ans *= ele
        return ans
    
    assert part2("1,2,2,2,2,3,1,2,3,3,1,3,1,2,3,2,1,4,1,3,2,2,1,3,2,2") == 270
    
    # Part 3: Binary Search for maximum full columns
    def part3(data: str):
        BRICKS = 202520252025000
        elements = get_elements(data)
    
        # Check if we can build 'cols' full columns within BRICKS bricks
        def can_build(cols: int) -> bool:
            bricks_used = 0
            for ele in elements:
                bricks_used += cols // ele
                if bricks_used > BRICKS:
                    return False
            return True
    
        # binary search: break on first column size we cannot build
        lo = 1
        hi = BRICKS
        while lo < hi:
            mid = lo + (hi - lo) // 2
            if can_build(mid):
                lo = mid + 1
            else:
                hi = mid
        
        # if lo is the first we cannot build, lo - 1 is the maximum we can build
        return lo - 1
    
    assert part3("1,2,2,2,2,3,1,2,3,3,1,3,1,2,3,2,1,4,1,3,2,2,1,3,2,2") == 94439495762954