Spaces:
Running
Running
def load_data(file): | |
with open(file) as f: | |
return f.read().strip("\n") | |
def generate_blocks(disk_map): | |
blocks = [] | |
for idx, i in enumerate(disk_map): | |
if idx % 2: | |
blocks.extend( ["."]*int(i)) | |
else: | |
blocks.extend( [str(idx // 2)] *int(i)) | |
return blocks | |
def get_next_valid_block_from_end(end: int, blocks): | |
for j in range(end, -1, -1): | |
if blocks[j] != ".": | |
return j | |
def compact_blocks(blocks): | |
# blocks = list(blocks) | |
end = get_next_valid_block_from_end(len(blocks) - 1, blocks) | |
for idx, block in enumerate(blocks): | |
if end == idx: | |
break | |
if block == ".": | |
blocks[idx] = blocks[end] | |
blocks[end] = "." | |
end = get_next_valid_block_from_end(end, blocks) | |
# print("".join(blocks)) | |
return blocks | |
def compute_checksum(blocks): | |
checksum = 0 | |
for idx, num in enumerate(blocks): | |
if num == ".": | |
return checksum | |
checksum += idx*int(num) | |
return checksum | |
disk_map = load_data("input.txt") | |
blocks = generate_blocks(disk_map) | |
compact_blocks = compact_blocks(blocks) | |
print(compute_checksum(compact_blocks)) | |
## Part two | |
def generate_blocks(disk_map): | |
blocks = [] | |
for idx, i in enumerate(disk_map): | |
if idx % 2: | |
if int(i) > 0: | |
blocks.append( ["."]*int(i)) | |
else: | |
blocks.append( [str(idx // 2)] *int(i)) | |
return blocks | |
def get_free_space_map(blocks): | |
free_space_map = [] | |
pos = 0 | |
for idx, block in enumerate(blocks): | |
if block[0] == ".": | |
free_space_map.append((idx, len(block))) | |
pos += len(block) | |
return free_space_map | |
def get_next_valid_block_from_end(blocks): | |
for idx, block in enumerate(blocks[::-1]): | |
if block[0] != ".": | |
block_idx = len(blocks) - idx - 1 | |
return block, block_idx | |
def pprint(blocks): | |
print("".join(["".join(b) for b in blocks])) | |
def move_block_at_fileid(blocks, file_id: int): | |
free_space_map = get_free_space_map(blocks) | |
# block = blocks[block_idx] | |
for idx, block in enumerate(blocks): | |
if block[0] != "." and block[0] == str(file_id): | |
block_idx = idx | |
break | |
K = len(block) | |
for free_block_idx, free_len in free_space_map: | |
if free_len > K and free_block_idx < block_idx: | |
# First condition means we have more space than needed | |
# Second condition ensures we Only move forward in queue, not backwards | |
blocks[free_block_idx] = ["."] * (free_len - len(block)) # Remaining free memory after insert | |
blocks.insert(free_block_idx, block) # Insert at index | |
blocks[block_idx + 1] = ["."] * K # Overwrite at end (+1 because we added a new index) | |
return True | |
elif free_len == K and free_block_idx < block_idx: | |
# First condition means we have just enough space | |
# Second condition ensures we Only move forward in queue, not backwards | |
blocks[free_block_idx] = block | |
blocks[block_idx] = ["."] * K | |
return True | |
return False | |
def compute_checksum(blocks): | |
blocks_ext = [b for block in blocks for b in block] | |
checksum = 0 | |
for idx, num in enumerate(blocks_ext): | |
if num == ".": | |
continue | |
checksum += idx*int(num) | |
return checksum | |
def get_max_file_id(blocks): | |
for block in blocks[::-1]: | |
if block[0] != ".": | |
max_file_id = int(block[0]) | |
return max_file_id | |
disk_map = load_data("input.txt") | |
blocks = generate_blocks(disk_map) | |
max_file_id = get_max_file_id(blocks) | |
# pprint(blocks) | |
for file_id in range(max_file_id, -1, -1): | |
# Progress-bar | |
# if file_id % 1000 == 0: | |
# print(file_id) | |
moved = move_block_at_fileid(blocks, file_id) | |
# if moved: | |
# pprint(blocks) | |
print(compute_checksum(blocks)) | |