#!/usr/bin/perl use v5.35.0; use List::Util qw(reduce); use Data::Dumper; my $verbose = 0; # Read disk map, build disk and gaps list my @disk; my @gaps; my $is_file = 1; my $file_id = 0; while (<>) { while (/(.)/g) { if ($is_file) { push @disk, ($file_id) x $1; ++$file_id if $1; } elsif ($1) { push @gaps, scalar @disk; push @disk, (undef) x $1; } $is_file = !$is_file; } } say Dumper \@disk, \@gaps, scalar @disk if $verbose; # Compact the disk COMPACT: while (@gaps) { # End of gap is defined by start of next file until (defined($disk[$gaps[0]])) { # If the last disk block is empty, it's part of # a trailing gap; remove that and all its blocks unless (defined $disk[$#disk]) { splice @disk, pop @gaps; # If the last gap just got removed, we're done last COMPACT unless @gaps; } # Last disk block now part of a file; move into gap say "$disk[$#disk] $#disk -> $gaps[0]" if $verbose > 1; $disk[$gaps[0]++] = pop @disk; } # This gap is now filled, discard it shift @gaps; } say Dumper \@disk, \@gaps, scalar @disk if $verbose; # Calculate filesystem checksum say reduce {$a + $b * $disk[$b]} 0, 0 .. $#disk;