106 lines
3.5 KiB
OCaml
106 lines
3.5 KiB
OCaml
open Printf;;
|
|
|
|
let rec list_of_lines in_file =
|
|
try
|
|
let line = input_line in_file in
|
|
line :: list_of_lines(in_file)
|
|
with End_of_file ->
|
|
close_in in_file;
|
|
[]
|
|
|
|
let parse_filesystem_block index length =
|
|
if index mod 2 == 0 then
|
|
Array.init length (fun x -> index / 2)
|
|
else
|
|
Array.init length (fun x -> (-1))
|
|
|
|
let digit_code_to_int c =
|
|
int_of_char c - int_of_char '0'
|
|
|
|
let rec fix_file_layout_inner front_index back_index file_layout =
|
|
if front_index >= back_index then
|
|
()
|
|
else if file_layout.(front_index) >= 0 then
|
|
fix_file_layout_inner (front_index + 1) back_index file_layout
|
|
else if file_layout.(back_index) < 0 then
|
|
fix_file_layout_inner front_index (back_index - 1) file_layout
|
|
else begin
|
|
file_layout.(front_index) <- file_layout.(back_index);
|
|
file_layout.(back_index) <- (-1);
|
|
fix_file_layout_inner (front_index + 1) (back_index - 1) file_layout
|
|
end
|
|
|
|
let fix_file_layout file_layout =
|
|
let array_copy = Array.copy file_layout in
|
|
fix_file_layout_inner 0 (Array.length array_copy - 1) array_copy;
|
|
array_copy
|
|
|
|
let rec get_repeated_count array value index step =
|
|
try
|
|
if array.(index) != value then
|
|
0
|
|
else
|
|
1 + get_repeated_count array value (index + step) step
|
|
with Invalid_argument _ -> 0
|
|
|
|
let rec try_move_file_no_fragment file_id file_index file_length file_layout front_index =
|
|
if front_index >= file_index then
|
|
()
|
|
else if file_layout.(front_index) >= 0 then
|
|
try_move_file_no_fragment file_id file_index file_length file_layout (front_index + 1)
|
|
else
|
|
let free_space_length = get_repeated_count file_layout (-1) front_index 1 in
|
|
if free_space_length < file_length then
|
|
try_move_file_no_fragment file_id file_index file_length file_layout (front_index + free_space_length)
|
|
else begin
|
|
Seq.ints 0
|
|
|> Seq.take file_length
|
|
|> Seq.iter (
|
|
fun i ->
|
|
file_layout.(front_index + i) <- file_id;
|
|
file_layout.(file_index + i) <- (-1));
|
|
end
|
|
|
|
let rec fix_file_layout_defragment_inner back_index file_layout =
|
|
if back_index < 0 then
|
|
()
|
|
else if file_layout.(back_index) < 0 then
|
|
let free_space_length = get_repeated_count file_layout (-1) back_index (-1) in
|
|
fix_file_layout_defragment_inner (back_index - free_space_length) file_layout
|
|
else
|
|
let file_id = file_layout.(back_index) in
|
|
let file_length = get_repeated_count file_layout file_id back_index (-1) in
|
|
let new_back_index = back_index - file_length in
|
|
try_move_file_no_fragment file_id (new_back_index + 1) file_length file_layout 0;
|
|
fix_file_layout_defragment_inner new_back_index file_layout
|
|
|
|
|
|
let fix_file_layout_defragment file_layout =
|
|
let array_copy = Array.copy file_layout in
|
|
fix_file_layout_defragment_inner (Array.length file_layout - 1) array_copy;
|
|
array_copy
|
|
|
|
let get_checksum file_layout =
|
|
file_layout
|
|
|> Array.to_seq
|
|
|> Seq.mapi (fun i x -> i * x)
|
|
|> Seq.filter (fun x -> x >= 0)
|
|
|> Seq.fold_left Int.add 0
|
|
|
|
let () =
|
|
let f = open_in "input.txt" in
|
|
let disk_map = f
|
|
|> list_of_lines
|
|
|> List.hd
|
|
|> String.to_seq
|
|
|> Seq.map digit_code_to_int
|
|
|> List.of_seq in
|
|
let file_layout = disk_map
|
|
|> List.mapi (fun i x -> parse_filesystem_block i x)
|
|
|> Array.concat in
|
|
let fixed_layout = fix_file_layout file_layout in
|
|
let result = get_checksum fixed_layout in
|
|
printf "%d\n%!" result;
|
|
let fixed_layout_defragment = fix_file_layout_defragment file_layout in
|
|
let result2 = get_checksum fixed_layout_defragment in
|
|
printf "%d\n"result2 |